【发布时间】:2014-08-06 02:33:06
【问题描述】:
我正在用 C++ 为 Windows 和 Unix 系统编写服务器。
此服务器的一个关键特性是它必须能够随时接收和发送网络数据包。 具体来说,服务器必须能够向客户端发送数据,不仅要响应他们的消息,还要能够在推送中异步向他们发送数据包。
我在实施在上述场景中使用select() 函数的解决方案时遇到了困难。
我目前实施的解决方案根本无法说服我,我认为它可以用更好的模式/解决方案来实施。
我目前有一个专用线程(选择器),它通过侦听读取服务器套接字(接受新连接)和连接到服务器的套接字的事件来执行选择。
这是主 select() 循环:
if((sel_res_ = select(nfds_+1, &read_FDs_, NULL, &excep_FDs_, &sel_timeout)) > 0){
if(FD_ISSET(serv_socket, &read_FDs_)){
//we have to handle a newly connection.
...
if(sel_res_ > 1){
//in addition to the newly connection, there is also some other message incoming on client sockets.
...
}
}else{
//we have to handle incoming messages on client sockets
...
}
}
此解决方案适用于接收数据并以同步形式响应客户端请求。 但是,服务器还必须能够发送异步数据,并在必要时发送推送数据包。
为此,我目前使用单独的线程直接在客户端套接字上执行send()。
这个方案说服不了我,我想把数据包的接收和发送集中在选择器线程上。
主要困难在于select() 本质上是阻塞的,在客户端不发送任何数据包或触发超时之前我无法控制。
将超时设置得很低的解决方案并不能说服我;我认为这是一个简单的解决方案,实际上是在进行主动等待,而且不仅是在最坏的情况下,我会在发送推送数据包之前付出超时的代价。
我想到了一个更“优雅”的解决方案;我认为,会很好用,但只适用于 Unix/Linux 平台。
我想使用匿名管道并将匿名管道读取描述符插入select() read_FDs_。
这样,当一个线程想要在 push 中发送数据时,它会在此管道上写入一些内容,中断select() 并将控制权返回给选择器,然后选择器可以倾向于将数据发送到客户端,而不会浪费大量时间.
不幸的是,我认为该解决方案无法在 Windows 上实现,因为该系统上的 select() 函数仅适用于实际上是套接字的 fd。
所以问题是:是否有一些众所周知的解决方案可用于解决这种情况(Linux 和 Windows)?
【问题讨论】:
-
使用两个线程,一个读一个写。