Прием сокета Python ожидает отправки при использовании getch?

Это очень неожиданное поведение:

Вот классическая короткая программа из учебника, которая использует один поток для получения символов один за другим из потока сокета и их отображения, а второй поток — для чтения ввода и отправки ввода через тот же поток сокета.

импортировать сокет, импортировать потоки, импортировать getch, импортировать sys

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)

def rxWorker():
    while(True):
        r = s.recv(1)
        print(r.decode('ascii'), end='')

def txWorker():
    while (True):
        i = input('')
        s.send(i.encode())

s.connect(('localhost',9999))

threading.Thread(name='Rx', target=rxWorker).start()
threading.Thread(name='Tx', target=txWorker).start()

Это работает против прослушивателя netcat, который работает на другом терминале:

nc -l localhost 9999

На данный момент все работает хорошо. Линии передаются из стороны в сторону и выглядят так, как ожидалось.

Теперь ввод изменен на немедленный, поэтому сторона python отправляет символы по мере их ввода (не дожидаясь новой строки), например:

импортировать сокет, импортировать потоки, импортировать getch, импортировать sys

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)

def rxWorker():
    while(True):
        r = s.recv(1)
        print(r.decode('ascii'), end='')

def txWorker():
    while (True):
        # i = input('')
        i = getch.getche()
        s.send(i.encode())

s.connect(('localhost',9999))

threading.Thread(name='Rx', target=rxWorker).start()
threading.Thread(name='Tx', target=txWorker).start()

Обратите внимание, что единственным изменением является способ чтения ввода: i = getch.getche() против i = input('')

Теперь поведение другое.

Символы со стороны python отображаются на стороне netcat правильно и сразу.

Проблема: персонаж со стороны netcat теперь не сразу отображается на стороне python. На самом деле они не отображаются, пока один или несколько символов не будут отправлены с python на netcat.

Это очень странно и как бы нарушает мой поток управления/:

пожалуйста, порекомендуйте

Система: Ubuntu 16.04, питон 3.5.2


person user1656671    schedule 30.07.2018    source источник
comment
Внесены некоторые изменения в образец кода в соответствии с примечаниями абарнерта. проблема, сохраняется, как описано.   -  person user1656671    schedule 31.07.2018


Ответы (1)


Основная проблема в том, что вы на самом деле не включили TCP_NODELAY.

Эта строка делает не то, что вы думаете:

s = socket.socket(socket.AF_INET, socket.TCP_NODELAY )

Аргументы для socket:

socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)

Так получилось, что, по крайней мере, в системах *nix TCP_NODELAY равно 1, а SOCK_STREAM - это перечисление со значением 1, поэтому, передавая TCP_NODELAY в качестве типа, вы выбираете SOCK_STREAM, также известный как TCP. Когда будущая версия библиотеки socket переключится на использование перечислений для sockopt значений (как это уже происходит для типов), это станет TypeError вместо того, чтобы тихо делать что-то неожиданное, что иногда случается с работой.

Если вы хотите включить значение sockopt, например TCP_NODELAY, вам нужно вызвать setsockopt на сокете. Как это:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)

В качестве примечания: в вашем коде есть по крайней мере еще одна очевидная ошибка, хотя она не вызывает никаких проблем:

rxt = threading.Thread(name='Rx', target=rxWorker).start()

Thread.start возвращает None. Итак, вы видите от rxttxt) до None. К счастью, вы на самом деле ничего с ними не делаете, но как только вы это сделаете, например, rxt.join(), вы получите AttributeError.

person abarnert    schedule 31.07.2018
comment
Спасибо за комментарии. Я изменил вопрос в соответствии с комментариями, чтобы сделать вопрос более ясным. К сожалению, проблема не связана с флагами и сохраняется до сих пор. - person user1656671; 31.07.2018