推送服务器的 select() 问题

问题描述 投票:0回答:1

我正在用 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_ 中。 这样,当线程想要以推送方式发送数据时,它会在该管道上写入一些内容,从而中断
select()
并将控制权返回给选择器,然后选择器可以预先安排将数据发送到客户端,而不会造成大量时间损失。 不幸的是,我认为这个解决方案无法在 Windows 上实现,因为该系统上的
select()
函数仅适用于实际上是套接字的 fd。

所以问题是:是否有一些众所周知的解决方案可以用来解决这种情况(Linux 和 Windows)?

c windows unix posix-select
1个回答
1
投票

您可以创建一个自连接的 UDP 套接字,这在 Windows 和 Linux 上同样有效。

基本上,您创建一个 UDP 套接字,

bind()
将其连接到
INADDR_LOOPBACK
和端口 0,然后
connect()
将其连接到自身(地址取自
getsockname()
)。

此时,您可以向自己发送一条单字节消息(或更具体的消息)来唤醒自己。

© www.soinside.com 2019 - 2024. All rights reserved.