Как вы можете определить, когда TCP-клиент отключается с помощью Python select ()? - PullRequest
0 голосов
/ 08 декабря 2018

У меня есть простой сервер, который использует 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).

Я знаю, что, вероятно, могу пойматьИсключение и справиться с ним, но мне более любопытно, почему:

  1. select () не улавливает тот факт, что клиент исчез
    • Я думаю, один изнаиболее важные типы исключений, которые выбирает select (), - это если клиент исчез.Или он ищет искаженный ввод?
  2. Даже когда я явно включаю TCP Keepalive, select () все равно помещает сокет тайм-аута в читаемый список вместо исключительного списка

Ожидается ли это?Есть ли способ, чтобы select () поместил клиентов, которые исчезли в исключительный список?Или важно не предполагать, что только из-за того, что select () сказал, что сокет готов к чтению, recv () не потерпит неудачу?

Редактировать: Этот вопрос не является дубликатом вопроса, который я задавал ранее здесь , так как этот имеет дело конкретно с select (), и как он обрабатывает исключения.Этот на самом деле содержит код, который я узнал из другого вопроса.

1 Ответ

0 голосов
/ 08 декабря 2018

Когда вы используете keepalive и обнаруживает сбой, select() должен сообщать о сокете как о доступном для чтения и записи.Затем, когда вы попытаетесь выполнить одну из этих операций, вы получите сообщение об ошибке.Используйте try/except вокруг вызова s.recv(), чтобы обнаружить socket.error.

. Вы можете наивно предполагать, что это будет сообщено как «исключительная ситуация», но это не так.Это используется для обычных исключений в допустимом сокете, таких как внеполосные данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...