LINUX.ORG.RU

[python] как правильно закрыть сокет


0

1

Есть клиент и есть сервер, написаны через модуль socket. Сервер в беск. цикле ждет соединения (socket.accept(...)).

Нужно в ОДНОМ скрипте bash запустить сервер, запустить клиента (тот стучится на сервер чего то делает и отваливается), потом грохнуть сервер так, что бы он отдал порт.

Запускаем сервер в фоне, запускаем клиента... валим сервер killall-ом... дальше начинается кино. Деструктор объекта сокет не отрабатывает, порт висит занятым еще сек 10-20, пока не стухнет по таймату (видимо). При попытке послать сигнал 2 (аналог Ctrl-C) ничего не происходит, сервер его тупо игнорирует (нет консоли что ли)? На все остальные сигналы тоже в обще плюет, кроме 9 и 15. Попытка явно повесить что то внятное на какой сигнал ни к чему не приводят - если вешаем метод close или shutdown вылетает сообщение

socket.error: (4, 'Interrupted system call')

и порт все равно остается занятым, если вешаем sys.exit() ничего не вылетает но порт все равно занят.

В общем вопрос - как корректно прибить снаружи сокет, который висит на методе accept? С консоли это делается Ctrl-C, но тут похоже он консоли то не видит...

Пока что я в баше сначала тупо жду освобождения порта, но это мягко говоря неудобно.

★★★★★

Чему у вас равен таймаут? Установлен ли blocking?

ilias ()

> который висит на методе accept

Сделать соединение, что-бы из блока вышел и отработал закрытие? Нет? :)

zJes ★★ ()

Не могу воспроизвести, python 2.7, простой echo сервер с accept лупом. После kill закрывает сокет.

baverman ★★★ ()

Предполагаю, что сервер убивается, когда есть активное клиентское соединение, тогда сокет остается в TIME_WAIT.

baverman ★★★ ()
Ответ на: комментарий от tailgunner

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

AIv ★★★★★ ()
Ответ на: комментарий от baverman

Да, python2.5.2 ;-( те мб местный баг?

RESUSEADDR дейстивтельно помогает, спасибо! Правда в socklist этих портов потом висит как собак, и я так и не понял баг такое повоеление или фича...

Режим blocking (ну все установки по умолчанию, я ниче не менял). listen(5)

AIv ★★★★★ ()
Ответ на: комментарий от AIv

> Не, клиент должен сдохнуть гарантированно

Совершенно очевидно, что у тебя на одном из концов не закрывается сокет.

RESUSEADDR дейстивтельно помогает, спасибо!

Ты хотя бы почитай, что он делает.

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

сервер server0.py

 
#!/usr/bin/python 
from socket import * 
s = socket(AF_INET,SOCK_STREAM) 
s.bind(('127.0.0.1',1234)) 
s.listen(5) 
while 1 : 
    conn, addr = s.accept() 
    data = conn.recv(1024) 
    conn.send(data+data) 
    conn.close() 

клиент client0.py

 
#!/usr/bin/python 
from socket import * 
import sys 
s = socket(AF_INET,SOCK_STREAM) 
s.connect(('127.0.0.1',1234)) 
s.send( ' '.join(sys.argv[1:]) ) 
print s.recv(2048) 

пускач

 
./server0.py & 
sleep 1 
./client0.py qwerty 
sleep 1 
killall server0.py 

Как он может не закрываться? На втором запуске - socket.error: (98, 'Address already in use')

AIv ★★★★★ ()
Ответ на: комментарий от AIv

fix:

#!/usr/bin/python 
from socket import * 
import struct

s = socket(AF_INET,SOCK_STREAM) 
s.setsockopt(SOL_SOCKET, SO_LINGER, struct.pack("ii",  1, 0))
s.bind(('127.0.0.1',1234)) 
s.listen(5) 
while 1 : 
    conn, addr = s.accept() 
    data = conn.recv(1024) 
    conn.send(data+data) 
    conn.close()
baverman ★★★ ()

Есть стандартный паттерн написания таких серверов. Псевда:

server_socket.soTimeout = //сколько нужно для достаточной респонсивности шатдавна

while(не сдохли и нам позволено дальше работать) 
  server_socket.accept
  .....
  catch timeout_error => продолжаем

чтобы потушить - выставляешь флаг что работать дальше не надо. accept вылетит по шатдавну и поскольку дальше работать нельзя - say goodnight.

Второй вариант - вешай сигнал который вызовет close сокету висячему на accept. Он должен улететь с ошибкой «меня закрыли какието поцы» и ты красиво завершаешь приложение.

r ★★★★★ ()
Ответ на: комментарий от AIv

> Как он может не закрываться?

А ты ничего не забыл? Например закрыть забинденый сокет. Отсюда и занятый порт.



r ★★★★★ ()
Ответ на: комментарий от r

Есть стандартный паттерн написания таких серверов. Псевда:

Правда есть ещё дополнение в виде SO_REUSABLEADDR или SO_LINGER, чтоб OS дала его заново слушать или побыренькому закрыть без ack. А этот паттерн только показывает как обрабатывать ошибки, graceful shutdown, но от TIME_WAIT никак не спасает.

baverman ★★★ ()
Ответ на: комментарий от r

СО тсороны клиента? Во первых я пробовал и закрывать - результат тот же. Во вторых он и так закрываеся по деструктору.

AIv ★★★★★ ()
Ответ на: комментарий от AIv

>СО тсороны клиента?

Со стороны сервера.

Брейвман правильно сказал про TIME_WAIT. Параметров наставь сокету.

r ★★★★★ ()
Ответ на: комментарий от baverman

Месье, Вы Маг и Волшебник, снимаю шляпу!;-)))

Не порекомендуете где про эти фокусы можно почитать?

AIv ★★★★★ ()
Ответ на: комментарий от baverman

>Он закрывается при сборке мусора.

Только когда это еще будет...

Вы вообще злые - дескрипторы оставлять на сборку мусора когда-нибудь.

r ★★★★★ ()
Ответ на: комментарий от r

В данном примере это будет сразу, поскольку клиент спросил-получил ответ и все...

AIv ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.