Python socket не закрывает соединение должным образом - PullRequest
9 голосов
/ 18 февраля 2011

Я новичок в программировании сокетов и столкнулся с загадочной проблемой:

У меня есть программа для Windows, которую я не могу изменить (проприетарное программное обеспечение), но которая пытается подключиться к определенному ip и порту с помощью сокета tcp.

На своем Linux-ящике я написал небольшой скрипт на python, чтобы подать сокет в прогу win. Это работает нормально, пока я не убью свою прогу на Linux. Исходный серверный сокет не закрывается, как указано, и я не могу перезапустить свою программу, пока сокет не будет собран мусором.

Если я попробую то же самое с сокетом Linux (в отдельном скрипте Python), у меня нет проблем.

Вот минимальный пример кода:

import socket

server = socket.socket()
server.bind(('192.168.0.111', 50001))
server.listen(1)
conn, addr = server.accept()
print 'Connection established'

running = True
while running:
    try:
        data = conn.recv(4096)
    except KeyboardInterrupt:
        conn.close()
        running = False
    else:
        if data:
            print data
        else:
            conn.close()
            running = False
server.close()

Если я убью это с помощью Ctrl-C, он выйдет нормально. Но после перезапуска скрипта я получаю сокет socket.error, сообщающий, что адрес уже используется. Примерно через минуту программа снова заработает.

Я также пытался завершить работу до закрытия (aka conn.shutdown (2) и server.shutdown ...), но это не имеет никакого эффекта.

Есть ли лучший «правильный» способ закрыть оконную розетку? Я пропускаю что-то фундаментальное в сокетах вообще?

Спасибо!

edit: я думаю, что только что увидел ответ здесь: Как правильно закрыть сокет в Python 2.6?

Хотя я использую Python 2.5, он все еще может работать.

Ответы [ 2 ]

30 голосов
/ 18 февраля 2011

Вы испытываете состояние TIME_WAIT подключенных розеток.Несмотря на то, что вы закрыли розетку, она по-прежнему имеет длительные последствия в течение пары минут.Причины этого, а также флаг сокета, который можно установить, чтобы отключить поведение (SO_REUSEADDR), объясняются в FAQ по сокету UNIX *1003*.

Короче говоря,

server = socket.socket()
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(...)
...
2 голосов
/ 18 февраля 2011

Попробуйте добавить импорт sys и завершить работу приложения с помощью sys.exit ().Сокет остается зарезервированным до тех пор, пока система не убедится, что приложение закрыто.Вы можете быть откровенны в этом с sys.exit ()

[править] О, хорошо.Я довольно новичок в розетках сам.То есть вы говорите, что эта последовательность не безопасна?Я не могу представить какой-либо другой способ сделать это.Вы должны закрыть свое приложение в какой-то момент, с какой-то техникой, верно?Как это правильно сделать тогда?

server.shutdown(socket.SHUT_RDWR) 
server.close()
sys.exit()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...