Python中的recv()

use*_*374 6 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( [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)
Run Code Online (Sandbox Code Playgroud)

现在我知道这是一个简单的服务器代码,可以处理几个客户端 - 唯一我不理解的是这两行:

        data = i.recv(1024)
        if data == "":
Run Code Online (Sandbox Code Playgroud)

我知道当客户端已经接受它时会转到另一个选项,该选项检查缓冲区中是否存在某些内容.我不明白为什么,当缓冲区中没有任何内容时,它继续并且不检查该行:

if data == "":
Run Code Online (Sandbox Code Playgroud)

但是当客户端只按下相当于""它断开的输入时

为什么什么时候没有按下它是不一样的""

Gar*_*het 7

它从select通话开始.此功能监视套接字并等待值得注意的事情发生.对于第一个列表中的套接字,"值得注意"表示套接字具有可供读取的数据.

rlist, wlist, xlist = select.select( [listening_socket] + open_sockets, [], [] )
Run Code Online (Sandbox Code Playgroud)

代码现在遍历已准备好读取数据的套接字列表,并根据正在处理的套接字类型进行操作.

    for i in rlist:
        if i is listening_socket:
Run Code Online (Sandbox Code Playgroud)

面向连接("监听")套接字用于接受新连接.既然它已经存在rlist,我们知道它有一些让我们"阅读"的东西.在侦听套接字的上下文中,这意味着已收到新连接.所以我们接受连接,并将新套接字保存在列表中open_sockets.

            new_socket, addr = listening_socket.accept()
            open_sockets.append(new_socket)
Run Code Online (Sandbox Code Playgroud)

如果套接字不是listening_socket,那么它是一个(或曾经)连接到远程客户端的套接字.再次,因为它rlist,我们知道它有一些东西供我们"阅读".在连接套接字的上下文中,这意味着数据实际上可以读取,或者套接字已经关闭.

所以我们打电话recv来获取任何可用的数据,

        else:
            data = i.recv(1024)
Run Code Online (Sandbox Code Playgroud)

看看我们是否真的读过任何东西.如果没有可用的数据,则必须已关闭连接,因此我们关闭套接字对象并将其从中删除open_sockets.

            if data == "":
                i.close()
                open_sockets.remove(i)
                print "Connection closed"
Run Code Online (Sandbox Code Playgroud)

如果我们确实收到了数据,我们只需将其写回客户端并将其打印在屏幕上即可.

            else:
                i.send(data)
                print repr(data)
Run Code Online (Sandbox Code Playgroud)

第一次呼叫select将等待直到收到连接.您可以通过将代码更新为自己查看

print "About to call select"
rlist, wlist, xlist = select.select( [listening_socket] + open_sockets, [], [] )
print "Returned from select"
Run Code Online (Sandbox Code Playgroud)

第一次通话后,rlist将包括listening_socket.我们知道这是因为它open_sockets是空的,并且在select读取"读取"的内容之前,调用将不会返回.所以我们接受新连接并将其添加到open_sockets.

select被再次调用,有三种可能的事件.首先,listening_socket可能已经收到另一个连接.在这种情况下,它像以前一样处理:我们接受连接并将其添加到open_sockets.

其次,新连接可能已收到数据.由于select包含它rlist,我们知道有数据准备从套接字"读取"(意味着数据已经准备好读取,或者套接字已经关闭).i.recv将返回新数据.

第三,新的连接可能已经关闭.由于select包含它rlist,我们知道有数据可以从套接字中读取(具有与上面相同的含义).但是i.recv会返回"",因为套接字没有任何新数据.所以我们知道套接字已经关闭,并相应地进行清理.

如果没有从客户端发送数据(并且连接仍处于打开状态),则不select会将其包含在内rlist.因此循环不会处理它,i.recv也不会在该特定套接字上调用.