非阻塞之connect()

非阻塞的socket客户端connect()困扰了一下午。因为是非阻塞,不管是否连接上都直接返回,所以就无法知道什么时候连接上。
一开始想到网上找资料,可惜不多。于是MSDN,总算找到一句话。
With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, this function will return SOCKET_ERROR and WSAGetLastError will resturn WSAEWOULDBLOCK. The following list shows the three scenarios that are possible in this case:
Use the select function to determine the completion of the connection request by checking to see if the socket is writeable.
If the application is using WSAEventSelect to indicate interest in connection events, then the associated event object will be signaled indicating that the connect operation is complete (successfully or not).
非阻塞socket连接请求不会立即完成。此时,函数返回SOCKET_ERROR且WSAGetLastERROR()返回WSAEWOULDBLOCK。下面展示了此情况的2种场景:
1、使用select函数检查这个socket是否可写确定连接请求是否完成;
2、如果程序使用WSAEventSelect表明关注连接事件,那么被关联的事件对象将被置信号表示连接操作完成(成功或失败)
小代码如下:

client.c

     FD_ZERO(&wtfds);
	_timout.tv_sec = 3;
	_timout.tv_usec = 0;

	msock = socket(AF_INET, SOCK_STREAM, 0);
	toAddr.sin_family = AF_INET;
	toAddr.sin_port = htons(7000);
	toAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.87");
	
	if (ioctlsocket(msock, FIONBIO, &iTemp) < 0)
	{
		perror("ioctlsocket error\n");
	}
	FD_SET(msock, &wtfds);

	iRet = connect(msock, (SOCKADDR*)&toAddr, sizeof(toAddr));
	if (!iRet)
	{
		printf("connect immediately\n");
		char sndMsg[100] = {0};
		sprintf(sndMsg, "hello world");
		if (SOCKET_ERROR == send(msock, sndMsg, strlen(sndMsg), 0))
		{
			perror("send error");
			return 1;
		}
		printf("send success\n");
	}
	else if (iRet<0 && WSAGetLastError()==WSAEWOULDBLOCK)
	{
		int iRet1 = select(0, NULL, &wtfds, NULL, &_timout);
		if (iRet1 < 0)
		{
			perror("connect error\n");
			return 1;
		}
		else if (!iRet1)
		{
			perror("timeout error\n");
			return 1;
		}
		else
		{
			if (FD_ISSET(msock, &wtfds))
			{
				printf("connect success\n");
				char sndMsg[100] = {0};
				sprintf(sndMsg, "hello world");
				if (SOCKET_ERROR == send(msock, sndMsg, strlen(sndMsg), 0))
				{
					perror("send error");
					return 1;
				}
				printf("send success\n");
			}
		}
	}

server.c

     msock = socket(AF_INET, SOCK_STREAM, 0);
	ioctlsocket(msock, FIONBIO, (unsigned long*)&iNonbk);
	FD_SET(msock, &rdfds);
	
	cltAddr.sin_family = AF_INET;
	cltAddr.sin_port = htons(7000);
	cltAddr.sin_addr.S_un.S_addr = INADDR_ANY;
	if (SOCKET_ERROR == bind(msock, (SOCKADDR*)&cltAddr, sizeof(cltAddr)))
	{
		perror("bind error");
		return 1;
	}
	if (SOCKET_ERROR == listen(msock, 5))
	{
		perror("listen error");
		return 1;
	}
	
	_tim =  time(NULL);
	ltime = localtime(&_tim);
	printf("%d:%d:%d\n", ltime->tm_hour, ltime->tm_min, ltime->tm_sec);
	
	iRet = select(0, &rdfds, NULL, NULL, &_timval);
	if (iRet < 0)
	{
		perror("accept error");
		return 1;
	}
	else if(iRet == 0)
	{
		perror("timeout error");
		return 1;
	}
	else
	{
		if (FD_ISSET(msock, &rdfds))
			printf("msock is in rdfds\n");
		else
			return 1;
		
		SOCKET clsock = accept(msock, (SOCKADDR*)&cltAddr, &iLen);
		if (clsock == INVALID_SOCKET)
		{
			printf("clsock is not a valid socket\n");
			return 1;
		}
		if (FD_ISSET(clsock, &rdfds))
			printf("clsock is in rdfds\n");
		else
			printf("clsock is not in rdfds\n");
		_tim =  time(NULL);
		ltime = localtime(&_tim);
		printf("%d:%d:%d\n", ltime->tm_hour, ltime->tm_min, ltime->tm_sec);
		char recvMsg[100] = {0};
		int iSize = recv(clsock, recvMsg, 100, 0);
		printf("from client %s:%s,%d\n", inet_ntoa(cltAddr.sin_addr),recvMsg,WSAGetLastError());
	}

原文地址:https://www.cnblogs.com/littlejohnny/p/1919434.html