#python #sockets #networking #udp
#python #сокеты #сеть #udp
Вопрос:
Предположим, у нас есть эхо-сервер и приложение для передачи файлов.
- Существует отправитель (
Client
) для отправки файлов и получатель (Server
) для получения файлов. Эхо-сервер будет отображать все, что получено отClient
иServer
. - Однако,
Client
иServer
не может обмениваться данными напрямую, т.Е. Все пакеты должны проходить через эхо-сервер. Например,Client
отправляет UDP-пакет на эхо-сервер, а эхо-сервер передает этот пакет наServer
эхо-сервер иServer
отправляет подтверждение на эхо-сервер, а эхо-сервер передает этот пакет подтверждения наClient
. - Цель состоит в том, чтобы реализовать надежный UDP для передачи файлов. И у нас есть только один сокет UDP.
На этом рисунке показано, что такое настройка клиента, сервера и эхо-сервера
Я пытался использовать многопоточность, select.select
и оба они работают не идеально
- Проблема с многопоточностью заключается в том, что, поскольку
Client
andServer
не может взаимодействовать внутри, и у нас есть только один сокет, трудно выбрать, кто должен отправлять или получать сейчас. - Проблема в
select.select
том, что возвращаемый список всегдаwriteable
непустой, из-за чего клиент продолжает отправлять кучу пакетов доreadable
готовности.
Вот реализация для обоих Client
и Server
внутри одного файла (скажем transceiver.py
), что я не использую select.select
(вместо этого используя send
переменную bool), но, похоже, работает нормально. Но я считаю, что это плохая практика, поэтому мне интересно, что я могу сделать, чтобы улучшить свой дизайн.
def create_transceiver(ip, port):
address = (ip, port)
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp.settimeout(1)
inout = [udp]
client = Client(udp, address)
server = Server(udp, address)
client_to_server = True
send = True
while True:
# infds, outfds, errfds = select.select(inout, inout, [])
if not send: # len(infds) != 0
if client_to_server:
server.start_recv()
client_to_server = False
else:
client.start_recv()
client_to_server = True
send = True
elif send: # len(outfds) != 0
if client_to_server:
if client.has_ack_all():
print(server.write_content())
break
client.start_send()
client_to_server = True
else:
server.start_send()
client_to_server = False
send = False
Вот реализация эхо-сервера:
import socket
ip = "10.10.1.100"
port = 8888
address = (ip, port)
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind(address)
while True:
data, address = udp_socket.recvfrom(2048)
udp_socket.sendto(data, address)
Ответ №1:
И у нас есть только один сокет UDP.
Насколько я понимаю эту цель, у вас где-то есть серверный процесс (вы называете его эхо-сервером), который прослушивает определенный порт. Также есть клиент, который хочет отправить данные на какой-то сервер.
Предоставленный вами код показывает реализацию так называемого конечного автомата, который (в вашем случае) переключается между получением и отправкой.
Однако клиент и сервер не могут взаимодействовать напрямую
Сценарий, который вы описываете, делает ваш эхо-сервер классическим сервером, который обрабатывает разные типы клиентов. В вашем случае это будет ваш «клиент» и ваш «сервер». Я хотел бы назвать их просто client-A и client-B. Я думаю, большинство руководств в Интернете назвали бы их Алисой и Бобом.
Цель состоит в том, чтобы реализовать надежный UDP для передачи файлов.
Итак, вы хотите передавать файлы между разными клиентами, используя UDP в качестве базового протокола. UDP не очень хорошо подходит для этой цели. Это не гарантирует доставку каждого переданного пакета. Возможно, что пакеты поступают в другом порядке, чем они были отправлены. Обычно вы используете TCP для такого рода передачи. UDP обычно используется для потоковой передачи данных в реальном времени, таких как аудио / видео звонки и тому подобное. Для получения дополнительной информации о различиях между UDP и TCP вы можете проверить страницы Википедии для каждого:
https://en.wikipedia.org/wiki/User_Datagram_Protocol
https://en.wikipedia.org/wiki/Transmission_Control_Protocol
Для ваших передач можно использовать UDP, но вам придется самостоятельно реализовать все меры безопасности, предоставляемые TCP.
Я предполагаю, что ваш клиент и ваш сервер на самом деле разные программы. В противном случае был бы способ, которым они могли бы общаться напрямую. Если это так, этот учебник может дать вам отправную точку: https://pythonprogramming.net/server-chatroom-sockets-tutorial-python-3 /
Комментарии:
1. Спасибо за ваш ответ! Ваше понимание действительно правильное. Я пытаюсь изучить TCP и думаю, что реализовать управление потоком TCP, контроль ошибок через UDP был бы полезен. В любом случае, считаете ли вы, что текущий конечный автомат является хорошим дизайном? Обычно я видел, как люди либо используют
select.select
, либо многопоточные, конечные машины кажутся немного наивными.2. Кроме того, клиент A и клиент B существуют в одном файле,
transceiver.py
. Проблема для меня заключается в том, что, поскольку клиент A и клиент B существуют в одном файле и совместно используют сокет с эхо-сервером, я тогда не знаю, как переключить сокет на правильный клиент.