@MechanicZelenyy

Как правильно закрыть сокет в Python?

Пишу небольшое клиент-серверное приложение для личных нужд. Решил сделать закрытие сокета через менеджер контекста:
import socket

HOST = '127.0.0.1' 
PORT = 65432 

class ServerApp:
    def __init__(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.bind((HOST, PORT))
        self.socket.listen(1)


    def mainloop(self):
        # Какой-то код здесь
        pass

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.socket.shutdown(socket.SHUT_RDWR)
        self.socket.close()

if __name__ == '__main__':
    with ServerApp() as app:
        while True:
            app.mainloop()

Аналогично сделал на клиенте. Если программы завершаются штатно, то сокет нормально закрывается, однако если валится с ошибкой, то сокет остается занятым и освобождается только по таймауту. В чем дело? Я неправильно закрываю сокет или же неправильно использую with (нужно добавить обработку исключений?)?
  • Вопрос задан
  • 782 просмотра
Решения вопроса 1
@MechanicZelenyy Автор вопроса
Помог комментарий javedimka:
После `self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)` надо добавить:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)


Документация:

Running an example several times with too small delay between executions, could lead to this error:

OSError: [Errno 98] Address already in use

This is because the previous execution has left the socket in a TIME_WAIT state, and can’t be immediately reused.

There is a socket flag to set, in order to prevent this, socket.SO_REUSEADDR:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))

the SO_REUSEADDR flag tells the kernel to reuse a local socket in TIME_WAIT state, without waiting for its natural timeout to expire.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@belyaevcyrill
Пример с исключением

try:
    s.connect((TCP_IP, TCP_PORT))
    s.sendall(MESSAGE)
    data = s.recv(BUFFER_SIZE)
except socket.error:
    #код обработки ошибки
finally:
    s.close()
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы