美文网首页
sock.recv(size) 的一些行为

sock.recv(size) 的一些行为

作者: ThomasYoungK | 来源:发表于2019-01-22 23:04 被阅读14次

sock.recv(1024), 当缓冲区没有数据时
如果是阻塞IO, 如果对面关闭, 返回empty, 否则会卡住
如果是非阻塞IO, 如果对面关闭,返回emtpy, 否则抛E_AGAIN 或 E_WOULDBLOCK error(参考文献[1]和[2])

以下是一个非阻塞IO的例子, 来自于一篇twisted教程的异步客户端代码:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(address)
sock.setblocking(0)
data = ''
while True:
    try:
        # 当远端的server端关闭时, 会返回空
        # 第一次IO就绪确实能获取数据,但是while True多次(其实是第二次)直到没有数据时,就会抛出EWOULDBLOCK异常
        new_data = sock.recv(1024)  
    except socket.error, e:
        if e.args[0] == errno.EWOULDBLOCK:
            print('每当读不到数据就跳过')
            # this error code means we would have
            # blocked if the socket was blocking.
            # instead we skip to the next socket
            break
        raise
    else:
        if not new_data:
            break
        else:
            print('len(new_data)=%d', len(new_data))
            data += new_data

if not data:  #  sock.recv(1024)当server端关闭时, 会返回空
    sockets.remove(sock)
    sock.close()
    print 'Task %d finished' % task_num
else:
    addr_fmt = format_address(sock.getpeername())
    msg = 'Task: got %d bytes of poetry from %s'
    print  msg % (len(data), addr_fmt)

关于阻塞IO何时返回的问题,文献[3]讲的非常清楚

From test, I concluded that in following three cases the socket.recv(recv_size) will return.

  1. After the connection was closed. For example, the client side called socket.close() or any socket error occurred, it would return empty string.

  2. Some data come, the size of data is more than recv_size.

  3. Some data come, the size of data is less than recv_size and no more data come after a short time (I found 0.1s would work).

关于#3有如下的例子:

#server.py

while True:
    data = sock.recv(10)
    print data, 'EOF'

#client1.py

sock.sendall("12345")
sock.sendall("a" * 50)

#client2.py

sock.sendall("12345")
time.sleep(0.1)
sock.sendall("a" * 50)

When I run client1.py, the server.py echos:

12345aaaaa EOF
aaaaaaaaaa EOF
aaaaaaaaaa EOF
aaaaaaaaaa EOF
aaaaaaaaaa EOF
aaaaa EOF

When I run client2.py, the server.py echos:

12345 EOF
aaaaaaaaaa EOF
aaaaaaaaaa EOF
aaaaaaaaaa EOF
aaaaaaaaaa EOF
aaaaaaaaaa EOF

因为sock.recv(size)只要一收到数据后就会返回,而不是收到size长度后再返回,因此可以用下面的方法来读取size长度的数据(当然你应该确保确实有这么多数据):

def recv_blen(conn, blen):
    b_data = conn.recv(blen)
    while len(b_data) < blen:
        b_data += conn.recv(blen)
    return b_data

参考文献:
[1] https://stackoverflow.com/questions/37330993/sock-recv-returns-empty-string-when-connection-is-dead-on-non-blocking-socke
[2] https://stackoverflow.com/questions/20988640/python-tcp-socket-recv-returns-with-nothing-as-soon-as-connection-is-made
[3] https://stackoverflow.com/questions/7174927/when-does-socket-recvrecv-size-return

相关文章

网友评论

      本文标题:sock.recv(size) 的一些行为

      本文链接:https://www.haomeiwen.com/subject/esrdjqtx.html