网络协议一般都是由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