如果使用getch,Python socket recv等待发送?

时间:2018-07-30 22:43:38

标签: python python-sockets

这是一个非常意外的行为:

这是经典的教科书简短程序,它使用一个线程从套接字流中一个接一个地获取字符并显示它,并使用第二个线程读取输入并通过相同的套接字流发送输入。

导入套接字     导入线程     进口机     导入系统

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端会在键入时发送字符(不等待换行符),如下所示:

导入套接字     导入线程     进口机     导入系统

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,Python 3.5.2

1 个答案:

答案 0 :(得分:2)

主要问题是您实际上尚未启用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_NODELAY1,而SOCK_STREAM是一个值为1的枚举,因此通过传递{{ 1}}作为您选择的TCP_NODELAY类型,也就是TCP。当SOCK_STREAM库的将来版本切换为对socket值使用枚举时(就像已经对类型使用的那样),它将变成sockopt而不是无声地做一些偶然的事情碰巧是某种工作。

如果要启用TypeError之类的sockopt值,则必须在套接字上调用setsockopt。像这样:

TCP_NODELAY

请注意,您的代码中至少还有一个其他明显的错误,尽管它没有引起任何问题:

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(和rxt)到txt。幸运的是,您实际上并没有对它们做任何事情,但是一旦您这样做,例如None,您将得到rxt.join()