我有一個(gè)使用 select() 的簡單服務(wù)器,如下所示:#!/usr/bin/env python2import select, socketserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server.setblocking(0)server.bind(('localhost', 50000))server.listen(5)# TCP Keepalive Options#server.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)#server.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1)#server.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 3)#server.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5)inputs = [server]print "Listening on port 50000"while True: readable, writable, exceptional = select.select(inputs, [], inputs) for s in readable: if s is server: connection, client_address = s.accept() print "New client connected: %s" % (client_address,) connection.setblocking(0) inputs.append(connection) else: data = s.recv(1024) if data: print "Data from %s: %s" % (s.getpeername(), data.replace('\n', '')) else: print "%s disconnected" % (s.getpeername(),) inputs.remove(s) s.close() for s in exceptional: print "Client at %s dropped out" % (s.getpeername(),) inputs.remove(s) s.close()我可以使用 telnet 客戶端連接到它,而且效果很好。它不響應(yīng)客戶端,但對(duì)于這個(gè)簡單的例子,這很好。我看到的問題是:如果客戶端在沒有發(fā)送 TCP FIN 或 TCP RST 的情況下斷開連接,服務(wù)器似乎永遠(yuǎn)不會(huì)發(fā)現(xiàn)客戶端已經(jīng)消失。我通過這樣做來模擬客戶端消失:運(yùn)行服務(wù)器將 telnet 客戶端連接到服務(wù)器使用 iptables 阻止 telnet 客戶端與服務(wù)器通信據(jù)我所知,正常的解決方案是打開 TCP Keepalive,我通過取消對(duì) TCP Keepalive 部分的注釋來實(shí)現(xiàn)。當(dāng)我這樣做時(shí),并按照相同的測(cè)試程序使客戶端在連接會(huì)話的中間消失,似乎當(dāng)套接字超時(shí)時(shí),select() 停止阻塞,并在“可讀”列表中返回客戶端(與例外列表相反)。這會(huì)導(dǎo)致我的服務(wù)器嘗試使用 s.recv(1024) 從該套接字讀取數(shù)據(jù),這會(huì)導(dǎo)致服務(wù)器崩潰(s.recv() 引發(fā) socket.error 異常)。我知道我可能可以捕獲異常并處理它,但我更好奇為什么:select() 沒有發(fā)現(xiàn)客戶端消失的事實(shí)我認(rèn)為 select() 會(huì)尋找的最重要的異常類型之一是客戶端是否消失?;蛘咚趯ふ襾y碼的輸入?即使我顯式啟用 TCP Keepalive,select() 仍然將超時(shí)套接字放入可讀列表而不是異常列表這是預(yù)期的嗎?有沒有辦法讓 select() 將消失的客戶端放入例外列表中?或者重要的是不要假設(shè)僅僅因?yàn)?select() 表示套接字已準(zhǔn)備好讀取,recv() 不會(huì)失?。烤庉嫞哼@個(gè)問題不是我之前在這里問的問題的重復(fù),因?yàn)檫@個(gè)問題專門處理 select() 以及它如何處理異常。這個(gè)實(shí)際上包括我從另一個(gè)問題中學(xué)到的代碼。
1 回答

犯罪嫌疑人X
TA貢獻(xiàn)2080條經(jīng)驗(yàn) 獲得超4個(gè)贊
當(dāng)您使用 keepalive 并檢測(cè)到故障時(shí),select()
應(yīng)該將套接字報(bào)告為可讀和可寫。然后,當(dāng)您嘗試執(zhí)行其中一項(xiàng)操作時(shí),您應(yīng)該會(huì)收到錯(cuò)誤消息。使用try/except
周圍s.recv()
調(diào)用來檢測(cè)socket.error
。
您可能天真地認(rèn)為這會(huì)被報(bào)告為“特殊情況”,但事實(shí)并非如此。這用于有效套接字上的正常異常,例如帶外數(shù)據(jù)。
添加回答
舉報(bào)
0/150
提交
取消