복붙노트

[PYTHON] 파이썬 소켓은 많은 양의 데이터를받습니다.

PYTHON

파이썬 소켓은 많은 양의 데이터를받습니다.

더 많은 양의 데이터를 수신하려고하면 데이터가 잘 리기 때문에 Enter 키를 눌러 나머지 데이터를 가져와야합니다. 처음에는 조금 늘릴 ​​수 있었지만 여전히 모든 것을받지는 못했습니다. 보시다시피 나는 conn.recv ()의 버퍼를 증가 시켰지만 여전히 모든 데이터를 가져 오지 못합니다. 그것은 특정 지점에서 그것을 자른다. 나머지 데이터를 받으려면 raw_input에 enter 키를 눌러야합니다. 어쨌든 모든 데이터를 한 번에 가져올 수 있습니까? 여기에 코드가 있습니다.

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()

해결법

  1. ==============================

    1.TCP / IP는 메시지 기반 프로토콜이 아닌 스트림 기반 프로토콜입니다. 하나의 피어에 의한 모든 send () 호출이 보내진 정확한 데이터를 수신하는 다른 피어에 의한 단일 recv () 호출을 초래할 것이라는 보장은 없습니다. 패킷으로 인해 여러 recv () 호출로 분할 된 데이터 조각 식사를 수신 할 수 있습니다 분열.

    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 함수를 사용하여 전체 메시지를 보내고받을 수 있으며 네트워크 수준에서 분할되거나 병합 된 패킷에 아무런 문제가 없습니다.

  2. ==============================

    2.다음과 같이 사용할 수 있습니다 : data = recvall (sock)

    다음과 같이 사용할 수 있습니다 : 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
    
  3. ==============================

    3.허용 된 대답은 괜찮지 만 대용량 파일에서는 매우 느릴 것입니다. -string은 불변 클래스입니다. + 기호를 사용할 때마다 더 많은 개체가 만들어지며 스택 구조로 목록을 사용하는 것이 더 효율적입니다.

    허용 된 대답은 괜찮지 만 대용량 파일에서는 매우 느릴 것입니다. -string은 불변 클래스입니다. + 기호를 사용할 때마다 더 많은 개체가 만들어지며 스택 구조로 목록을 사용하는 것이 더 효율적입니다.

    이것은 더 잘 작동 할 것입니다.

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

    4.모든 데이터를 수신하려면 conn.recv ()를 여러 번 호출해야 할 수도 있습니다. TCP 스트림이 프레임 경계를 유지하지 않기 때문에 (즉, 메시지의 구조화 된 스트림이 아닌 원시 바이트 스트림으로 만 작동하기 때문에) 한 번만 호출하면 전송 된 모든 데이터를 가져올 수 있다고 보장 할 수 없습니다. .

    모든 데이터를 수신하려면 conn.recv ()를 여러 번 호출해야 할 수도 있습니다. TCP 스트림이 프레임 경계를 유지하지 않기 때문에 (즉, 메시지의 구조화 된 스트림이 아닌 원시 바이트 스트림으로 만 작동하기 때문에) 한 번만 호출하면 전송 된 모든 데이터를 가져올 수 있다고 보장 할 수 없습니다. .

    이 문제에 대한 다른 설명은이 대답을 참조하십시오.

    즉, 모든 데이터를 받았을 때 알 수있는 방법이 필요합니다. 보낸 사람이 항상 정확히 8000 바이트를 보내면 지금까지 수신 한 바이트 수를 계산하여 수신 할 수있는 숫자를 알기 위해 8000에서 해당 바이트 수를 뺄 수 있습니다. 데이터가 가변 크기 인 경우 보낸 사람이 메시지를 보내기 전에 바이트 수 헤더를 보내는 것과 같이 보낼 수있는 다양한 방법이 있습니다. 또는 보내지는 ASCII 텍스트 인 경우 개행 문자 또는 NUL 문자.

  5. ==============================

    5.발전기 함수를 사용하는 변형 (더 파이썬이라고 생각합니다) :

    발전기 함수를 사용하는 변형 (더 파이썬이라고 생각합니다) :

    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))
    
  6. ==============================

    6.Adam Rosenfield의 코드 수정 :

    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
    

    그러나 나는 원래의 접근법을 사용하도록 강력히 권할 것이다.

  7. from https://stackoverflow.com/questions/17667903/python-socket-receive-large-amount-of-data by cc-by-sa and MIT license