sock_stream Python Socket riceve una grande quantità di dati




socket sock_stream python (5)

Quando provo a ricevere grandi quantità di dati, viene troncato e devo premere Invio per ottenere il resto dei dati. All'inizio sono stato in grado di aumentarlo un po ', ma non lo riceverà ancora. Come puoi vedere, ho aumentato il buffer su conn.recv () ma non ottiene ancora tutti i dati. Lo interrompe ad un certo punto. Devo premere Invio sul mio raw_input per ricevere il resto dei dati. Posso comunque ottenere tutti i dati contemporaneamente? Ecco il codice.

port = 7777
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('0.0.0.0', port))
sock.listen(1)
print ("Listening on port: "+str(port))
while 1:
    conn, sock_addr = sock.accept()
    print "accepted connection from", sock_addr
    while 1:
        command = raw_input('shell> ')
            conn.send(command)
                data = conn.recv(8000)
                if not data: break
                print data,
    conn.close()

TCP / IP è un protocollo basato sul flusso , non un protocollo basato su messaggi . Non vi è alcuna garanzia che ogni chiamata send() di un peer abbia come risultato una singola chiamata recv() dall'altro peer che riceve i dati esatti inviati - potrebbe ricevere i dati pezzo-pasto, divisi tra più chiamate recv() , a causa del pacchetto la frammentazione.

È necessario definire il proprio protocollo basato su messaggi su TCP per differenziare i limiti dei messaggi. Quindi, per leggere un messaggio, si continua a chiamare recv() fino a quando non si legge un intero messaggio o si verifica un errore.

Un modo semplice per inviare un messaggio è precedere ogni messaggio con la sua lunghezza. Quindi per leggere un messaggio, prima leggi la lunghezza, poi leggi molti byte. Ecco come potresti farlo:

def send_msg(sock, msg):
    # Prefix each message with a 4-byte length (network byte order)
    msg = struct.pack('>I', len(msg)) + msg
    sock.sendall(msg)

def recv_msg(sock):
    # Read message length and unpack it into an integer
    raw_msglen = recvall(sock, 4)
    if not raw_msglen:
        return None
    msglen = struct.unpack('>I', raw_msglen)[0]
    # Read the message data
    return recvall(sock, msglen)

def recvall(sock, n):
    # Helper function to recv n bytes or return None if EOF is hit
    data = b''
    while len(data) < n:
        packet = sock.recv(n - len(data))
        if not packet:
            return None
        data += packet
    return data

Quindi è possibile utilizzare le funzioni send_msg e recv_msg per inviare e ricevere messaggi interi e non avranno alcun problema con i pacchetti divisi o coalescati a livello di rete.


Potrebbe essere necessario chiamare conn.recv () più volte per ricevere tutti i dati. Non è garantito il richiamo di una singola volta per inserire tutti i dati inviati, poiché i flussi TCP non mantengono i limiti dei frame (cioè funzionano solo come flusso di byte non elaborati, non come flusso strutturato di messaggi) .

Vedi questa risposta per un'altra descrizione del problema.

Nota che questo significa che hai bisogno di sapere quando hai ricevuto tutti i dati. Se il mittente invierà sempre esattamente 8000 byte, potreste contare il numero di byte ricevuti finora e sottrarre quello da 8000 per sapere quanti ne rimangono da ricevere; se i dati sono di dimensioni variabili, ci sono vari altri metodi che possono essere usati, come avere il mittente inviare un'intestazione numero-di-byte prima di inviare il messaggio, o se si tratta di un testo ASCII che viene inviato si potrebbe cercare un newline o carattere NUL.


La risposta accettata va bene, ma sarà molto lento con i file di grandi dimensioni. La stringa è una classe immutabile, questo significa che più oggetti devono essere creati ogni volta che si utilizza il segno + , usando l' list come una struttura dello stack più efficiente.

Questo dovrebbe funzionare meglio

while True: 
    chunck = s.recv(10000)
    if not chunck: 
        break
    fragments.append(chunck)

print "".join(fragments)

Una variazione che utilizza una funzione generatore (che considero più pitonica):

def recvall(sock, buffer_size=4096):
    buf = sock.recv(buffer_size)
    while buf:
        yield buf
        if len(buf) < buffer_size: break
        buf = sock.recv(buffer_size)
# ...
with socket.create_connection((host, port)) as sock:
    sock.sendall(command)
    response = b''.join(recvall(sock))

Modifica del codice di Adam Rosenfield:

import sys


def send_msg(sock, msg):
    size_of_package = sys.getsizeof(msg)
    package = str(size_of_package)+":"+ msg #Create our package size,":",message
    sock.sendall(package)

def recv_msg(sock):
    try:
        header = sock.recv(2)#Magic, small number to begin with.
        while ":" not in header:
            header += sock.recv(2) #Keep looping, picking up two bytes each time

        size_of_package, separator, message_fragment = header.partition(":")
        message = sock.recv(int(size_of_package))
        full_message = message_fragment + message
        return full_message

    except OverflowError:
        return "OverflowError."
    except:
        print "Unexpected error:", sys.exc_info()[0]
        raise

Tuttavia, incoraggerei fortemente l'utilizzo dell'approccio originale.







sockets