Не могу понять, как отправить двумерный массив через сокет - OSError: [WinError 10022] - PullRequest
1 голос
/ 27 марта 2020

Я пытаюсь отправить 2D-массив через сокет, его нужно сделать из нескольких socket.recv (), иначе я получу ошибку _pickle.UnpicklingError: pickle data was truncated.

Я пытался сделать это, пока l oop получает пакеты и добавляет их в список, пока не будут получены все данные:

def receive(self):
    packets = []
    while True:
        packet = self.socket.recv(1024)
        if not packet:
            break
        packets.append(packet)

    data = b"".join(packets)
    data = pickle.loads(data)
    return data

Просто выполняю:

def receive(self):
    data = self.socket.recv(1024)
    data = pickle.loads(data)
    return data

Работает, если я отправляю что-то меньше, чем двумерный массив, например, кортеж пары координат (2, 3). Но не с 2D-массивом.

Я получаю OSError: [WinError 10022] при попытке приближения в то время как l oop. Я видел, что OSError: [WinError 10022] может быть проблемой без привязки сокета, но я думаю, что сделал это.
Я не могу понять, где закрываются соединения, и я очень запутался.

Остальной код:

Сервер:

import socket
from _thread import start_new_thread

clients = []


def threaded(client):
    while True:
        data = client.recv(1024)
        if not data:
            print('Not Data.')
            break

        # Send the data received from one client to all the other clients.
        for c in clients:
            if c != client:
                c.send(data)

    client.close()


def Main():
    host = ""
    port = 5555
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((host, port))
    print("Socket binded to port:", port)

    s.listen(2)
    print("Socket is listening.")

    while True:
        c, addr = s.accept()
        clients.append(c)

        print(f"Connected to: {addr[0]}:{addr[1]}")

        start_new_thread(threaded, (c,))

    s.close()

Клиент:

import socket
import pickle


class Client:
    def __init__(self):
        self.host = 'localhost'
        self.port = 5555
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((self.host, self.port))

    def send(self, data):
        message = pickle.dumps(data)
        try:
            self.socket.send(message)
        except socket.error as e:
            return str(e)

    def receive(self):
        packets = []
        while True:
            packet = self.socket.recv(1024)
            if not packet:
                break
            packets.append(packet)

        data = b"".join(packets)
        data = pickle.loads(data)
        return data

Клиент-сервер, который я хочу сделать, будет иметь 2 клиенты и каждый клиент будут отправлять данные другому постоянно. Как я могу исправить свой код и правильно реализовать это?

1 Ответ

1 голос
/ 29 марта 2020

Проведя дополнительные исследования и выяснив, что идет не так, я нашел решение.

Код никогда не выходил из этого, пока l oop - потому что данные постоянно отправлялись, а какой-то пакет всегда приходил .

def receive(self):
    packets = []
    while True:
        packet = self.socket.recv(1024)
        if not packet:
            break
        packets.append(packet)

Решение, которое я нашел, состояло в том, чтобы отправить сообщение, указывающее, насколько большим должно быть полученное сообщение, чтобы я мог сказать, когда все байты для конкретного сообщения прибыли. Ссылки: Сокеты Python 3.5: Сокетный сервер навсегда зависает при получении файла , Python Сокет получения большого количества данных

def send(self, data):
    message = pickle.dumps(data)
    msg_len = len(message)
    try:
        # Send what the total length of the message to be sent is in bytes.
        self.socket.send(msg_len.to_bytes(4, 'big'))
        self.socket.sendall(message)
    except socket.error as e:
        return str(e)

def receive(self):
    remaining = int.from_bytes(self.socket.recv(4), 'big')
    chunks = []
    while remaining:
        # until there are bytes left...
        # fetch remaining bytes or 4096 (whatever smaller)
        chunk = self.socket.recv(min(remaining, 4096))
        remaining -= len(chunk)
        # write to file
        chunks.append(chunk)

    chunks = b"".join(chunks)
    data = pickle.loads(chunks)
    return data
...