网络协议一般都是由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.youkuaiyun.com/attachment/201112/20/0_1324361094v7Tx.gif