如何在保持套接字打开的情况下确定Python中传入套接字数据的数据类型

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

我似乎找不到问题所在。我想做的是,保持客户端和服务器套接字打开,同时使用结构区分传入数据的类型。在我运行服务器和客户端代码后,套接字连接似乎中断了。也许与服务器代码中的 while 循环有关。请帮忙。

这是我的服务器代码:

                import struct
                import socket
                import threading
                import random

                # Define the server's IP address and port
                SERVER_IP = '0.0.0.0'
                SERVER_PORT = 55555

                # Create a socket for the server
                server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                server_socket.bind((SERVER_IP, SERVER_PORT))
                server_socket.listen()

                # Dictionary to store client sockets based on their public keys
                client_sockets = {}

                def handle_client(client_socket):
                    try:
                        while True:
                            # Receive a message
                            message_type, received_message = receive_message(client_socket)
                            
                            if message_type == 1:
                                # Store the client socket in the dictionary with the public key as the key
                                client_sockets[received_message] = client_socket
                                print(f"Client connected with public key: {received_message}")

                            if message_type == 2:
                                # Example: Sending a broadcast message to all connected clients
                                print(received_message)
                    except Exception as e:
                        print(f"Error handling client: {e}")
                    

                def receive_message(socket):
                    # Receive the header
                    print("Received message")
                    header = socket.recv(8)

                    # Unpack the message type and length
                    message_type, length = struct.unpack('!II', header)

                    # Receive the message data
                    message_data = socket.recv(length)

                    if message_type == 2:
                        # Extract regular message and public key as bytes
                        null_char_index = message_data.index(b'\0')
                        regular_message = message_data[:null_char_index].decode('utf-8')
                        public_key = message_data[null_char_index+1:] if len(message_data) > null_char_index+1 else None
                        return message_type, regular_message, public_key
                    
                    else:
                        # Handle other message types as needed
                        return message_type, message_data

                def send_message(socket, message_type, message_data):
                    # Pack the message type and length
                    header = struct.pack('!II', message_type, len(message_data))

                    # Send the header
                    socket.sendall(header)

                    # Send the message data
                    socket.sendall(message_data)


                while True:
                    # Accept a client connection
                    client_socket, client_address = server_socket.accept()

                    # Create a new thread to handle the client
                    client_thread = threading.Thread(target=handle_client, args=(client_socket,))
                    client_thread.start()

这是我的客户端代码:

                import socket
                import struct 
                import threading
                from cryptography.hazmat.backends import default_backend
                from cryptography.hazmat.primitives import padding
                from cryptography.hazmat.primitives.asymmetric import x25519, ed25519
                from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
                from cryptography.hazmat.primitives import serialization
                from os import urandom



                def generate_key_pair():
                    private_key = x25519.X25519PrivateKey.generate()
                    public_key = private_key.public_key()
                    return private_key, public_key


                def send_message(socket, message_type, message_data, public_key=None):
                    # Pack the message type and length
                    header = struct.pack('!II', message_type, len(message_data) + len(public_key) + 1 if public_key else len(message_data))
                

                    # Send the message data
                    if message_type == 1:
                        socket.sendall(header)
                        # If it's a public key, send as-is (assuming it's already in bytes)
                        socket.sendall(message_data)
                    elif message_type == 2:
                        socket.sendall(header)
                        # If it's a regular message with a public key, concatenate both with a null character separator before sending
                        if public_key:
                            combined_data = message_data.encode('utf-8') + b'\0' + public_key
                            print(combined_data)
                        else:
                            # If no public key, send only the regular message
                            socket.sendall(message_data.encode('utf-8'))
                    else:
                        # Handle other message types as needed
                        print("Unsupported message type:", message_type)

                def receive_messages(socket):
                    while True:
                        try:
                            # Receive messages from the server
                            message_type, received_message = receive_message(socket)

                            if message_type == 2:
                                # If it's a regular message, print it
                                print("Received message from server:", received_message.decode('utf-8'))

                        except Exception as e:
                            print(f"Error receiving message from server: {e}")
                            break

                def receive_message(socket):
                    # Receive the header
                    header = socket.recv(8)

                    # Unpack the message type and length
                    message_type, length = struct.unpack('!II', header)

                    # Receive the message data
                    message_data = socket.recv(length)

                    return message_type, message_data

                # Create a client socket
                client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                client_socket.connect(('44.216.25.151', 55555))

                # Generate client key pair
                private_key, public_key = generate_key_pair()

                # Serialize public key to bytes
                serialized_pub_key = public_key.public_bytes(
                    encoding=serialization.Encoding.Raw,
                    format=serialization.PublicFormat.Raw
                )

                # Send the public key to the server
                send_message(client_socket, 1, serialized_pub_key)

                # Start a thread to receive messages from the server
                receive_thread = threading.Thread(target=receive_messages, args=(client_socket,))
                receive_thread.start()


                while True:
                    # Get user input or any other data to send
                    user_input = input("Enter a message to send: ")
                    # Sending a regular message
                    regular_message = user_input
                    send_message(client_socket, 2, regular_message, serialized_pub_key)



