如何在所有线程上同时接收UDP消息

huangapple go评论51阅读模式
英文:

How to receive UDP message concurrently over all threads

问题

在处理一个包含多线程和UDP的大型项目时,我注意到消息的顺序有些混乱。最初的计划是每条消息都有一个标头,所有线程同时接收它,现在哪个线程忽略它,哪个线程接受它取决于标头。所以我写了以下简单的代码来检查:

client.py

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

inpt = input("Enter input: ")

s.sendto(inpt.encode(), ("127.0.0.1", 50005))

server.py

import socket, threading

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

s.bind(("127.0.0.1", 50005))

def thrd1():
    msg = s.recv(1024).decode()
    print(f"thread 1: {msg}")

def thrd2():
    msg = s.recv(1024).decode()
    print(f"thread 2: {msg}")

t1 = threading.Thread(target=thrd1)
t2 = threading.Thread(target=thrd2)

t1.start()
t2.start()

预期结果是,当我写一条消息时,线程1和线程2同时输出,然而当发送一条消息时,只有线程1输出,线程2等待第二条消息。

这段代码中是否有任何可以更改以使其按预期工作的地方?

英文:

When working on a bigger project that included multithreading and UDP I noticed that the messages were all over the place. The initial plan was that every message has a header and all the threads receive it at the same time, now which thread ignores it and which one accepts depends on the header. So i wrote the following simple code just to check

client.py

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

inpt = input("Enter input: ")

s.sendto(inpt.encode(), ("127.0.0.1", 50005))

server.py

import socket, threading

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

s.bind(("127.0.0.1", 50005))

def thrd1():
    msg = s.recv(1024).decode()
    print(f"thread 1: {msg}")

def thrd2():
    msg = s.recv(1024).decode()
    print(f"thread 2: {msg}")

t1 = threading.Thread(target=thrd1)
t2 = threading.Thread(target=thrd2)

t1.start()
t2.start()

The expected result was that when i write a message both thread 1 and thread 2 give an output at the same time, however when sending a message only thread 1 gave an output and thread 2 waited for a second message.

Is there anything i can change in this code to make it work as intended?

答案1

得分: 1

以下是翻译好的部分:

最简单的方式来实现您想要的行为是为每个接收线程提供其自己的UDP套接字,并发送广播(或多播)UDP数据包,而不是单播。像这样:

// server.py
import socket, threading

def createReceivingSocket():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
    s.bind(("", 50005))
    return s

def thrd1():
    s = createReceivingSocket()
    while True:
       msg = s.recv(1024).decode()
       print(f"thread 1: {msg}")

def thrd2():
    s = createReceivingSocket()
    while True:
       msg = s.recv(1024).decode()
       print(f"thread 2: {msg}")

t1 = threading.Thread(target=thrd1)
t2 = threading.Thread(target=thrd2)
t1.start()
t2.start()
t1.join()
t2.join()

以下是已更新的客户端代码:

// client.py
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_IP, socket.IP_TTL, 0) # 保持数据包不进入局域网
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

inpt = input("输入内容: ")
s.sendto(inpt.encode(), ("<broadcast>", 50005))
英文:

The easiest way to get the behavior you want is to provide each receiving thread with its own UDP socket, and send broadcast (or multicast) UDP packets instead of unicast. Like this:

// server.py
import socket, threading

def createReceivingSocket():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
    s.bind((&quot;&quot;, 50005))
    return s

def thrd1():
    s = createReceivingSocket()
    while True:
       msg = s.recv(1024).decode()
       print(f&quot;thread 1: {msg}&quot;)

def thrd2():
    s = createReceivingSocket()
    while True:
       msg = s.recv(1024).decode()
       print(f&quot;thread 2: {msg}&quot;)

t1 = threading.Thread(target=thrd1)
t2 = threading.Thread(target=thrd2)
t1.start()
t2.start()
t1.join()
t2.join()

and here is the updated client code:

// client.py
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_IP, socket.IP_TTL, 0) # to keep the packets off the LAN
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

inpt = input(&quot;Enter input: &quot;)
s.sendto(inpt.encode(), (&quot;&lt;broadcast&gt;&quot;, 50005))

huangapple
  • 本文由 发表于 2023年4月20日 08:31:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76059735.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定