Python: неблокирующий сокет или асинхронный ввод / вывод - PullRequest
10 голосов
/ 16 июня 2011

Я новичок в Python и в настоящее время должен написать сокет python для запуска в качестве сценария, который связывается с устройством по TCP / IP (метеостанция).
Устройство действует как сторона сервера (прослушивание через IP: PORT, принятие соединения, получение запроса, передача данных).
Мне нужно только отправить одно сообщение, получить ответ, а затем спокойно и красиво выключить и закрыть розетку.

try:
    comSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    sys.stderr.write("[ERROR] %s\n" % msg[1])
    sys.exit(1)

try:
   comSocket.connect((''))
except socket.error, msg:
   sys.stderr.write("[ERROR] %s\n" % msg[1])
   sys.exit(2)

comSocket.send('\r')
comSocket.recv(128)
comSocket.send('\r')
comSocket.recv(128)
comSocket.send('\r\r')
comSocket.recv(128)

comSocket.send('1I\r\r3I\r\r4I\r\r13I\r\r5I\r\r8I\r\r7I\r\r9I\r\r')

rawData = comSocket.recv(512)

comSocket.shutdown(1)
comSocket.close()

У меня проблема:
Канал связи ненадежен, устройство работает медленно. Таким образом, иногда ответ устройства с сообщением длиной 0 (просто ACK), мой код будет зависать и ждать ответа навсегда.
Этот фрагмент кода содержит часть, включающую SOCKET, весь код будет выполняться под CRON, поэтому замораживание нежелательно.

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

Ответы [ 3 ]

11 голосов
/ 16 июня 2011

Вы можете попробовать тайм-аут подход, такой как код Рассела, или вы можете использовать неблокирующий сокет, как показано в коде ниже. Он никогда не будет блокироваться на socket.recv, и вы можете использовать его внутри цикла, чтобы повторить столько раз, сколько захотите. Таким образом, ваша программа не будет зависать во время ожидания. Таким образом, вы можете проверить, доступны ли данные, а если нет, вы можете заняться другими делами и повторить попытку позже.

socket.setblocking(0)
while (retry_condition):
    try:
        data = socket.recv(512)
    except socket.error:
        '''no data yet..'''
3 голосов
/ 16 июня 2011

Я бы порекомендовал для этого Eventlet и зеленые потоки.

Twisted - хорошая библиотека, но немного крутая кривая обучения для такого простого варианта использования.

Посмотрите несколько примеров здесь .

0 голосов
/ 16 июня 2011

Попробуйте, до получения, положить тайм-аут на сокет:

comSocket.settimeout(5.0)
try:
    rawData = comSocket.recv(512)
except socket.timeout:
    print "No response from server"
...