как закрыть блокирующий сокет, пока он ожидает получения данных? - PullRequest
4 голосов
/ 27 сентября 2011

У меня есть сервис, который использует блокирующий сокет для получения данных. У меня проблема в том, что я не знаю, как правильно закрыть сокет, если он все еще ждет данных. Ниже приведен краткий фрагмент того, как я открываю и жду данных: я не хочу реализовывать тайм-ауты, так как согласно документации на python сокет должен блокироваться для использования makefile.

Возможно, я ошибаюсь, поскольку я новичок в программировании с использованием сокетов.

EDIT:

Следует отметить, что я не могу изменить работу сервера.

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
reader = s.makefile("rb")
line = reader.readline()

Ответы [ 4 ]

5 голосов
/ 07 июля 2012

Существует довольно простое решение. При наличии сокета и объекта файла считывателя, например rfile = socket.makefile('rb'), чтобы rfile.readline() немедленно возвращался при закрытии сокета, вам нужно выполнить следующее в отдельном потоке:

socket.shutdown(socket.SHUT_RDWR)
socket.close()

Вызов socket.shutdown() заставит rfile.readline() вернуть пустое значение str или bytes, в зависимости от версии Python (2.x или 3.x соответственно).

1 голос
/ 27 сентября 2011

Одно из решений для закрытия этого сокета - попросить сервер закрыть его.

Если сервер закроет клиентский сокет, клиент получит ошибку «Сброс соединения по одноранговой сети», что может привести к снятию блокировки.receive.

Другое решение состоит в том, чтобы не использовать readline() и не устанавливать таймаут для вашего сокета (неопределенное ожидание может ждать .... бесконечно)

1 голос
/ 27 сентября 2011

Я считаю, что если вы просто продолжите и закроете его из другого потока, то поток, который пытался прочитать из него, вернется с ошибкой.Если у вас нет нескольких потоков, вам придется выполнить рефакторинг для использования неблокирующего режима (опция os.O_NONBLOCK при открытии сокета).

0 голосов
/ 28 сентября 2011

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

from twisted.internet.protocol import ClientFactory
from twisted.protocols.basic import LineOnlyReceiver
from twisted.protocols.policies import TimeoutMixin
from twisted.internet import reactor

class YourClientProtocol(LineOnlyReceiver, TimeoutMixin):
    def connectionMade(self):
        # Initiate the timeout
        self.setTimeout(30)

    def lineReceived(self, line):
        # Reset the countdown
        self.resetTimeout()
        # And process the line somehow
        if line == "great justice":
            print "for the win!"

    def timeoutConnection(self):
        # Report the timeout
        print "Timed out waiting for a line"
        # Drop the connection
        self.transport.loseConnection()

    def connectionLost(self, reason):
        # Let the program complete
        reactor.stop()

# Set up a connection
clientFactory = ClientFactory()
clientFactory.protocol = YourClientProtocol
reactor.connectTCP(HOST, PORT)

# Start the main loop, which can handle timed and 
# network events simultaneously
reactor.run()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...