Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python通过select控制死插座的故障_Python_Sockets_Select_Tcp_Blocking - Fatal编程技术网

python通过select控制死插座的故障

python通过select控制死插座的故障,python,sockets,select,tcp,blocking,Python,Sockets,Select,Tcp,Blocking,我有一些代码,它将连接到主机,只监听传入数据,直到客户端关闭或主机发送close语句。为此,我的代码运行良好 但是,当主机死亡而未发送close语句时,我的客户机将一如既往地侦听传入的数据。为了解决这个问题,我让套接字每foo秒超时一次,然后开始检查连接是否处于活动状态。从Python howto中,我发现: select有一个非常严重的问题:如果套接字输入列表中的某个地方是一个死气沉沉的套接字,select将失败。然后,您需要遍历所有这些列表中的每一个该死的套接字,并进行选择([sock],[

我有一些代码,它将连接到主机,只监听传入数据,直到客户端关闭或主机发送close语句。为此,我的代码运行良好

但是,当主机死亡而未发送close语句时,我的客户机将一如既往地侦听传入的数据。为了解决这个问题,我让套接字每foo秒超时一次,然后开始检查连接是否处于活动状态。从Python howto中,我发现:

select有一个非常严重的问题:如果套接字输入列表中的某个地方是一个死气沉沉的套接字,select将失败。然后,您需要遍历所有这些列表中的每一个该死的套接字,并进行选择([sock],[],0),直到找到错误的套接字。超时值为0意味着不会花太长时间,但这很难看

本文提出三个问题

  • 我被教导,要检查连接是否处于活动状态,必须向套接字写入数据并查看是否返回响应。如果不是,则必须假定连接已断开。在文本中,它说,要检查坏连接,每个套接字单独一个,将其传递给select的第一个参数,并将超时设置为零。这将如何确认插座是否已断开
  • 为什么不改为尝试写入套接字来测试套接字是死的还是活的呢
  • 当连接处于活动状态时,我在寻找什么?当连接处于死亡状态时,我在寻找什么?Select将立即超时,因此没有数据将证明什么也没有 我意识到有像
    gevent
    asyncore
    twisted
    这样的库可以帮助我做到这一点,但我选择自己这样做是为了更好地了解正在发生的事情,并更好地控制自己的源代码

  • 如果您向套接字写入内容,然后等待应答以检查连接,则服务器应支持此“ping”消息。情况并非总是如此。否则,如果服务器不等待此消息,服务器应用可能会自行崩溃或断开客户端连接。 如果按您描述的方式选择失败,套接字框架将知道哪个套接字已失效。你只需要找到它。但是,如果一个套接字被服务器的应用程序崩溃这样的严重死亡所破坏,这并不意味着客户端的套接字框架必须检测到这一点。例如,当客户机正在等待来自服务器的某些消息时,服务器崩溃,在某些情况下,客户机可以永远等待。例如Putty,为了避免这种情况,可以使用服务器的应用程序协议级别ping(SSH-ping选项)来检查连接;SSH服务器可以使用TCP keepalive检查连接,并防止网络设备在没有活动的情况下断开连接
  • (见第1页)
  • 您是对的,select的超时和没有数据证明了什么。正如文档所述,当select失败时,您必须检查每个套接字

  • 如果连接的客户端崩溃或退出,但其主机操作系统和计算机仍在运行,则其操作系统的TCP堆栈将向服务器发送一个FIN数据包,让计算机的TCP堆栈知道TCP连接已关闭。Python应用程序会将其视为select(),表示客户端的套接字已准备好读取,然后在套接字上调用recv()时,recv()将返回0。当这种情况发生时,您应该关闭套接字来响应


    另一方面,如果连接的客户机的计算机从来没有机会发送FIN数据包(例如,因为有人伸手将其以太网线或电源线从插座中拔出),那么您的服务器将不会意识到TCP连接在相当长的一段时间内(可能永远)失效。避免“僵尸套接字”的最简单方法就是让服务器每隔一段时间(例如每分钟一次)在套接字上发送一些虚拟数据。客户机应该知道如何丢弃虚拟数据。发送虚拟数据的好处是,您的服务器的TCP堆栈随后会注意到,它没有为它发送的数据包返回任何ACK数据包,并将重新发送它们;在重新发送几次之后,服务器的TCP堆栈将放弃并确定连接已断开,此时您将看到与我在第一段中描述的相同的行为。

    我不确定Python howto是否正确,它必须循环所有套接字以确定哪一个已“死掉”。根据我的经验,select()只有在传递无效的文件描述符时才会失败,即使远程对等方突然断开连接的套接字在显式关闭之前仍然是完全有效的套接字。因此,请恕我直言。@JeremyFriesner我认为向死套接字写入数据会发现它死了(在尝试重新传输段后,客户端将关闭套接字并向服务器发送RST)。@Den是的,您是正确的。
        # Example code written for this question.
        from select import select
        from socket include socket, AF_INET, SOCK_STREAM
    
        socket = socket(AF_INET, SOCK_STREAM)
        socket.connect(('localhost', 12345))
        socklist = [socket,]
        attempts = 0
    
        def check_socklist(socks):
            for sock in socklist:
                (r, w, e) = select([sock,], [], [], 0)          
    
                ...
                ...
                ...
    
        while True:
    
            (r, w, e) = select(socklist, [], [], 60)
    
            for sock in r:      
                if sock is socket:
                    msg = sock.recv(4096)
                    if not msg:
                        attempts +=1
                        if attempts >= 10:
                            check_socket(socklist)
                        break
                    else:
                        attempts = 0
                        print msg