Почему при отправке нескольких сообщений клиентский сокет остается открытым, почему программа выдает ошибку при большой задержке сообщений? - PullRequest
0 голосов
/ 28 декабря 2018

Есть сервер, который прослушивает соединения.Клиентский сокет подключается к серверу и несколько раз вызывает sendall() в цикле перед его закрытием.Однако, если любая итерация занимает некоторое время, существует ConnectionAbortedError.

Существует цикл, начинающийся с 0-9, где на каждой итерации sendall() использует клиентский сокет.Чтобы создать задержку, я добавил фиктивный цикл while, который просто увеличивает некоторую переменную.

Соответствующая часть кода сервера

with socket.socket() as s:
    s.bind(('127.0.0.1', 65432))
    s.listen()

    while True:
        connection, address = s.accept()

        with connection:
            data = connection.recv(72)
            print('Client says "{}"'.format(data))

Код клиента

with socket.socket() as s:
    s.connect((host, port))
    for i in range(10):
        s.sendall(bytes("message {}".format(i+1), encoding='utf-8'))

        if i+1 == 3:
            count = 0
            while count < 12000:
                count += 1

Небольшой предел для подсчета в цикле while, например, 500, работает нормально.Однако, что-то выше 5000, кажется, вызывает ошибку.Мне не понятно, почему они дают разные результаты.

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

Ваш сервер читает с клиента ровно один раз и получает до 72 байт, а затем закрывает соединение.Если клиент может отправить все 10 сообщений достаточно быстро, он не получит ошибку.Прочтите об алгоритме Nagle , который:

запрещает [s] отправку новых сегментов TCP, когда новые исходящие данные поступают от пользователя, если ранее переданные данные по соединению остаются неподтвержденными.

Ваш сервер никогда не получит все сообщения (всего 91 байт), но клиент не выдаст ошибку, если он все их отправит.

Небольшое изменение на сервере делаетубедитесь, что он получает все данные (независимо от задержки), ожидая, пока клиент не закроет соединение:

with connection:
    while True:
        data = connection.recv(72)
        if not data: break # empty data means client closed connection.
        print('Client says "{}"'.format(data))

Он по-прежнему не будет получать сообщения по одному.TCP - это потоковый протокол, поэтому сообщения объединяются вместе.Вам нужно добавить буферизацию и средство для извлечения из нее только полных сообщений.Пример (Python 3.6 +):

client.py

import socket

host = '127.0.0.1'
port = 65432

with socket.socket() as s:
    s.connect((host, port))
    for i in range(10):
        # Use newline as message delimiter.
        s.sendall(f'message {i+1}\n'.encode())

server.py

import socket

with socket.socket() as s:
    s.bind(('127.0.0.1', 65432))
    s.listen()

    while True:
        connection, address = s.accept()

        with connection:
            data = b''
            while True:
                chunk = connection.recv(16)
                if not chunk: break # client closed connection
                data += chunk # buffer input
                while b'\n' in data: # break off messages and display
                    msg,_,data = data.partition(b'\n')
                    print(f'Client says "{msg.decode()}"')
            if data:
                print(f'Incomplete message: {data}')

Вывод:

Client says "message 1"
Client says "message 2"
Client says "message 3"
Client says "message 4"
Client says "message 5"
Client says "message 6"
Client says "message 7"
Client says "message 8"
Client says "message 9"
Client says "message 10"
0 голосов
/ 28 декабря 2018

Ваш серверный код неверен.Вы должны использовать threading или любой другой метод для обслуживания нескольких клиентских подключений.Что здесь происходит:

1) Сервер принимает первый сокет

2) Сервер получает 72 байта

3) Соединение закрыто , потому что withоператор закрывает его

4) Сервер переходит к следующему accept -loop

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...