【问题标题】:UDP and socket on responce to client响应客户端的 UDP 和套接字
【发布时间】:2018-05-23 12:46:40
【问题描述】:

我启动并运行了 UDP 通信。 在一个简单的条带化版本中,客户端基本上是这样做的:(是的,代码中有很多 if 和错误检查,不,没有很多定义,它不会按原样工作。但我更多的是概念这里比实际代码)

sock = socket(AF_INET, SOCK_DGRAM, 0);
server_length = sizeof(struct sockaddr_in);
sendto(sock, "Hi", 3, 0, (struct sockaddr *)&myaddr, server_length);
numRes = recvfrom(sock, (char *)buff, (int)sizeof(buff), 0, (struct sockaddr *)&myaddr, &server_length);

和服务器基本一样:

sock=socket(AF_INET, SOCK_DGRAM, 0);
bind(sock,(struct sockaddr *)&server,length);
resBytes=recvfrom(sock,buff,(int)sizeof(buff),0,(struct sockaddr *)&from, &fromlen);
sendto(sock, "Test",5, 0, (struct sockaddr *)&from, fromlen);

这行得通。两端接收对方发送的数据。

这是我的问题:服务器应该同时处理大量请求。我为消息创建了一个队列,以便另一个线程可以处理它们,然后在另一个线程中将它们发送回客户端。当我这样做时,我为发送创建了一个新套接字,使用了与消息相同的“发件人”地址,但客户端从未收到它。

理解必须使用同一个套接字来回复 UDP 消息是否正确?

如果我使用相同的套接字进行发送和接收,如果我有三个客户端发送消息会发生什么,然后在处理完这些消息后,我会以随机顺序回答它们。这行得通吗?

我可以在客户端上创建一个“服务器”,但我猜任何 NAT 都会很快扼杀这个想法。

我尝试尝试的或多或少是这样的:

sock=socket(AF_INET, SOCK_DGRAM, 0);
sock2=socket(AF_INET, SOCK_DGRAM, 0);

bind(sock,(struct sockaddr *)&server,length);
resBytes=recvfrom(sock,buff,(int)sizeof(buff),0,(struct sockaddr *)&from, &fromlen);

sendto(sock2, "Test",5, 0, (struct sockaddr *)&from, fromlen);

如果这种代码应该可以工作,我会回去调试,但现在似乎不是这样。

编辑: 有人添加了“多线程”作为标签。忘记多线程的事情它更多地解释了为什么我不及时响应相同的请求。如果需要的话,我可以在一个线程中进行所有通信。对不起,如果这让人们感到困惑,但我的主要问题是:a)我可以在不定义客户端上的“服务器”的情况下向另一个 socked 发送响应。 b) 如果不是,它将如何处理同一个 socked 上的随机回复顺序(IE 客户端 A 发送,客户端 B 发送,回复客户端 B,然后回复客户端 A)

【问题讨论】:

  • 套接字不能被多个线程共享。但是因此UDP是一个无连接协议,你可以使用不同的套接字来接收和发送。
  • @user0042:“套接字不能被多个线程共享。”当然可以。这只是访问如何同步的问题。
  • @alk 好吧,同步有点违背了使用单独线程的目的,不是吗?
  • 好吧,忽略线程问题。如果需要,我可以将发送者和接收者放在同一个循环中。这里的主要问题是:a)可以在另一个袜子上发送响应。 b) 如果我以随机顺序响应多个请求怎么办。

标签: multithreading sockets networking udp


【解决方案1】:

只要套接字没有连接,单个 UDP 套接字就可以从多个源接收数据并将数据发送到多个对等点。这意味着如果您显式或隐式绑定套接字,然后使用sendtorecvfrom(或recv),那么您可以使用同一个套接字从多个对等方发送和接收数据。但是,如果您首先connect 套接字,那么您将只能从绑定到连接的 ip:port 的套接字接收数据,即通常与接收数据的套接字相同。

要对此进行测试,您可以使用简单的 Python 服务器(与 C 相同)。此服务器创建两个套接字:sock1sock2。它将在sock1 上接收一条消息,然后使用第一个sock2(未收到原始消息的那个)和sock1(收到原始消息的那个)发回一条消息:

from socket import *

sock1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
sock2 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)

sock1.bind(('127.0.0.1',9999))
data,addr = sock1.recvfrom(1024)
print("got '{}' from {}".format(data,addr))

sock2.sendto(b"send from sock2", addr)
sock1.sendto(b"send from sock1", addr)

作为对等点,我们有一个客户端,它根据配置使用连接的套接字(即connect + send)或未连接的套接字(即没有connectsendto):

from socket import *

connected=False
sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)
if connected:
    sock.connect(('127.0.0.1',9999))
    sock.send('send from connected client')
else:
    sock.sendto('send from unconnected client',('127.0.0.1',9999))
while True:
    data,addr = sock.recvfrom(1024)
    print("got '{}' from {}".format(data,addr))

如果您使用连接的套接字 (connected=True) 运行客户端,您会看到它只会从 sock1 获取消息,因为 sock1 已(显式)绑定到客户端的 ip:port连接到并且sock2 (隐式)绑定到其他地址:

got 'send from sock1' from ('127.0.0.1', 9999)

如果客户端使用的是未连接的套接字 (connected=False),那么它将同时接收来自 sock1sock2 的消息:

got 'send from sock2' from ('127.0.0.1', 44596)
got 'send from sock1' from ('127.0.0.1', 9999)

【讨论】:

  • 非常感谢。这是在回答我的问题。据我所见,我从两个套接字发回“未连接”。那么我的代码一定有问题。
  • @AslakBerby: 如果你有一个设备在客户端和服务器之间进行 NAT,那么它通常会从连接的两边创建一个由 ip,port 组成的 state 并让只有与此状态匹配的数据包从服务器传递。在这个具体的例子中:从 sock1 发送的数据包将通过 NAT 设备,而从 sock2 发送的数据包将被丢弃,因为没有匹配状态。状态防火墙也是如此,即使它们不进行 NAT。
  • 我开始意识到这一点。由于当今大多数家庭在它们和互联网之间都有某种 NAT,我必须确保它可以与 NAT 一起使用,然后选择连接版本。我将所有 UDP 代码移到同一个类中,并且只使用一个套接字。我只需要做一些测试,看看我可以连接多个客户端。
猜你喜欢
  • 1970-01-01
  • 2011-03-16
  • 2018-02-04
  • 2013-10-23
  • 2011-08-15
  • 2012-01-06
  • 1970-01-01
  • 2018-09-08
  • 2014-10-28
相关资源
最近更新 更多