В то время как цикл, чтобы получить все полученные данные, python 3.6 (socket) [duplicate]

Если ваш основной метод находится в классе под пакетом, вы должны запустить его по иерархическому каталогу.

Предположим, что есть файл исходного кода (Main.java):

package com.test;

public class Main {

    public static void main(String[] args) {
        System.out.println("salam 2nya\n");
    }
}

Для запуска этого кода вы должны поместить Main.Class в пакет, например каталог ./com/test/Main.Java. И в корневом каталоге используйте java com.test.Main.

31
задан user2585107 16 July 2013 в 05:16
поделиться

6 ответов

TCP / IP - это протокол на основе потока , а не протокол на основе сообщений . Нет никакой гарантии, что каждый send() вызов одним одноранговым узлом приводит к единственному вызову recv() другим одноранговым узлом, получающему точные данные, - он может получать кусочек данных, разделенный на несколько вызовов recv(), из-за пакета фрагментация.

Чтобы дифференцировать границы сообщений, вам нужно определить свой собственный протокол на основе протокола TCP. Затем, чтобы прочитать сообщение, вы продолжаете называть recv() до тех пор, пока не прочитаете целое сообщение или не появится ошибка.

Один простой способ отправки сообщения - префикс каждого сообщения с его длиной. Затем, чтобы прочитать сообщение, сначала прочитайте длину, затем вы прочтете, что много байтов. Вот как вы можете это сделать:

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

Затем вы можете использовать функции send_msg и recv_msg для отправки и получения целых сообщений, и у них не будет проблем с разбиением пакетов или объединены на сетевом уровне.

85
ответ дан Hedde van der Heide 28 August 2018 в 02:42
поделиться

Вам может потребоваться несколько раз вызвать conn.recv () для получения всех данных. При вызове его один раз не гарантируется получение всех отправленных данных из-за того, что потоки TCP не поддерживают границы кадров (т. Е. Они работают только как поток необработанных байтов, а не структурированный поток сообщений) .

См. этот ответ для другого описания проблемы.

Обратите внимание, что это означает, что вам нужен какой-то способ узнать, когда вы получили все данные , Если отправитель всегда будет отправлять ровно 8000 байт, вы можете подсчитать количество полученных байтов до сих пор и вычесть из 8000, чтобы узнать, сколько осталось получить; если данные имеют переменный размер, существуют различные другие методы, которые могут использоваться, например, когда отправитель отправляет заголовок с номерами байтов перед отправкой сообщения или если он отправляет текст ASCII, вы можете искать символ новой строки или NUL.

3
ответ дан Community 28 August 2018 в 02:42
поделиться

Принятый ответ хорош, но он будет очень медленным с большими файлами -string - это неизменный класс, это означает, что каждый объект будет создан каждый раз, когда вы используете знак +, используя list в качестве структуры стека будет больше эффективный.

Это должно работать лучше

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

print "".join(fragments)
4
ответ дан Mina Gabriel 28 August 2018 в 02:42
поделиться

Вариант с использованием функции генератора (который я считаю более pythonic):

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))
3
ответ дан Shadur 28 August 2018 в 02:42
поделиться

Изменение кода Адама Розенфилда:

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

Я бы, однако, очень хотел использовать оригинальный подход.

1
ответ дан sjMoquin 28 August 2018 в 02:42
поделиться

Вы можете использовать его как: data = recvall(sock)

def recvall(sock):
    BUFF_SIZE = 4096 # 4 KiB
    data = b''
    while True:
        part = sock.recv(BUFF_SIZE)
        data += part
        if len(part) < BUFF_SIZE:
            # either 0 or end of data
            break
    return data
15
ответ дан trilobyte 28 August 2018 в 02:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: