最近看了许多关于网络编程的资料,自己小记一下,以方便以后查找。
什么是阻塞socket,什么是非阻塞socket。对于这个问题,我们要先弄清什么是阻塞/非阻塞。阻塞与非阻塞是对一个文件描述符指定的文件或设备的两种工作方式。 阻塞的意思是指,当试图对该文件描述符进行读写时,如果当时没有东西可读或者暂时不可写,程序就进入等待状态,直到有东西可读或者可写为止。 非阻塞的意思是,当没有东西可读或者不可写时,读写函数就马上返回,而不会等待。
这里我列举了,哪些socket api会阻塞:
accept,connect,recv(recvfrom),send(sendto),closesocket,select(poll或epoll)
1)accept在阻塞模式下,没有新连接时,线程会进入睡眠状态;非阻塞模式下,没有新连接时,立即返回WOULDBLOCK错误。
2)connect在阻塞模式下,仅TCP连接建立成功或出错时才返回,分几种具体的情况,这里不再叙述;非阻塞模式下,该函数会立即返回INPROCESS错误(需用select检测该连接是否建立成功)
3)recv/recvfrom/send/sendto很好理解,因为这两类函数读写socket文件描述符的接收/发送缓冲区。
4) select/poll/epoll并不是真正意义上的阻塞,它们的阻塞是由于它们最后一个timeout参数决定的,timeout大于0时,它们会一直等待直到超时才退出(相等于阻塞了吧,^_^),而timeout=-1即永远等待。
5)closesocket也不是真正意义上的阻塞,它其实是指是否等待关闭(相当于阻塞了吧,^_^),它受套接字选项SO_LINGER和SO_DONTLINGER的影响。
若SO_DONTLINGER或SO_LINGER的间隔=0时,closesocket就是非等待关闭的,但是当SO_LINGER的间隔>0时,closesoket就是等待关闭的,直到剩余数据都发送完毕或直到超时才退出。
(但是这个地方只有对于阻塞的套接口才有用,如果是非阻塞的套接口,它会立即返回并且指示错误WOULDBLOCK)。
实例:
客户端读操作:
BOOL CCommunication::InitCom()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
CString szMsg;
m_tcpPort.TrimLeft();
m_tcpPort.TrimRight(); int port = atoi(m_tcpPort); wVersionRequested = MAKEWORD(,); err = WSAStartup(wVersionRequested,&wsaData);
if (err != )
{
return FALSE;
} if (LOBYTE(wsaData.wVersion) != ||
HIBYTE(wsaData.wVersion) != )
{
WSACleanup();
return FALSE;
} m_clientSocket = socket(AF_INET,SOCK_STREAM,);
if (m_clientSocket == INVALID_SOCKET)
{
TRACE("创建套接字失败!");
return FALSE;
} SOCKADDR_IN addrClient;
addrClient.sin_addr.S_un.S_addr = inet_addr(m_szLocalPort);
addrClient.sin_family = AF_INET;
addrClient.sin_port = htons(port);
memset(addrClient.sin_zero,,sizeof(addrClient.sin_zero));
m_connsocket = connect(m_clientSocket,(SOCKADDR*)&addrClient,sizeof(SOCKADDR));
if (m_connsocket == SOCKET_ERROR)
{
TRACE("Connect Error!");
return FALSE;
}
DWORD nMode = ;
int nError = ioctlsocket(m_clientSocket,FIONBIO,&nMode);
if (nError == SOCKET_ERROR)
{
closesocket(m_clientSocket);
WSACleanup();
return FALSE;
}
return TRUE;
} int CCommunication::ReadBytes(BYTE *lpByte, DWORD dwBytes)
{
tv.tv_sec = ;
tv.tv_usec = ;
FD_ZERO(&fdRead);
FD_SET(m_clientSocket,&fdRead); int nError = select(,&fdRead,NULL,NULL,&tv);
if (nError <= )
{
return ;
}
if (FD_ISSET(m_clientSocket,&fdRead))
{
memset(lpByte,,dwBytes);
nError = recv(m_clientSocket,(char*)lpByte,dwBytes,);
} return nError;
}