c++ - 在多线程 UDP 服务器中使用多个套接字

标签 c++ multithreading sockets

Requirement: 

我需要编写一个服务器,它应该能够接收多个客户端连接(FCFS顺序),并且能够在单独的线程中处理每个客户端,以便处理看起来就像所有客户端同时服务一样。使用的传输协议(protocol)应该是 UDP。此外,客户端和服务器之间会发生多次数据传输,并且从客户端接收到的数据必须存储在服务器端,以供该客户端进一步处理。

Implementation:

为了实现这一点,我采用了队列/线程池机制。最初,我创建了一个固定数量的线程池,并有一个队列数据结构来存储客户端地址。该队列在所有线程之间共享,因此我使用“互斥体”来锁定/解锁该队列。在主服务器线程中,我创建一个套接字,将其绑定(bind)到全局端口/地址,然后在“recvfrom”调用上阻止服务器。任何想要与服务器通信的客户端都会向监听全局端口地址的主线程服务器发送“Hi”消息。主服务器线程在收到此“Hi”数据报后,将客户端的 sockaddr 结构推送到队列中,并返回到阻塞“recvfrom”调用以接受其他客户端。

任何获得队列锁定、弹出客户端地址并开始自行处理该客户端的池线程。也就是说,池线程现在将创建一个套接字,将其绑定(bind)到与全局端口不同的端口,并使用它弹出的客户端地址将此端口地址发送到客户端。在客户端,发送“Hi”消息后,它会阻止“recvfrom”调用,一旦从服务器(具有不同端口)接收到消息,它就会存储此端口/地址,从那时起,它就与服务器仅使用池服务器线程发送的这个新端口。

Clarification needed:

我在许多堆栈溢出问题中注意到,在多线程UDP服务器中,单个套接字总是足够的,但根据我的要求,我认为我需要多个UDP套接字,每个套接字都满足一个客户端的需求。请根据我的要求提供有关线程 UDP 服务器方法的建议

编辑:改进设计

感谢您对我的设计的所有评论和讨论。在掌握了大家对单套接字连接和上下文切换的所有看法之后,我想到了一个改进的设计。请对我的改进设计提供反馈

在此实现中,我将仅使用一个绑定(bind)到全局已知端口地址的全局 UDP 套接字。就像以前一样,我最初将创建固定数量的线程,比如 5 个线程。然后我在所有线程中的单个套接字上执行recvfrom()。无论哪个线程首先接收到数据报,都能够从该数据报中得知三件事:

  • 客户端sockaddr(客户端地址)
  • 客户端数据(实际发送的数据)
  • 进程号(与数据一起发送。这是为了让服务器知道要对客户端数据进行什么样的处理)

根据上述信息,服务器线程将根据进程号处理数据,并将回复发送给收到的同一客户端。处理数据并发送回复(如果需要)后,该线程将返回到阻塞在 recvfrom() 调用上。

此外,有关各种客户端的详细信息将存储在全局哈希表和映射中(所有线程都可以访问),以便任何线程都可以访问它并根据该特定客户端进行处理。

客户端的更改:服务器应该能够知道它必须对客户端数据进行哪些处理。因此,客户端将随数据一起发送进程号。

最佳答案

一旦套接字就足够了,因为每次接收数据包时,您都可以通过使用其源地址(src_addr)调用recvfrom来识别客户端:

recvfrom(int sockfd, void *buf, size_t len, int flags,
             struct sockaddr *src_addr, socklen_t *addrlen);

现在,该解决方案只有一个接收点。这意味着服务器必须接收数据,然后将其传递给应该执行该过程的线程。由于您仅使用一个端口,因此这会降低单套接字解决方案的并行性。

<删除> 在我看来,您的解决方案在并行性方面更好,因为您的线程在不同的端口上运行,因此它们可以并行地为多个客户端提供服务,特别是如果您的计算机有多个处理器和多个可用于处理客户端的网卡。在最好的情况下,您可能有多个线程在不同的处理器中并行运行,每个线程为来自不同网络接口(interface)的客户端提供服务。

编辑:

在与 David 讨论您的设计后,他让我相信拥有多个套接字会导致多次上下文切换,这可能会降低服务器性能。因此,在这种情况下最好的方法是对所有客户端使用多个线程,但使用单个套接字。

关于c++ - 在多线程 UDP 服务器中使用多个套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32780267/

相关文章:

c++ - 如何确定状态模式的状态

c++ - std::ios::openmode 的组合在文件存在时截断但阻止创建新文件?

C++ 将新类对象添加到数组中的新位置

c++ - 错误编译opencv示例

java - 从一个线程多次调用同步方法

python - 处理以换行符结尾的套接字数据

c++ - 整数列表与 C++ 中给定整数的有效比较

C中创建多线程

c# - C# 中的条件线程锁

java - 通过socket连接tomcat