Reputation: 1
In my program, I have the following schema:
Client - intermediate router - server
The client and router are connected with TCP connection. Router and server has UDP connection. I am sending the data as this:
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()
In the router, I have the following:
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()
And the server:
sock = socket(AF_INET,SOCK_DGRAM)
sock.bind((myip, myport))
while True:
data, addr = sock.recvfrom(128)
#print data
Everything I do seems correct. However, the server usually receives packets as 128 bytes, sometimes receives most of them 128bytes and some of them not 128 bytes.
Am I doing something wrong here? I want server to receive all of these packets with length of 128 bytes(all received packets length should be identical)
Upvotes: 0
Views: 555
Reputation: 2816
Your recv
call returns up to 128 bytes. If you need to receive exactly 128 bytes, then you should write your own 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.: You can send whole messagetobesend
, sending it byte by byte is not necessary. OS kernel and network interface would buffer and split your bytes however they need to.
And generally: TCP is a stream of bytes that will end when the socket would be closed. It arrives in unpredictable chunks, independent of how much data was sent in each send
call. TCP guarantees the order and integrity of the stream, but does not have packet boundaries.
UDP is unreliable, can arrive with mangled data, in a wrong packet order, duplicated, or not arrive at all. But UDP is packet oriented, meaning that receiver can determine the boundaries of the packets, exactly how they were sent (if the packet made it over the network).
Upvotes: 1