这是一个非常意外的行为:
这是一个教科书经典的短程序,它使用一个线程从套接字流逐个获取字符并显示它,第二个线程读取输入并通过相同的套接字流发送输入。
import socket import threading import getch import 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端在输入字符时会发送字符(不等待换行符),如下所示:
import socket import threading import getch import 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()
vs i = input('')
现在行为是不同的。
python端的字符正确且立即出现在netcat端。
问题:netcat端的字符现在不会立即显示在python端。实际上,直到从python发送一个或多个字符到netcat才显示。
这很奇怪,有点打破我的控制流程/:
请指教
系统:Ubuntu 16.04,python 3.5.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_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
。所以你看到rxt
(和txt
)到None
。幸运的是,你实际上并没有对它们做任何事情 - 但是一旦你这样做,例如rxt.join()
,你就会得到一个AttributeError
。