关于多线程UDP Client-Server架构的问题

Questions about multithread UDP Client-Server architecture

我正在练习一些套接字和 UDP 客户端-服务器体系结构,参考网上的一些示例,我使用 C 实现了一个非常简单的 UDP 服务器,使用 C++ 实现了一个 UDP 客户端 class .
简而言之,当前的实现让服务器侦听传入的消息并将相同的数据包传回客户端。
如果客户端发出顺序请求,它似乎工作正常。
这是一个简短的解释性示例:

#include "UDPClient.h"
int main(int argc, char* argv[]) {
  UDPClient testClient;
  testClient.initSockets(1501, "127.0.0.1", 1500);
  for (int i = 0; i < 10; i++) {
    testClient.notifyEntry();
    testClient.notifyExit();
  }
  return 0;
}

由于客户端实际上应该同时与服务器共享更多信息,因此我测试了启动新线程的相同代码块:

#include <thread>
#include "UDPClient.h"
int main(int argc, char* argv[]) {
  UDPClient testClient;
  std::thread thrdOne, thrdTwo;
  testClient.initSockets(1501, "127.0.0.1", 1500);
  for (int i = 0; i < 10; i++) {
    thrdOne = std::thread(UDPClient::notifyEntry, std::ref(testClient));
    thrdTwo = std::thread(UDPClient::notifyExit, std::ref(testClient));
  }
  return 0;
}

如您所见,notifyEntrynotifyExit 已创建 static,目前需要引用 class 实例才能正常工作。 此外,在它们的函数体内,我还添加了一个小代码块,以检查由于服务器发回相同的内容,发送的消息是否等于接收的消息。
这是一个解释性的例子:

void UDPClient::notifyEntry(UDPClient& inst) {
  char buffer = "E"
  inst.sendPacket(buffer);  // sendto...
  inst.receivePacket(buffer);  // recvfrom...
  if (!(buffer == 'E') ){
    std::string e = "Buffer should be E but it is ";
    e.append(buffer);
    throw UDPClientException(e);
  }
}

使用多线程经常会发生上述检查抛出异常,因为缓冲区实际上包含另一个charnotifyExit发送的那个)

考虑到这些信息,请问您:

  1. 发生这种情况是因为线程的 recvfrom 也可以捕获来自另一个线程的请求的响应,而套接字实例化只是一个绑定套接字?
  2. 如果是,我是否应该实例化多个套接字(例如,每个套接字仅可用于一种类型的消息,即一个用于 notifyEntry,一个用于 notifyExit)?服务器上的多线程响应只是不能解决提到的问题吗?

this happens because the recvfrom of a thread can catch also the response of a request from another one, being the socket instantiated only a single bound socket?

这很有可能——如果您有多个线程在同一个 UDP 套接字上调用 recvfrom(),那么它将是 indeterminate/unpredictable 哪个线程接收哪个传入的 UDP 数据包。

if yes, should I instantiate more than a single socket (for instance, each one usable for only a single type of messages, that is one for notifyEntry and one for notifyExit)?

是的,我建议让每个线程创建自己的私有 UDP 套接字并将其套接字绑定()到它自己的单独端口(例如,将 0 作为端口号传递给 bind());这样每个线程都可以确保只接收自己的响应,而不会被其他线程的响应所混淆。 (请注意,您还需要对服务器进行编码,以将其回复发送回 recvfrom() 调用报告的 IP 地址和端口,而不是将回复数据包发送回硬编码的端口号)

Does multithreading on server for response only not solve the issue mentioned anyway?

不,UDP 数据包的正确处理(或不正确处理)是一个单独的问题,与服务器是单线程还是多线程无关。