为什么我的Python套接字连接没有接收到所有数据,有时......?

问题描述 投票:0回答:1

我制作了一个简单的测试程序,用于将多个客户端连接到服务器。服务器只是重复向客户端发送其时间,并进行一些额外的加密。问题是有时客户端没有收到完整的消息,这会在 pickle 尝试 unpickle 不完整的消息时导致错误。然而,它在本地主机上运行完美。

服务器.py

import datetime
import logging
import socket
import threading
import traceback

import rsa.randnum

from blob_api import *

logging.basicConfig(format='%(levelname)s - %(message)s', level=logging.DEBUG)

SERVER_IP = "192.168.101.1"
SERVER_PORT = 8108


class __Server(socket.socket):
    def __init__(self):
        super().__init__()
        self.public_key, self.private_key = rsa.newkeys(2048)
        try:
            self.bind((SERVER_IP, SERVER_PORT))
        except socket.error as _:
            logging.error(traceback.format_exc())
        self.listen()
        logging.info(f"Server started: ('{SERVER_IP}', {SERVER_PORT}).")
        while True:
            client_socket, client_address = self.accept()
            logging.info(f"Connected to client: {client_address}, waiting for public key...")
            threading.Thread(target=self.client_thread, args=(client_socket, client_address,)).start()

    def client_thread(self, client_socket: socket.socket, client_address):
        client_public_key: rsa.PublicKey = pickle.loads(client_socket.recv(2048))
        client_socket.sendall(pickle.dumps(self.public_key))
        logging.info(f"Established connection to client: {client_address}.")
        n = 0
        while True:
            n += 1
            try:
                header = client_socket.recv(HEADER_SIZE)
                print(f"Header recv {n}: " + header.decode())
                if not len(header):
                    break
                packet = client_socket.recv(int(header.decode()))
                data = decrypt(packet, self.private_key)
                client_socket.sendall(create_message(encrypt(f"Server {n}: {datetime.datetime.now()}", client_public_key)))
            except:
                logging.error(traceback.format_exc())
                print(packet)   
                break
        logging.warning(f"Lost connection to client: {client_address}")
        client_socket.close()


__Server()

客户端.py

import datetime
import socket
import sys
import threading
import logging
import traceback

from blob_api import *

logging.basicConfig(format='%(levelname)s - %(message)s', level=logging.DEBUG)

SERVER_IP = "SERVER_PUBLIC_IP"
SERVER_PORT = 8108


class Connection(socket.socket):
    def __init__(self):
        super().__init__()
        self.public_key, self.private_key = rsa.newkeys(2048)
        try:
            self.connect((SERVER_IP, SERVER_PORT))
        except ConnectionRefusedError as e:
            logging.warning("Could not connect to server " + str(e))
            sys.exit()
        self.sendall(pickle.dumps(self.public_key))
        self.server_public_key = pickle.loads(self.recv(2048))
        threading.Thread(target=self.__handle_requests).start()

    def __handle_requests(self):
        logging.info("Established connection to server.")
        n = 0
        while True:
            n += 1
            try:
                message = create_message(encrypt(f"Client: {datetime.datetime.now()}", self.server_public_key))
                print(message)
                self.sendall(message)
                header = self.recv(HEADER_SIZE)
                print(f"Header recv {n}: " + header.decode())
                if not len(header):
                    break
                packet = self.recv(int(header.decode()))
                data = decrypt(packet, self.private_key)
                print(data)
            except:
                logging.error(traceback.format_exc())
                break
        logging.warning("Lost connection to server.")
        self.close()

Connection()

blob_api.py

import pickle

import obj_encrypt
import rsa
import rsa.randnum

HEADER_SIZE = 8

def encrypt(data: any, public_key: rsa.PublicKey) -> bytes:
    secret = obj_encrypt.Secret(key=str(rsa.randnum.read_random_int(32)))
    return pickle.dumps({
        "data": secret.encrypt(data),
        "secret": rsa.encrypt(pickle.dumps(secret), public_key)
    })


def decrypt(packet: bytes, private_key: rsa.PrivateKey) -> any:
    packet = pickle.loads(packet)
    return pickle.loads(rsa.decrypt(packet["secret"], private_key)).decrypt(packet["data"])


def create_message(message: bytes) -> bytes:
    return f"{len(message):<8}".encode() + message

我尝试过从手机热点笔记本电脑上的客户端连接到远程服务器。客户端连接成功,消息在短时间内被接收并打印在客户端上,但随后在随机时间点(约 5-60 秒),客户端或服务器都没有收到完整的消息。首先读取消息的头部,它决定了消息其余部分的长度,然后才能读取消息的准确长度。

客户端输出到此结束。

