Пакетировать поток TCP - PullRequest
       6

Пакетировать поток TCP

0 голосов
/ 23 ноября 2018

В моей программе используется следующая схема:

Клиент - промежуточный маршрутизатор - сервер

Клиент и маршрутизатор связаны по 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 байт (длина всех принятых пакетов должна быть одинаковой)

1 Ответ

0 голосов
/ 23 ноября 2018

Ваш 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()

PS: Вы можете отправить целое messagetobesend, отправка его по байтам не требуется.Ядро ОС и сетевой интерфейс буферизуют и разделяют ваши байты, как им нужно.

И вообще: TCP - это поток байтов, который заканчивается, когда сокет будет закрыт.Он приходит непредсказуемым образом, независимо от того, сколько данных было отправлено в каждом вызове send.TCP гарантирует порядок и целостность потока, но не имеет границ пакетов.

UDP ненадежен, может поступать с искаженными данными, в неправильном порядке пакетов, дублироваться или вообще не поступать.Но UDP ориентирован на пакет, то есть получатель может определить границы пакетов, в точности как они были отправлены (если пакет прошел через сеть).

...