Вопрос или проблема
Я написал простой сокет-сервер на Python 3.11.2 на Bookworm. Очень простой на данный момент.
root@9b6f7:~# python3 w1.py
Сокет успешно создан
Traceback (most recent call last):
Файл "/root/w1.py", строка 7, в <module>
s.bind(('', port))
OSError: [Errno 98] Адрес уже используется
Во время тестирования и написания скрипта я продолжаю получать ошибку “Адрес уже используется” при запуске скрипта, и, изучая информацию об этой ошибке на сокетах, я увидел, что мне нужно добавить SO_REUSEADDR.
Я добавил s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) в свой скрипт, но все равно продолжаю получать ошибку “Адрес уже используется”, особенно если скрипт падает.
Вот мой простой скрипт, создающий ошибку при запуске. Может ли кто-нибудь помочь, где я мог ошибиться.
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print ("Сокет успешно создан")
port = 1712
s.bind(('', port))
print ("сокет привязан к %s" %(port))
# перевести сокет в режим прослушивания
s.listen(5)
print ("сокет прослушивается")
# вечный цикл до прерывания или возникновения ошибки
while True:
# Установить соединение с клиентом.
c, addr = s.accept()
print ('Получено соединение от', addr )
while True:
data = c.recv(1024)
if not data:
break
c.send('Спасибо за подключение'.encode())
c.close()
Спасибо
.
Ответ или решение
Конечно, давайте подробно разберем вашу проблему с сокет-сервером на Python, работающим на Debian (версия Bookworm) и использование опции SO_REUSEADDR
.
Проблема:
Вы создали простой TCP-сервер, но сталкиваетесь с ошибкой OSError: [Errno 98] Address already in use
при попытке забиндить порт, даже после добавления опции SO_REUSEADDR
.
Анализ:
Ошибка "Address already in use" указывает на то, что сокет, пытающийся привязать порт, сталкивается с конфликтом: порт уже занят другим процессом или недавним завершением предыдущего сокет-соединения. Опция SO_REUSEADDR
предназначена для того, чтобы сокет мог использовать локальный адрес, который может быть занят в результате активации предыдущей программы, но она не стимулирует немедленное освобождение портов, которые используются активно.
Потенциальные причины и решения:
-
Процессы, использующие порт:
- Проверьте, если другие процессы используют этот порт. Используйте команду
lsof -i :1712
илиnetstat -tuln | grep 1712
для проверки, занят ли порт другим процессом. Если занят, уберите этот процесс.
- Проверьте, если другие процессы используют этот порт. Используйте команду
-
Исходящий таймаут:
- Даже с
SO_REUSEADDR
, пока полностью не истечет время ожидания завершения предыдущего соединения (TIME_WAIT), может появляться эта ошибка. Вы можете использовать командуss -s
для просмотра состояния сокетов и выявления долгоживущих соединений в состоянии TIME_WAIT.
- Даже с
-
Изменение версии Python или конфигурации:
- Перепроверьте вашу версию Python. Иногда возможно, что дело в особенностях версии интерпретатора. Также убедитесь в корректности вашей системы конфигурации.
-
Правильное закрытие сокетов:
- Убедитесь, что сокеты корректно закрываются методом
close()
после их использования. Это предотвратит зависание открытых соединений и снижает вероятность появления TIME_WAIT.
- Убедитесь, что сокеты корректно закрываются методом
-
Обработка исключений:
- Добавьте обработку исключений, чтобы ваш сервер корректно обрабатывал ошибки во время выполнения. Это улучшит стабильность работы серверного скрипта.
Пример улучшенного кода:
import socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print("Socket создан успешно")
port = 1712
s.bind(('', port))
print(f"Сокет привязан к порту {port}")
s.listen(5)
print("Сокет находится в режиме прослушивания")
while True:
client_socket, addr = s.accept()
print(f'Получено соединение от {addr}')
try:
while True:
data = client_socket.recv(1024)
if not data:
break
client_socket.sendall('Спасибо за подключение'.encode())
finally:
client_socket.close()
except Exception as e:
print(f"Произошла ошибка: {e}")
finally:
s.close()
Заключение:
Использование правильных инструментов диагностики и улучшение управления соединениями вашего сервера помогут устранить проблему с занятыми адресами. Соблюдайте осторожность при управлении сетевыми ресурсами, и это внесет значительный вклад в надежность вашей системы.