У меня есть простой сервер, который использует select (), который выглядит следующим образом:
#!/usr/bin/env python2
import select, socket
server = 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, и он прекрасно работает.Он не отвечает клиентам, но для этого простого примера это нормально.
Проблема, с которой я сталкиваюсь, заключается в следующем: если клиент отключается без отправки TCP FIN или TCP RST, сервер не 'Кажется, что когда-нибудь выяснилось, что клиент ушел.
Я имитирую исчезновение клиента, выполнив следующее:
- Запустите сервер
- Подключите клиент telnet ксервер
- Используйте iptables, чтобы заблокировать клиент telnet от общения с сервером
Насколько я знаю, нормальным решением для этого является включение TCP Keepalive, что я и делаюраскомментировав раздел TCP Keepalive.Когда я делаю это и следую той же процедуре тестирования, чтобы клиент исчезал в середине подключенного сеанса, кажется, что когда время ожидания сокета истекло, select () прекращает блокировку и возвращает клиента в «читаемый» список (в отличие от исключительного списка).Это заставляет мой сервер пытаться прочитать данные из этого сокета с помощью s.recv (1024), что приводит к сбою сервера (s.recv () выдает исключение socket.error).
Я знаю, что, вероятно, могу пойматьИсключение и справиться с ним, но мне более любопытно, почему:
- select () не улавливает тот факт, что клиент исчез
- Я думаю, один изнаиболее важные типы исключений, которые выбирает select (), - это если клиент исчез.Или он ищет искаженный ввод?
- Даже когда я явно включаю TCP Keepalive, select () все равно помещает сокет тайм-аута в читаемый список вместо исключительного списка
Ожидается ли это?Есть ли способ, чтобы select () поместил клиентов, которые исчезли в исключительный список?Или важно не предполагать, что только из-за того, что select () сказал, что сокет готов к чтению, recv () не потерпит неудачу?
Редактировать: Этот вопрос не является дубликатом вопроса, который я задавал ранее здесь , так как этот имеет дело конкретно с select (), и как он обрабатывает исключения.Этот на самом деле содержит код, который я узнал из другого вопроса.