客户端代码的输出是:

                $ python3 client3.py 
                Enter a message to send: hi
                b'hi\x00:{uF\xac\xf6\\m\x8a\xb5\xb2\x14\xdeuq\xa5{\\-\xd0W\x1e,C\xf0\xfa\xa4\x87{#\xfa\x1f'
                Enter a message to send: hi
                b'hi\x00:{uF\xac\xf6\\m\x8a\xb5\xb2\x14\xdeuq\xa5{\\-\xd0W\x1e,C\xf0\xfa\xa4\x87{#\xfa\x1f'
                Enter a message to send: 

服务器端的输出为:

                $ python3 server7.py
                Received message
                Client connected with public key: b':{uF\xac\xf6\\m\x8a\xb5\xb2\x14\xdeuq\xa5{\\-\xd0W\x1e,C\xf0\xfa\xa4\x87{#\xfa\x1f'
                Received message
                Error handling client: too many values to unpack (expected 2)

python multithreading sockets struct tcp
1个回答
0
投票

我假设您的服务器端代码正在处理类型 2 的传入消息(带有公钥的常规消息)。现在,您收到“太多值无法解包(预期为 2)”的错误基本上是在告诉您服务器端的 receive_message 函数返回的值比handle_client 函数预期的要多。

您的代码中实际上有两个问题,receive_message 中不匹配 - 主要问题在于返回值中。并在客户端本身发送消息。我已经解释了当

receive_message
函数不匹配时会发生什么,现在详细说明第二个:当传递类型2消息时,客户端的
send_message
函数仅在
public_key
可用时发送标头和组合数据。另一方面,如果
public_key
为 None,则该函数不会传递组合数据。

解决这个问题首先要解决/修改服务器代码,这将涉及:

  1. receive_message
    函数返回值的标准化:返回值的数量必须始终相同。例如,
    Message_type
    message_data
    public_key
    是它始终可以返回的三个值(如果不适用,可以是
    None
    )。

  2. 更新handle_client函数:您需要更新

    handle_client
    函数来处理来自
    receive_message
    的额外返回值。

解决问题的第二部分是修改客户端代码: 更正

send_message
逻辑,确保无论是否存在 public_key,消息数据都会在标头之后传输。

您的代码应该如下所示:

服务器代码更新:

def receive_message(socket):
    # Code before    
    message_data = socket.recv(length)
    public_key = None
    if message_type == 2:
        return message_type, regular_message, public_key
    else:
        return message_type, message_data, public_key

handle_client
功能中:

def handle_client(client_socket):
    try:
        while True:
            message_type, received_message, public_key = receive_message(client_socket)

客户端代码更新:

send_message
函数中:

def send_message(socket, message_type, message_data, public_key=None):
    # Existing code

    socket.sendall(header)

    # Revised logic to send message data
    if message_type == 1:
        socket.sendall(message_data)
    elif message_type == 2:
        combined_data = message_data.encode('utf-8') + b'\0' + public_key if public_key else message_data.encode('utf-8')
        socket.sendall(combined_data)
    else:
        # Handle other message types as needed
        print("Unsupported message type:", message_type)

我希望这能让您走上正确的道路。

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