我正在尝试解决网络中的连接问题,试图了解为什么某些用户在开机时可以看到一个盒子,而其他用户可能需要近20秒钟才能看到它。这在我们的本地程序中引起了一些致命的问题。
为此,我运行了一个简单的最小可验证python脚本,尝试找出问题所在:
import socket
import time
import errno
HOST = '192.168.1.1'
PORT = 12345
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1)
while(True):
err = s.connect_ex((HOST, PORT))
if err == 0:
print("CONNECTED")
else:
print("NO CONNECTION: {0}".format(errno.errorcode[err]))
time.sleep(2)
运行此代码时,我看到一个一致的模式:EAGAIN,后跟10个EALREADY实例。完成连接后,“ CONNECTED”将替换周期的EAGAIN位。
我认为将超时设置为1秒并等待2秒,应该可以让我更快地在后台中止connect调用,但这似乎没有任何作用。有没有我可以设置的TCP选项或我可以调整的Windows设置,以确保在轮询远程设备以进行连接时不会出现这些尴尬的20秒块?
答案 0 :(得分:1)
通过在套接字上设置超时,socket.connect_ex()
成为非阻塞操作。这就是为什么在循环中反复调用EAGAIN
时遇到EALREADY
和connect_ex()
错误的原因-第一次调用EAGAIN
表示连接无法立即完成并且正在进行中在后台,然后在后续调用中EALREADY
表示现有连接仍在进行中,尚未完成。
您的循环会一直运行,直到连接最终以成功或失败结束,无论需要多长时间。您设置的套接字超时不会影响该逻辑。
要执行所需的操作,请在连接循环的同时运行自己的计时器,然后在socket.connect_ex()
返回其最终结果之前,如果计时器已过,则关闭套接字。
或者,完全摆脱循环。
呼叫socket.connect_ex()
一次,如果返回EAGAIN
,则使用select.select()
等待连接完成。它具有一个timeout
参数。如果挂起的连接尝试成功连接到服务器,则TCP套接字将进入可写状态。如果select()
超时或报告错误,请关闭套接字。
或者尝试使用socket.create_connection()
,它也有一个timeout
参数。