2016-01-16 3 views
2

Я разрабатываю приложение обратной оболочки в python, и сейчас я пытаюсь реализовать функцию автообнаружения. Он должен работать следующим образом:UDP широковещательная рассылка и автоматическое обнаружение сервера в python, сокет TCP недоступен

  1. Сервер передает IP-порт, на который он прослушивает подключения, и ждет клиента. Если клиент не пытается подключиться через несколько секунд, он снова транслирует (и повторяется до соединения).
  2. Клиент пытается получить широковещательную передачу сервера и подключается к рекламируемому IP/порту.

Радиопередача работает отлично, клиент получает IP/порт и успешно подключается, однако после того, как с помощью подсоединенных паров портов я получаю (на стороне сервера):

socket.error: [Errno 35] Resource temporarily unavailable

сервер код бокового теста:

sckt = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sckt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
sckt.settimeout(2) 
sckt.bind(('', 9999)) 
sckt.listen(5) 

broadcastSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
broadcastSocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) 
broadcastSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
while True: 
    broadcastSocket.sendto(socket.gethostbyname(socket.getfqdn()) + ' ' + str(9999), ('<broadcast>', 8888)) 
    try: 
     sock, address = sckt.accept() 
     break 
    except socket.timeout: 
     pass 
broadcastSocket.close() 
sckt.settimeout(None) 

sock.send('test') 
# if I add time.sleep(1) here, it works, but I don't get why 
# would sock be unavailable at first, but available a second later 
print sock.recv(1) # this is where it fails 
# note that it also fails with any recv buffer size, for instance 1024 

Почему бы мне не получить 1 байт данных, вы можете спросить. У меня есть алгоритм, который префикс сообщения с их длиной, и получатель читает этот префикс побайтовым образом до разделителя, вот почему. клиентского код на сторону теста:

broadcastSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
broadcastSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
broadcastSocket.settimeout(3) 
broadcastSocket.bind(('', 8888)) 
while True: 
    try: 
     data = broadcastSocket.recv(1024) 
     break 
    except socket.timeout: 
     pass 
broadcastSocket.close() 

sckt = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sckt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
sckt.connect((str(data.split()[0]), int(data.split()[1]))) 

print sckt.recv(1024) 
sckt.send('lel') 

Если я опускаю все широковещательные и автообнаружению часть коды и просто вручную ввести IP/порт сервера print sock.recv(1) не подведет. Любые подсказки о том, что может быть проблемой?

+1

Он работает. Ваш код должен добавить, 'send' и' recv' вызовы, вызывающие ошибку – mementum

+0

Я добавил несколько строк кода, который вызывает ошибку. –

+1

Теперь ясно. В любом случае вы можете изменить заголовок, потому что ваша реальная проблема связана с сокет TCP. Что-то по строкам «TCP-сокет умирает до получения данных» – mementum

ответ

1

Изменить sckt.settimeout(None) на sock.settimout(None) в поле сервера.

Вы хотите иметь принял сокет в блокирующем режиме, а не в принимать один.

Это гарантирует, что sckt.recv ожидает входящего сообщения от клиента.

P.S. sock.setblocking(1) точно такой же

+0

Awesome, спасибо! Похоже на 3 часа с этой неприятной ошибкой. По какой-то странной причине я думал, что принятый сокет наследует свойство блокировки принимающего, но ясно, что это не так. Но, тем не менее, это в какой-то мере верно, поскольку принятые сокеты обычно блокируются по умолчанию, но теперь он разблокируется (и я думаю, это потому, что принимающий сокет разблокировался). –

+1

Вы устанавливаете ** accepting ** socket в неблокирующем режиме в начале вашего кода с помощью 'sckt.settimeout (2)'. Вот почему вы получаете ** неблокирующий принятый ** сокет. – mementum