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

问题描述 投票:1回答:1

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

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

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

python python-sockets
1个回答
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的枚举,所以通过传递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

© www.soinside.com 2019 - 2024. All rights reserved.