如何确保客户端在 Python 中使用 UDP 套接字收到我的消息?

How can I ensure that a client received my message using UDP sockets in Python?

我正在 python 中使用 UDP 套接字编写学校练习,我需要在服务器和客户端之间交换一些信息(例如,整数、字符串等)。

我写了这个函数来确保客户端收到从服务器发送的消息,反之亦然:

import socket

BUFFER_SIZE = 1024

def send_udp_mgs(origin, destination, msg):
    msg = str(msg).encode('utf8')
    origin.sendto(msg, destination) # sending message
    # I never receive confirmation
    opt, _ = origin.recvfrom(BUFFER_SIZE) # Code stucks here
    opt = opt.decode('utf8')
    print(opt)

def receive_udp_msg(destination):
    msg, origin = destination.recvfrom(BUFFER_SIZE) # receiving message OK
    # This is the message sent as confirmation but is never received
    destination.sendto("CHECK".encode('utf8'), origin) # sent but not received
    msg = msg.decode()
    return msg

我希望代码能够在发送消息后与接收确认的函数一起正常工作,但它在等待确认时卡住了。客户端发送确认,但服务器从未收到它。除此之外,客户端接收消息很好,只是向服务器的确认返回失败。

这是服务器代码:

def client_thread (s, c):
    print("Connection petition from", c)
    global n_cons
    cport = PORT + n_cons
    send_udp_mgs(s, c, cport)
    return

# UDP socket acting as server
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((IP, PORT))
while True:
    data, addr = s.recvfrom(BUFFER_SIZE)
    if data.decode() == CONNECT:
        n_cons += 1
        try:
            Thread(target=client_thread, args=(s,), kwargs={'c':addr}).start()
        except:
            print("Error creating thread")
            break

客户代码

c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
c.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s = (IP, PORT)
# Connecting to the server
c.sendto(CONNECT.encode('utf8'), s)
cport = receive_udp_msg(c)

我无法让你的程序在你说的确切停止点停止,但我找到了一个我怀疑有类似原因的问题:

如果有多个客户端,等待一个客户端确认的线程可以收到下一个客户端的CONNECT消息,服务器的"main loop"可以收到确认消息。

您无法避免这个问题:除非您可以控制所有客户端发送数据的时间,否则您无法在使用 UDP 时为不同的客户端分离线程。我建议使用 select, selectors, or asyncio, or just asyncio's socket functions 在您的套接字上执行操作。

但还有其他问题需要考虑:您为什么要尝试确认 UDP 消息?如果您需要确保连接的另一端收到您发送的内容,为什么不使用 TCP 或其他具有确保内置传送机制的协议?

如果你真的需要使用UDP,你需要至少制作一个数据结构来跟踪试图"connect,"和关于它们的其他信息 "connections." 但是 UDP 是明确无连接的。


作为不相关的评论,client_thread 中的 cport 是否暗示您计划为每个客户端按顺序 创建一个新端口?如果是这样,请考虑 (a) 您只能打开这么多端口,(b) 许多其他进程正在使用其中一个端口,(c) 除非 n_cons 永远不会关闭,否则此进程 会使用这些端口吗,以及 (d) 你需要那么多端口做什么? (另见 this answer。)