场景描述:

通讯上的问题,client在接收server数据时,偶尔会发生EAGAIN的错误。使用strace抓出来的显示基本相同,但红旗方面提供的帮助说可能是使用select后,套接字不在集合中了。现正在改代码,问题有两个:

  1. 以下对EAGAIN的处理是否正确?

  2. select后是否必须用FD_ISSET检测sockfd是否在fd_set集合中?如果FD_ISSET返回错误,该如何处理?原sockfd是否还可用?重建sockfd还是只需要重新清空fd_set,再使用select等待?

望高人解答!

strace片段:
17:09:12 send(1089, "\0\0\1$\2\10\0\0\nAAAAAAAAAA110101\0\0\0\0\0\0\0"..., 296, 0) = 296
17:09:12 recv(1089, 0xbfff0090, 4000, 0) = -1 EAGAIN (Resource temporarily unavailable)
17:09:12 select(1090, [1088 1089], NULL, NULL, {3, 0}) = 1 (in [1088], left {3, 0})
17:09:12 recv(1089, 0xbfff0090, 4000, 0) = -1 EAGAIN (Resource temporarily unavailable)
17:09:12 close(1089) = 0

代码片段:


while(nLen < nMsgLen) {
                FD_ZERO(&r_fds);
                FD_SET(nSockfd, &r_fds);
                errno = 0;

                if ((tv.tv_sec > 0)
                        || ((tv.tv_sec == 0) && (tv.tv_usec > 0))){
                    ret = select(nSockfd + 1, &r_fds, NULL, NULL, &tv);
                }else{
                    ret = select(nSockfd + 1, &r_fds, NULL, NULL, NULL);
                }
                if (ret < 0) {          /* error */
                    return -1;
                }else if(ret == 0) {    /* expired */
                    return -2;
                }
                [color=#FF0000]/** 增加对 FD_ISSET 返回值处理 **/[/color]

                /* recv data */
                nRecvLen = recv(nSockfd, &pData[nLen], HSM_MAX_BUFFER_SIZE, 0);
                if(nRecvLen < 0) {      /* error */
                    [color=#FF6600]if (EAGAIN == errno)
                    {
                        if ((tv.tv_sec > 0)
                                || ((tv.tv_sec == 0) && (tv.tv_usec > 0)))
                        {
                            continue;
                        }
                    }[/color]/* 增加的对EAGAIN错误的处理 */
                    return -2;
                }else if (nRecvLen == 0)
                    return -4; // peer close connection.

                nLen += nRecvLen;
            } /* while */

推荐图书

  • C++ Primer中文版(第4版)
  • More Effective C++:35个改善编程与设计的有效方法(中文版)
  • 设计模式:可复用面向对象软件的基础


1个回答

如果select表示socket可读,那么再recv应该不会返回EAGAIN

select返回时,可能会修改它的参数(集合、超时时间),最好在循环内部重新赋值