简体   繁体   English

如何设置超时以非阻塞方式从服务器的客户端接收消息?

[英]How to set time out for receiving message fromt client of server with non-blocking mode?

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. 我有一个具有2个连接SOCKETserver ,该serverclients连接,并且我将此server设置为非阻止模式,该模式在发送或接收消息时不会停止。 I want to set time out for a SOCKET of each connections, but if I use the following code: 我想为每个连接的SOCKET设置超时,但是如果使用以下代码:

 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 is a demultiplexing mechanism. select是一种解复用机制。 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 ). 当您使用它来确定单个套接字上的数据何时准备就绪或超时时,它实际上是为在许多套接字上返回数据就绪状态而设计的(因此fd_set )。 Conceptually, it is the same with poll , epoll and kqueue . 从概念上讲, pollepollkqueue 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. 我相信让套接字处于阻塞I / O模式更为合适。

If you insist on non-blocking mode, my suggestion is to replace the select call with something else. 如果您坚持使用非阻塞模式,我的建议是将select调用替换为其他内容。 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. 由于您要从select中获得的信息是单个套接字已准备就绪或超时的指示,因此通过在适当的参数上设置套接字并设置适当的超时,可以通过recv达到类似的效果。

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;
}

From man recv : man recv

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. MSG_PEEK-此标志使接收操作从接收队列的开头返回数据,而不从队列中删除该数据。 Thus, a subsequent receive call will return the same data. 因此,后续的接收呼叫将返回相同的数据。

MSG_WAITALL (since Linux 2.2) -- This flag requests that the operation block until the full request is satisfied. MSG_WAITALL(从Linux 2.2开始)-此标志请求操作块,直到满足完整请求为止。 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. 但是,如果捕获到信号,发生错误或断开连接,或者下一个要接收的数据与返回的数据类型不同,则呼叫返回的数据仍可能比请求的少。

As to why select is behaving in the way you observed. 至于为什么select以您观察的方式表现。 While the select call is thread-safe, it is likely fully guarded against reentrancy. 尽管select调用是线程安全的,但可能会完全防止重入。 So, one thread's call to select will only come in after another thread's call completes (the calls to select are serialized). 因此,一个线程的select调用只会在另一个线程的调用完成之后才进行( select的调用已序列化)。 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. 因此,它希望由单个线程控制。

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

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