socket阻塞与非阻塞读写

来源:互联网 发布:淘宝流量推广软件 编辑:程序博客网 时间:2024/05/22 16:19

网络协议一般都是由head和body构成。

socket在实际应用中有2种方式,阻塞和非阻塞。

使用setsockopt()可以在2种方式之间切换。

/**** 设置非阻塞模式(for Win32)* **/int nNonBlocking = 1;ioctlsocket(sockListen,FIONBIO,&nNonBlocking);


先看阻塞模式的读写

/**** 功能 - 阻塞模式读取指定字节协议内容* * 参数 - sockfd, 套接字句柄*      - pBuffer, 接收缓冲区*      - nBufferLen, 接收缓冲区大小*      - nBytesToRead, 需要读取的大小** 返回值* true  - 成功读取nBytesToRead个字节* false - 发生错误(SOCKET_ERROR), 连接关闭(0)***/bool ReadMessage(int sockfd                  , char * pBuffer                  , size_t nBufferLen                  , size_t nBytesToRead)  {        int nRead = 0, nFinished = 0;        while (nFinished < nBytesToRead)        {              if (0 >= (nRead = recv(sockfd                                    , pBuffer + nFinished                                    , nBytesToRead - nFinished                                    , 0)))                   break;              nFinished += nRead;        }        if (nFinished == nBytesToRead)        {              return true;        }        return false;  }  

非阻塞模式:

先看一个辅助函数, 检测缓冲区是否就绪

/**** 功能 - 测试指定socket的数据是否可读* * 参数 - hSocket, 需要测试的socket句柄** 返回值* -1 SOCKET_ERROR* 0  BUSY* 1  READY**/int IsRecvBufReady(SOCKET hSocket){fd_set sockSet; FD_ZERO(&sockSet);FD_SET(hSocket,&sockSet);struct timeval interval;interval.tv_sec = 0;interval.tv_usec = 0;int nPending = select(0   // 忽略 , sockSet // 可读, NULL    // 可写, NULL    // 错误, &interval); // 超时return nPending;}/**** 功能 - 读取指定字节** 参数 - hSocket, socket句柄*      - pBuffer, 接收缓冲区*      - nBufferLen, 缓冲区大小*      - nBytesToRead, 需要读取的指定大小** 返回值* -1  发生错误* 1   成功* 0   读取的字节数小于nBytesToRead, 下次读取**/int ReadMessage(SOCKET hSocket               , char * pBuffer               , size_t nBufferLen               , size_t nBytesToRead){    int nStatus = -1;    size_t nRead = 0, nFinished = 0;    while (0 > (nStatus = IsRecvBufReady(hSocket)))    {        if (0 >= (nRead = recv(hSocket                              , pBuffer + nFinished                              , nBytesToRead - nFinished                              , 0)))            return -1;                    nFinished += nRead;                if (nFinished == nBytesToRead)            return 1;    }        return nStatus;}

常用的socket属性设置setsockopt

/**** 开启NOLINGER配置* 立即关闭socket* 不等待缓冲区的数据发送出去* 避免出现大量的FIN_WAIT_2状态的socket占用资源* * 备注: tcp连接关闭的过程* *        Me                            Peer* 1,   close()      -> [FIN] ->          * 2,   FIN_WAIT_1                    CLOSE_WAIT* 3,                <- [ACK] <-     * 4,   FIN_WAIT_2                    * 5,                <- [FIN] <-      close()* 6,   TIME_WAIT                     LAST_ACK* 7,                -> [ACK] ->      * 8,   CLOSED                        CLOSED**/struct linger noLinger;noLinger.l_onoff = 1;noLinger.l_linger = 0;setsockopt(hSocket, SOL_SOCKET, SO_LINGER, (const char *)&noLinger, sizeof(noLinger));/**** No-Nagle* 不需要在缓冲区中整合小包碎片* 立刻发送* 不用凑齐链路层的一个帧大小* **/int NoNagleFlag = 1;setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&NoNagleFlag, sizeof(NoNagleFlag));/**** 设置超时* 注意: linux和win的参数不一样***/int nTimeout = 6000;setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(const char*)&nTimeout,sizeof(nTimeout))


源代码;

http://hi.csdn.net/attachment/201112/20/0_1324361094v7Tx.gif

原创粉丝点击