如何设置非阻塞模式下从服务器的客户端接收消息的超时时间? [英] How to set time out for receiving message fromt client of server with non-blocking mode?

查看:34
本文介绍了如何设置非阻塞模式下从服务器的客户端接收消息的超时时间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具有2个连接的 server 服务器 SOCKET ,该服务器与 clients 连接,并且我设置此 server 为非阻塞模式,在发送或接收消息时不会停止.我想为每个连接的 SOCKET 设置超时,但是如果我使用以下代码:

I have a server with 2 connections SOCKET which is connected with clients and I set this server is non-blocking mode which don't stop when sending or recieving message. I want to set time out for a SOCKET of each connections, but if I use the following code:

 void getMessage(SOCKET connectedSocket, int time){ 
    string error = R_ERROR;
    // Using select in winsock
    fd_set  set;
    timeval tm;

    FD_ZERO(&set);
    FD_SET(connectedSocket, &set);

    tm.tv_sec = time; // time 
    tm.tv_usec = 0; // 0 millis
    switch (select(connectedSocket, &set, 0, 0, &tm))
    {
    case 0:
        // timeout
        this->disconnect();
        break;
    case 1:
        // Can recieve some data here
        return this->recvMessage();
        break;
    default:
        // error - handle appropriately.
        break;
    }
return error;
}

我的服务器不再是无阻塞模式!我必须等到第一个连接的超时结束才能从第二个连接获取消息!那不是我所期望的!那么,有没有办法为非阻塞模式设置超时时间?还是我必须自己处理?

My server is not none-blocking mode any more! I have to wait until the end of 1st connection's time out to get message from the 2nd connection! That's not what I expect! So, is there any way to set time out for non-blocking mode? Or I have to handle it myself?

推荐答案

select 是一种多路分解机制.当您使用它来确定单个套接字上的数据何时准备就绪或超时时,它实际上是为在许多套接字上返回数据就绪状态而设计的(因此 fd_set ).从概念上讲,它与 poll epoll kqueue 相同.这些机制与非阻塞I/O相结合,为应用程序编写者提供了实现单线程并发服务器的工具.

select is a demultiplexing mechanism. While you are using it to determine when data is ready on a single socket or timeout, it was actually designed to return data ready status on many sockets (hence the fd_set). Conceptually, it is the same with poll, epoll and kqueue. Combined with non-blocking I/O, these mechanisms provide an application writer with the tools to implement a single threaded concurrent server.

我认为,您的应用程序不需要这种功能.您的应用程序将仅处理两个连接,并且每个连接已使用一个线程.我相信让套接字处于阻塞I/O模式更为合适.

In my opinion, your application does not need that kind of power. Your application will only be handling two connections, and you are already using one thread per connection. I believe leaving the socket in blocking I/O mode is more appropriate.

如果您坚持使用非阻塞模式,我的建议是将 select 调用替换为其他内容.由于您要从 select 中获得的信息是单个套接字的就绪状态或超时的指示,因此可以通过将 recv 传递给适当的参数和适当的超时,来实现类似的效果.设置在插座上.

If you insist on non-blocking mode, my suggestion is to replace the select call with something else. Since what you want from select is an indication of read readiness or timeout for a single socket, you can achieve a similar effect with recv passed with appropriate parameters and with the appropriate timeout set on the socket.

tm.tv_sec = time;
tm.tv_usec = 0;
setsockopt(connectedSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tm, sizeof(tm));
char c;
swtich (recv(connectedSocket, &c, 1, MSG_PEEK|MSG_WAITALL)) {
case -1:
    if (errno == EAGAIN) {
        // handle timeout ...
    } else {
        // handle other error ...
    }
    break;
case 0: // FALLTHROUGH
default:
    // handle read ready ...
    break;
}

来自 man recv :

MSG_PEEK-此标志使接收操作从接收队列的开头返回数据,而不会从队列中删除该数据.因此,后续的接收呼叫将返回相同的数据.

MSG_PEEK -- This flag causes the receive operation to return data from the beginning of the receive queue without removing that data from the queue. Thus, a subsequent receive call will return the same data.

MSG_WAITALL(从Linux 2.2开始)-此标志请求操作阻塞,直到满足完整请求为止.但是,如果捕获到信号,发生错误或断开连接,或者下一个要接收的数据与返回的数据类型不同,则呼叫返回的数据可能仍然少于请求的数据.

MSG_WAITALL (since Linux 2.2) -- This flag requests that the operation block until the full request is satisfied. However, the call may still return less data than requested if a signal is caught, an error or disconnect occurs, or the next data to be received is of a different type than that returned.

关于为什么 select 表现出您所观察到的方式.尽管 select 调用是线程安全的,但它可能会完全防止重新进入.因此,一个线程对 select 的调用仅在另一个线程的调用完成(对 select 的调用已序列化)之后才进入.这与其作为解复用器的功能是一致的.目的是充当准备好连接的单个仲裁器.因此,它希望由单个线程控制.

As to why select is behaving in the way you observed. While the select call is thread-safe, it is likely fully guarded against reentrancy. So, one thread's call to select will only come in after another thread's call completes (the calls to select are serialized). This is inline with its function as a demultiplexer. It's purpose is to serve as a single arbiter for which connections are ready. As such, it wants to be controlled by a single thread.

这篇关于如何设置非阻塞模式下从服务器的客户端接收消息的超时时间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