Python中的recv()
现在我知道这是一个简单的服务器代码,可以处理一些客户端-我唯一不明白的是以下两行:Python中的recv(),python,sockets,Python,Sockets,现在我知道这是一个简单的服务器代码,可以处理一些客户端-我唯一不明白的是以下两行: open_sockets = [] listening_socket = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) listening_socket.bind( ("", 1234) ) listening_socket.listen(5) while True: rlist, wlist, xlist = select.select(
open_sockets = []
listening_socket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
listening_socket.bind( ("", 1234) )
listening_socket.listen(5)
while True:
rlist, wlist, xlist = select.select( [listening_socket] + open_sockets, [], [] )
for i in rlist:
if i is listening_socket:
new_socket, addr = listening_socket.accept()
open_sockets.append(new_socket)
else:
data = i.recv(1024)
if data == "":
i.close()
open_sockets.remove(i)
print "Connection closed"
else:
i.send(data)
print repr(data)
我知道当客户端已经接受时,它将转到另一个选项,即检查缓冲区中是否有内容的选项。我不明白为什么,当缓冲区中没有任何内容时,它会继续运行并且不检查行:
data = i.recv(1024)
if data == "":
但是,当客户端只需按enter键(相当于“”
)时,它就会断开连接
为什么按nothing时与“
不同 当套接字发送“
作为响应时,通常意味着套接字关闭(或关闭?)。如果我错了,有人纠正我。如果没有该语句,如果远程服务器突然停止响应,它可能会陷入无限循环。它从调用开始。此函数监视设置套接字并等待值得注意的事情发生。对于第一个列表中的套接字,“值得注意”表示套接字具有可读取的数据
if data == "":
代码现在遍历套接字列表,其中包含准备读取的数据,并根据正在处理的套接字类型进行操作
rlist, wlist, xlist = select.select( [listening_socket] + open_sockets, [], [] )
面向连接的(“侦听”)套接字用于接受新连接。因为它在rlist
中,所以我们知道它有一些东西可供我们“阅读”。在侦听套接字的上下文中,这意味着已接收到新连接。因此,我们接受连接,并将新套接字保存在open\u sockets
列表中
for i in rlist:
if i is listening_socket:
else:
data = i.recv(1024)
如果套接字不是侦听套接字,则它是连接到(或曾经连接到)远程客户端的套接字。同样,由于它位于rlist
,我们知道它有一些东西可供我们“阅读”。在已连接套接字的上下文中,这意味着数据实际上可以读取,或者套接字已关闭
所以我们调用recv
来获取任何可用的数据
new_socket, addr = listening_socket.accept()
open_sockets.append(new_socket)
看看我们是否真的读过什么。如果没有可用数据,则连接必须已关闭,因此我们关闭套接字对象并将其从打开的\u sockets中删除
for i in rlist:
if i is listening_socket:
else:
data = i.recv(1024)
如果我们确实收到了数据,我们只需将其写回客户端并在屏幕上打印
if data == "":
i.close()
open_sockets.remove(i)
print "Connection closed"
对select
的第一次调用将等待收到连接。您可以通过将代码更新为
else:
i.send(data)
print repr(data)
在第一次调用后,rlist
将包括侦听\u套接字
。我们之所以知道这一点,是因为open\u sockets
是空的,而所谓的select
在将某个内容读取为“read”之前不会返回。因此,我们接受新连接并将其添加到open\u sockets
for i in rlist:
if i is listening_socket:
else:
data = i.recv(1024)
再次调用select
时,有三种可能的事件。首先,侦听\u socket
可能已接收到另一个连接。在这种情况下,它的处理与以前一样:我们接受连接并将其添加到open\u sockets
for i in rlist:
if i is listening_socket:
else:
data = i.recv(1024)
其次,新连接可能已经接收到数据。由于select
将其包含在rlist
中,我们知道有数据准备好从套接字“读取”(意味着数据准备好读取,或者套接字已关闭)i.recv
将返回新数据
第三,新的连接可能已经关闭。由于select
将其包含在rlist
中,我们知道有数据可以从套接字读取(与上面的含义相同)。但是i.recv
将返回“”,因为套接字没有任何新数据。因此,我们知道插座已关闭,并进行相应的清理
如果没有从客户端发送数据(且连接仍处于打开状态),则select
将不会将其包含在rlist
中。因此循环将不会处理它,并且不会在该特定套接字上调用i.recv
。i
(顺便说一句,套接字的一个不幸名称)不会在rlist
中,除非有要读取的内容,即i.recv(1024)
将返回某个内容或连接已完成,即i.recv(1024)
返回b”“
一旦.recv()
返回b”“
您将不会从该套接字接收任何内容
“客户端(人)只需按enter键”的解释取决于客户端(软件)。它与服务器无关,例如,客户端可以缓冲输入字符串,直到遇到换行符或发生超时,或者它可以在从用户处收到每个字节后立即发送,等等。值得一提的是socket.setblocking()
和socket.settimeout()
,我认为,因为严格来说,recv
会普遍阻塞不是真的。它不会阻塞i
表示i
已“准备好”阅读。1024是bufsize,recv()可以返回更少字节。我不明白。你说的是,如果不按任何键,它将无法通过线路,因此它将被卡住,无法通过其他客户端,或者你的意思是它将跳过if条件?@J.F.Sebastian,你完全正确。我已经编辑了我的答案。谢谢。@user1779374,请让我知道编辑是否有助于澄清。谢谢这是正确的。这正好发生在我身上,它导致了巨大的内存过载,因为我正在向列表中添加数据以查找终端标记。谢谢你指出这一点。@MichaelDavidWatson一个相当流行的网络库也有一个类似的bug,它在我的代码中造成了混乱的无限循环挂起。一个简单的如果不是数据:引发异常通常是最好的解决方法。
print "About to call select"
rlist, wlist, xlist = select.select( [listening_socket] + open_sockets, [], [] )
print "Returned from select"