在我的程序中,我具有以下架构:
客户端-中间路由器-服务器
客户端和路由器通过TCP连接连接。路由器和服务器具有UDP连接。 我正在这样发送数据:
messagetobesend = "some very long message to be send"
sock = socket(AF_INET,SOCK_STREAM)
# bind my port to the socket
sock.bind((IP,PORT))
sock.connect((routerip, routerport))
# since I'm using TCP, send the data byte by byte
for i in range(len(messagetobesend)):
sock.send(messagetobesend[i])
# now, I have send all of the message
sock.close()
在路由器中,我有以下内容:
sock = socket(AF_INET,SOCK_STREAM)
sock.bind((ip, port))
sock.listen(1)
# I have accepted the TCP connection
newsocket, addr = sock.accept()
# now create a UDP socket
udpsock = socket(AF_INET,SOCK_DGRAM)
udpsock.bind((myudpip, myudpport))
while True:
# I want to packetize the data with 128 bytes
data = newsocket.recv(128)
if(data):
data.sendto(udpsock,(serverip,serverport))
else:
#received no data, terminate udp connection
udpsock.close()
newsocket.close()
和服务器:
sock = socket(AF_INET,SOCK_DGRAM)
sock.bind((myip, myport))
while True:
data, addr = sock.recvfrom(128)
#print data
我所做的一切似乎都是正确的。但是,服务器通常接收128字节的数据包,有时接收大多数128字节的数据包,有些不接收128字节的数据。
我在这里做错什么了吗?我希望服务器接收所有这些长度为128字节的数据包(所有接收到的数据包长度应相同)
答案 0 :(得分:1)
您的recv
调用返回最多 128个字节。如果您需要精确接收128个字节,则应编写自己的recv_exactly
:
PACKET_LEN = 128
# ...
def recv_exactly(socket, length):
buf = bytearray()
bytes_left = length
while bytes_left: # equivalent to while bytes_left != 0:
data = socket.recv(bytes_left)
if not data:
return buf # could theoretically be less than length
buf += data
bytes_left -= len(data)
return buf
while True:
data = recv_exactly(newsocket, PACKET_LEN)
if (len(data) == PACKET_LEN): # Data fully received
udpsock.sendto(data, (serverip, serverport))
elif (len(data) > 0): # Data partially received
udpsock.sendto(data, (serverip, serverport))
udpsock.close()
else: # got no data
udpsock.close()
P.S .:您可以发送整个messagetobesend
,而不必逐字节发送。操作系统内核和网络接口会根据需要缓冲和拆分字节。
通常:TCP是字节流,在套接字关闭时将结束。它以不可预测的块的形式到达,而与每个send
调用中发送了多少数据无关。 TCP保证了流的顺序和完整性,但没有数据包边界。
UDP是不可靠的,可以以错误的数据包顺序与错误的数据一起到达,重复或根本不到达。但是UDP是面向数据包的,这意味着接收方可以确定数据包的边界,准确确定数据包的发送方式(如果数据包是通过网络发送的)。