繁体   English   中英

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

[英]Use of multiple sockets in Multithreaded UDP server

Requirement: 

我需要编写一个服务器,该服务器应该能够接收多个客户端连接(FCFS顺序),并且能够在单独的线程中处理每个客户端,以便处理过程看起来好像所有客户端都可以同时服务。 使用的传输协议应为UDP。 在客户端和服务器之间还会发生几次数据传输往返,并且必须将从客户端接收的数据存储在服务器端,以便对该客户端进行进一步处理。

Implementation:

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

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

Clarification needed:

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

编辑:改进了设计

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

在此实现中,我将仅使用绑定到全局已知端口地址的一个全局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);

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

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

编辑

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

好吧,我不确定这些需求来自何处-主要是现实生活程序或某种任务/面试/等等的需求。

我会继续以为这是一个现实生活中的程序,因为我不会帮助任何人做作业:)

UDP不是面向连接的协议(即使UDP套接字可以“连接”,但这只会增加混乱)。 这是一个面向消息的协议。 现在,设计线程模型的第一个问题始终是“我这里需要线程模型吗?” 如果您具有可以彼此独立执行的操作并且花费大量时间,则将需要线程。 就您而言,这取决于您对消息的实际处理方式。 假设您已经对其进行了一些处理,并且与潜在同时发生的客户端数目相比,该处理时间是很重要的(请记住,有成功的单线程Web服务器!仅通过单线程处理所有请求就没有错)。

在设计方面,我认为给客户端提供新端口以进行连接的想法不是一个好主意。 造成这种情况的原因有很多,其中一个可能是客户端和服务器之间的防火墙。 在实现方面,它也不是简单明了的,并且以某种方式模仿了TCP和UDP。 如果需要TCP,请使用TCP,请勿尝试通过UDP构建TCP-您不会成功。

相反,我建议在套接字上有一个侦听器,该侦听器会将请求(连同发送者信息)分派给工作线程,然后将答复发送回客户端。 请记住,对于UDP,您不需要通过用于处理请求的同一套接字发送响应。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM