如何连接()与非阻塞套接字?

时间:2016-03-18 19:15:28

标签: python sockets networking nonblocking

在Python中,我想在我设置为非阻塞的套接字上使用socket.connect()。当我尝试这样做时,该方法总是抛出BlockingIOError。当我忽略错误(如下所示)时,程序按预期执行。在连接后将套接字设置为非阻塞时,没有错误。当我使用select.select()来确保套接字可读或可写时,我仍然会收到错误。

testserver.py

import socket
import select

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(0)

host = socket.gethostname()
port = 1234

sock.bind((host, port))
sock.listen(5)

while True:
    select.select([sock], [], [])
    con, addr = sock.accept()
    message = con.recv(1024).decode('UTF-8')
    print(message)

testclient.py

import socket
import select

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(0)

host = socket.gethostname()
port = 1234

try:
    sock.connect((host, port))
except BlockingIOError as e:
    print("BlockingIOError")

msg = "--> From the client\n"

select.select([], [sock], [])
if sock.send(bytes(msg, 'UTF-8')) == len(msg):
    print("sent ", repr(msg), " successfully.")

sock.close()

终端1

$ python testserver.py
--> From the client

终端2

$ python testclient.py
BlockingIOError
sent  '--> From the client\n'  successfully.

除了第一个connect()上的BlockingIOError之外,此代码正常工作。错误的文档如下所示:Raised when an operation would block on an object (e.g. socket) set for non-blocking operation.

如何正确连接()与设置为非阻塞的套接字?我可以使connect()无阻塞吗?或者忽略错误是否合适?

1 个答案:

答案 0 :(得分:0)

这里的技巧是当第一次完成选择时,然后你需要再次调用sock.connect在您从connect收到成功的返回状态之前,套接字未连接。

在第一次调用{/ 1}}之后,只需添加以下两行

select

编辑:
跟进。我说错了需要额外调用print("first select completed") sock.connect((host, port)) ,这是错误的。但是,如果您希望在自己的代码路径中处理连接失败,则可以发现对sock.connect的原始非阻塞调用是否成功。

此处解释了在C代码中实现此目的的传统方法:Async connect and disconnect with epoll (Linux)

这涉及致电connect。您也可以在python中执行此操作,但从getsockopt返回的结果是sock.getsockopt对象。如果它表示失败,那么您需要将其转换为整数bytes值并将其映射到字符串(或异常或将问题传达给外部世界所需的任何内容)。再次调用errno会将sock.connect值映射到适当的异常。

解决方案2: 您也可以在连接完成后将<{1}}推迟到