繁体   English   中英

在Linux上编写多线程TCP服务器

[英]Writing multithreaded TCP server on Linux

在工作中,我的任务是将TCP服务器作为Modbus从设备的一部分来实现。 我已经在堆栈交换和一般的互联网上做了很多阅读(包括优秀的http://beej.us/guide/bgnet/ ),但我正在努力解决设计问题。 总之,我的设备只能接受2个连接,并且在每个连接上都是传入的modbus请求,我必须在主控制器循环中处理这些请求,然后回复成功或失败状态。 我有如何实现这一点的以下想法。

  1. 有一个创建,绑定,侦听和接受连接的侦听器线程,然后生成一个新的pthread来监听连接以获取传入数据并在空闲超时期限后关闭连接。 如果活动线程的数量当前为2,则立即关闭新连接以确保仅允许2个。

  2. 不要从侦听器线程生成新线程,而是使用select()来检测传入的连接请求以及活动连接上的传入modbus连接(类似于Beejs指南中的方法)。

  3. 创建2个侦听器线程,每个线程创建一个套接字(相同的IP和端口号),可以阻止accept()调用,然后关闭套接字fd并处理连接。 在这里,我(或许天真)假设这将只允许最多2个连接,我可以使用阻塞读取来处理。

我一直在使用C ++,但我对Linux开发还不熟悉。 我真的很欢迎任何关于上述哪种方法最好的建议(如果有的话)以及我对Linux的经验不足意味着他们中的任何一个都是非常糟糕的想法。 我希望避免fork()并坚持使用pthreads,因为传入的modbus请求将被排队并定期从主控制器循环读取。 提前感谢任何建议。

第三种方法不起作用,你只能绑定到本地地址一次。

我可能会使用您的第二种替代方案,除非您需要进行大量处理,在这种情况下,第一种替代方案的组合可能会有用。

我想到的两个第一个替代方案的组合是让主线程(程序启动时总是有的)创建两个工作线程,然后进行阻塞accept调用以等待新连接。 当新连接到达时,告诉其中一个线程开始处理新连接并返回阻止accept 当第二个连接被接受时,您告诉另一个线程在该连接上工作。 如果两个连接都已打开,则在关闭一个连接之前不要接受,或等待新连接但立即关闭它们。

由于您只处理2个连接,因此每个连接的线程非常适合此类应用程序。 如果需要扩展到数千个连接,使用非阻塞或异步I / O的面向对象方法会更好。 2个监听线程有意义,你不需要关闭接受fd。 连接完成后再回来接受它。 事实上,一个变化是阻止三个线程做接受。 如果其中两个线程正在主动处理连接,则第三个线程将重置新创建的连接(或返回忙响应,适用于您的设备)。

要让所有三个线程都阻塞接受,您需要让主线程在三个线程启动之前创建并绑定套接字以进行接受/处理。

Linux上pthreads手册页表明accept是线程安全的。 (线程安全函数下的部分列出了非线程安全的函数,如图所示。)

你提出的所有设计选项都不是面向对象的,而且它们都更倾向于C而不是C ++。 如果你的工作允许你使用boost,那么Boost.Asio库非常适合制作简单(和复杂)的套接字服务器。 您可以接受几乎任何示例,并将其扩展为仅允许2个活动连接,一打开就关闭所有其他连接。

通过在连接类(构造函数中的inc,析构函数中的dec)中保留静态计数器,可以修改它们的简单HTTP服务器来执行此操作,并在创建新计数器时检查计数并确定是否关闭连接。 连接类也可以获得boost :: asio :: deadline_timer来跟踪超时。

这最类似于你的第一个设计选择,boost可以在1个线程中执行此操作,而在后台执行类似于select() (通常是epoll() )。 但这是“C ++方式”,在我看来,使用select()和原始pthread是C方式。

暂无
暂无

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

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