Header recv 44: 349
Server 44: 2024-03-13 12:29:40.200717
Len: 346
b"346     \x80\x04\x95O\x01\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04data\x94C1\x00\x9f\xc0\xe9]\xea\x9c\tg#\xa0\x83;\x9d\x1a\xda\xe3\xb5\xa9u\x7f\x15\xff\xeah\x0c\xf8f\xbe\xc14\x8c\xa2\xc1T^\xf9Z]\x16\xf2\x96,3\xd6\\\xb0\x04[\x94\x8c\x06secret\x94B\x00\x01\x00\x00a`\x05#\xf7\x08}\x17Ay\xe2\x96\xc8\xab:V@%\x94?j-\xd3F\xd3Q\xc1\xabl\xf3\x94\x9b\xc3U\xc2\xe7fD\n\x17\xad2\x0c\xea\x87m\xb3\xfb\xffq\xbb'\xdd\x07\x0f\r\x95\x14]3\xdfuh\xf3\x03i\x9f\x94R\x92>\xce\xa5\x8d\xb0';\x1a\x91)kJ\x9f?\xbe\xec\xc4\x85\\\xed\xb2\x88]k\x7f\xfc~\x0e9\xcd\xa2P:\x86Nq,J\xe3ol\xe3\x00\x94\xf8^+j\xb2\x8d3\xb1\x84\t\x80a\x16\x98\x84\x0fM\xe9\xd7\xa9OZ\xcf\xab&\xe1\xab\xa5\x1b\xc9\r,\xaf\r\x1f0,\xc5\xd9\x11L\xe6>\xcb\x12\xe6\x9e\xbc\xde\xb48\x1f\xa9\xd2g\xb2BZ\x98\xa4\x00\x85\xa1\xc9\xba\x87\r\xe0\x16\xc2\x9d\x00\xc3lz\xc9\x0f\xb8\x1fE\xf0[\xd3N\xd4\xa1\x91e_IS\x17C\x014V\xce@\xa3\x04.\xbc\xd0\x05\xb3\xf1\xc6\x97\x04_\xa6W\xe0\x17\x82\xa0\\\x92P3g\xd9\x1e.\x82{?'4\xd2\x19l\xce\xb0\xb5\xb0\xc3M\x8d\x14%V\x94u."
Header recv 45: 349
Server 45: 2024-03-13 12:29:40.292893
Len: 346
b'346     \x80\x04\x95O\x01\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04data\x94C1\x89\xbe"\xdb\xd5=\x19\x01\xc8\xc3\xba\x81\x96\x07L)\xfa,\'(\xaa\x80"\xadt\xbck\x8fZY\x8c\xd2\x84\x0e\xfc\xdb$\x1dY\xf3\x98\x8e\x88pvC\xd9\xb2\x8b\x94\x8c\x06secret\x94B\x00\x01\x00\x00B\xcez\x93\xa8\xbbf\n\xc5\xcbi6\xfe}\xff\xb1\x8e\xc8\x98\xbb\x8bbp\\g\x0f\x15y\xf6\xf0_\x0e\x82\x8b\x1e\xb3\xb3\xdf\x17\xc6\x97\xd9\x02\x88\x00l\xaa={gF\x92\xec;\xdbB\x08\xbd\x18I\x84*\xb9\xb8P\xbf\r|\xb2\xbeP\x19\xb1+\xb2\xaa[\xd8\xc7\x1e\xb4K(\x05\xbd_\x90\x99\xdd.\xfb^\x17\xac\xa7\xd69\x13\x8c\x1e\x8e\xb4I\xbc\xb2)c\xc5\x97\xb5\xb3e2\x91\xb2\xd8\xe3\xc1\xben\x0c\xdcd\xd0\xf3\x84\xfa[\xfc6\xbd_\x12M\xafS\xcc\xe4H\x8bQQ\xac\x07\xff\xe1\xd1\x19IW\xf6\x94\xf3\xd13\x08F\xe2\x07 U<\xcb\xecD\xcd\x84\x00#\xe4\xc2\xa5(\x80\x12\x80\x1dm\xab\x8b\x19N\xa1;/\x13\x7f\x05\xde\xc4+\xdeKQ\x01\'\xcc\xe6;>s\x01\xf9\xdd\x80\xdc\xb0A\xee\xba\x85c/\x7f\x04z\xe0H\xb6l\x90\x9a\x91\xa5\xed\xe28\xa8T\xf4\x99l\xd6\xf2\x85\xcb\x05\xee\x19,o\xa7\xe1w\x80\x87.\x02@n#\xac\xadQ\xa2\xb6\x94u.'
Header recv 46:
WARNING - Lost connection to server.

服务器端的输出到此结束。

Header recv 44: 346     
Len: 349
Header recv 45: 346     
Len: 349
Header recv 46: 346     
ERROR - Traceback (most recent call last):
  File "/path_to/server.py", line 46, in client_thread
    data = decrypt(packet, self.private_key)
  File "/path_to/blob_api.py", line 18, in decrypt
    packet = pickle.loads(packet)
_pickle.UnpicklingError: pickle data was truncated
b'\x80\x04\x95O\x01\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04data\x94C1\x89\xbe"\xdb\xd5=\x19\x01\xc8\xc3\xba\x81\x96\x07L)\xfa,\'(\xaa\x80"\xadt\xbck\x8fZY\x8c\xd2\x84\x0e\xfc\xdb$\x1dY\xf3\x98\x8e\x88pvC\xd9\xb2\x8b\x94\x8c\x06secret\x94B\x00\x01\x00\x00B\xcez\x93\xa8\xbbf\n\xc5\xcbi6\xfe}\xff\xb1\x8e\xc8\x98\xbb\x8bbp\\g\x0f\x15y\xf6\xf0_\x0e\x82\x8b\x1e\xb3\xb3\xdf\x17\xc6\x97\xd9\x02\x88\x00l\xaa={g'

客户端向服务器发送了一条大小为 346 字节的消息,服务器只收到了 137 字节。但是,您可以看到它在错误之前工作了 45 次。我认为这与与移动热点的连接有关,因为它在本地主机上运行良好,但我不确定。

如有任何帮助,我们将不胜感激。

python python-3.x sockets tcp pickle
1个回答
0
投票

感谢Wonka将我链接到另一个问题。我认为问题在于数据包碎片。为了解决这个问题,我只需将链接问题中的

packet = recv()
函数更改为
recvall()
函数。

© www.soinside.com 2019 - 2024. All rights reserved.