Python 使用 TCP 套接字发送/接收数据包
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17499961/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Send/receive Packets with TCP sockets
提问by intensified
Recently, I managed to create sockets on my PC and my Raspberry Pi to enable communication between both devices. Currently, the client is able to automatically send messages to the server. I was wondering, if it is possible to modify the scripts to send tcp data packets instead of purely text messages, as I would very much like to control the raspberry pi using my PC in the future without having the need to ssh/etc.
最近,我设法在我的 PC 和我的 Raspberry Pi 上创建了套接字,以实现两个设备之间的通信。目前,客户端能够自动向服务器发送消息。我想知道,是否可以修改脚本以发送 tcp 数据包而不是纯文本消息,因为我非常希望将来使用我的 PC 控制 raspberry pi,而无需 ssh/etc。
I've looked at some examples, but as I don't have much experience in writing my own scripts/codes, I'm not very sure how to go about doing this. I would appreciate if someone could guide me in the right direction with explanation and some examples if possible.
我看过一些例子,但由于我在编写自己的脚本/代码方面没有太多经验,我不太确定如何去做。如果有人可以通过解释和一些示例(如果可能)引导我朝着正确的方向前进,我将不胜感激。
Anyway here is the server/client script I'm running at the moment:
无论如何,这是我目前正在运行的服务器/客户端脚本:
Client:
客户:
import socket
import sys
import struct
import time
#main function
if __name__ == "__main__":
if(len(sys.argv) < 2) :
print 'Usage : python client.py hostname'
sys.exit()
host = sys.argv[1]
port = 8888
#create an INET, STREAMing socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print 'Failed to create socket'
sys.exit()
print 'Socket Created'
try:
remote_ip = socket.gethostbyname( host )
s.connect((host, port))
except socket.gaierror:
print 'Hostname could not be resolved. Exiting'
sys.exit()
print 'Socket Connected to ' + host + ' on ip ' + remote_ip
#Send some data to remote server
message = "Test"
try :
#Set the whole string
while True:
s.send(message)
print 'Message sent successfully'
time.sleep(1)
print 'Sending...'
except socket.error:
#Send failed
print 'Send failed'
sys.exit()
def recv_timeout(the_socket,timeout=2):
#make socket non blocking
the_socket.setblocking(0)
#total data partwise in an array
total_data=[];
data='';
#beginning time
begin=time.time()
while 1:
#if you got some data, then break after timeout
if total_data and time.time()-begin > timeout:
break
#if you got no data at all, wait a little longer, twice the timeout
elif time.time()-begin > timeout*2:
break
#recv something
try:
data = the_socket.recv(8192)
if data:
total_data.append(data)
#change the beginning time for measurement
begin=time.time()
else:
#sleep for sometime to indicate a gap
time.sleep(0.1)
except:
pass
#join all parts to make final string
return ''.join(total_data)
#get reply and print
print recv_timeout(s)
s.close()
Server:
服务器:
import socket
import sys
from thread import *
HOST = '' # Symbolic name meaning all available interfaces
PORT = 8888
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
try:
s.bind((HOST, PORT))
except socket.error , msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
s.listen(10)
print 'Socket now listening'
#Function for handling connections
def clientthread(conn):
#Sending message to connected client
conn.send('Welcome to the server. Receving Data...\n') #send only takes string
#infinite loop so that function do not terminate and thread do not end.
while True:
#Receiving from client
data = conn.recv(1024)
reply = 'Message Received at the server!\n'
print data
if not data:
break
conn.sendall(reply)
conn.close()
#now keep talking with the client
while 1:
#wait to accept a connection
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
#start new thread
start_new_thread(clientthread ,(conn,))
s.close()
回答by Steve Barnes
回答by Ulrich Eckhardt
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
already creates a connection that provides a reliable stream of bytes between two machines. This uses TCP, which is on top of IP and Ethernet. The latter two are package-based, while TCP creates a stream of continuous bytes on top of it. It also adds some error checking and error correction, so it is pretty reliable.
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
已经创建了一个连接,在两台机器之间提供可靠的字节流。这使用 TCP,它位于 IP 和以太网之上。后两者是基于包的,而 TCP 在其上创建连续字节流。它还添加了一些错误检查和错误纠正,因此非常可靠。
I honestly don't understand what you want to achieve with what you call "send packets". What you don't want to do is to create an implementation of TCP yourself, as that's a non-trivial task, so sending RAW packets is out. In general, even using TCP is already relatively low-level and should be avoided unless really necessary.
老实说,我不明白你想用你所谓的“发送数据包”来实现什么。您不想做的是自己创建 TCP 的实现,因为这是一项非常重要的任务,因此发送 RAW 数据包已结束。一般来说,即使使用 TCP 也已经是相对低级的,除非真的有必要,否则应该避免使用。
Using e.g. ZeroMQ you get a message-based interface that does all the transmission for you. It does so on top of TCP (or other transports) and adds more error correction for e.g. disconnects. There, you also have something like "packets", but those are independent of how many TCP or IP packets were required to send it underneath. If you don't want to implement a specific protocol, I'd suggest you use this framework instead of lowlevel TCP sockets.
使用例如 ZeroMQ,您将获得一个基于消息的接口,为您完成所有传输。它在 TCP(或其他传输)之上执行此操作,并为例如断开连接添加更多错误校正。在那里,您还有“数据包”之类的东西,但这些与需要多少 TCP 或 IP 数据包在下面发送它无关。如果您不想实现特定的协议,我建议您使用此框架而不是低级 TCP 套接字。
Another simple alternative is to use HTTP, for which there is also existing code in Python. The downside is that it is always one side that initiates some communication and the other side only replies. If you want some kind of active notification, you either have to poll or use hacks like delaying an answer.
另一种简单的替代方法是使用 HTTP,为此也有 Python 中的现有代码。缺点是总是由一方发起一些通信,而另一方只回复。如果您想要某种主动通知,则必须轮询或使用诸如延迟答复之类的技巧。