对于socket编程一直有一种误解:socket的阻塞连接下应该调用send/recv来发送和接收数据,而无阻塞连接下应该用WSASend/WSARecv函数来发送和接收数据。其实socket工作模式与调用哪个收发函数没有任何关系,自己写段简单的代码测试下就知道了。无阻塞模式下,send/recv都是立即返回的。并不会等待发送或接收完成才返回。测试还发现选择模式下无阻塞连接,调用connect函数会立即返回,随后调用select,在连接建立时会设置fdWrite。
SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
return -1;
}
// Set the connection to non-blocking mode
unsigned long ulMode = 1;
if (::ioctlsocket(s, FIONBIO, &ulMode) != 0)
{
s = INVALID_SOCKET;
return -1;
}
char szHost[128] = "www.myhost.com";
int nPort = 8000;
char szBuffer[1024] = "test socket function.\n"
addrinfo aiHints;
addrinfo *aiList = NULL;
memset(&aiHints, 0, sizeof(aiHints));
aiHints.ai_family = AF_INET;
aiHints.ai_socktype = SOCK_STREAM;
aiHints.ai_protocol = IPPROTO_TCP;
if (0 != ::getaddrinfo(szHost, NULL, &aiHints, &aiList))
{
//m_nLastError = WSAGetLastError();
::WSASetLastError(WSAEINVAL);
return -1;
}
fd_set fdRead, fdWrite;
FD_ZERO(&fdRead);
FD_ZERO(&fdWrite);
FD_SET(s, &fdRead);
FD_SET(s, &fdWrite);
struct timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 0;
SOCKADDR_IN hostAddr;
hostAddr = *((SOCKADDR_IN*)aiList->ai_addr);
hostAddr.sin_port = ::htons(nPort);
int retCode = ::connect(s, (SOCKADDR*) &hostAddr, sizeof(hostAddr));
if (retCode == SOCKET_ERROR)
{
int errCode = WSAGetLastError();
if (errCode != WSAEWOULDBLOCK)
{
::closesocket(s);
s = INVALID_SOCKET;
return -1;
}
}
retCode = ::select(0, &fdRead, &fdWrite, NULL, &tv);
if (retCode > 0)
{
if (FD_ISSET(s, &fdRead))
{
printf("error!\n");
}
if (FD_ISSET(s, &fdWrite))
{
//connection has succeeded.
printf("connect success!\n");
FD_SET(s, &fdWrite);
FD_ZERO(&fdRead);
retCode = ::select(0, &fdRead, &fdWrite, NULL, &tv);
if (retCode > 0)
{
if (FD_ISSET(s, &fdRead))
{
printf("error!\n");
}
if (FD_ISSET(s, &fdWrite))
{
retCode = send(s, szBuffer, strlen(szBuffer), 0);
if (retCode > 0)
{
retCode = recv(s, buf, 1023, 0);
if (retCode == SOCKET_ERROR)
{
retCode = WSAGetLastError();
}
else if (retCode > 0)
{
printf("recv %d bytes.\n", retCode);
}
}
}
}
}
}
return 0; 很多问题要想深入理解最好的方法就是写一段短的测试程序验证一下,既不要想当然也不要道听途说。