非阻塞式connect的Windows实现

     下面是connect的MSDN文档。由划线部分可知,当socket设置为非阻塞模式时,connect发起后会立即返回,然而,“三次握手”却依然进行,此时,connect返回SOCKET_ERROR,WSAGetLastError()返回WSAEWOULDBLOCK。如果需要判断connect是否成功,可以使用select()函数,当connect成功时,socket文件描述符写就绪;当connect失败时,socket文件描述符异常就绪。
Return Value
     If no error occurs, connect returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be retrieved by calling WSAGetLastError.
    On a blocking socket, the return value indicates success or failure of the connection attempt.
    With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, connect will return SOCKET_ERROR, and WSAGetLastError will return WSAEWOULDBLOCK. In this case, there are three possible scenarios:
     • 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 WSAAsyncSelect to indicate interest in connection events, then the application will receive an FD_CONNECT notification indicating that the connect operation is complete (successfully or not).

     • 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).


     For connection-oriented, nonblocking sockets, it is often not possible to complete the connection immediately. In such a case, this function returns the error WSAEWOULDBLOCK. However, the operation proceeds.

     When the success or failure outcome becomes known, it may be reported in one of two ways, depending on how the client registers for notification.
     • If the client uses the select function, success is reported in the writefds set and failure is reported in the exceptfds set.

     • If the client uses the functions WSAAsyncSelect or WSAEventSelect, the notification is announced with FD_CONNECT and the error code associated with the FD_CONNECT indicates either success or a specific reason for failure.

     下面是select()的MSDN文档。由connect的帮助文档可知,当socket文件描述符异常就绪时,connect失败,那么,如何得到错误号呢?由下面划线的句子可知,当connect失败时,使用getsocket中的SO_ERROR可以得到错误号。
     The parameter writefds identifies the sockets that are to be checked for writability. If a socket is processing a connect call (nonblocking), a socket is writeable if the connection establishment successfully completes. If the socket is not processing a connect call, writability means a send, sendto, or WSASendto are guaranteed to succeed. However, they can block on a blocking socket if the len parameter exceeds the amount of outgoing system buffer space available. It is not specified how long these guarantees can be assumed to be valid, particularly in a multithreaded environment.
     The parameter exceptfds identifies the sockets that are to be checked for the presence of OOB data or any exceptional error conditions.

     Note: Out-of-band data will only be reported in this way if the option SO_OOBINLINE is FALSE. If a socket is processing a connect call (nonblocking), failure of the connect attempt is indicated in exceptfds (application must then call getsockopt SO_ERROR to determine the error value to describe why the failure occurred). This document does not define which other errors will be included.

    下面是vs2008环境下的实现代码。

int connect()
{	
	unsigned long ul = 1;
	ioctlsocket(sockClient, FIONBIO, &ul);//将socket设置为阻塞模式

	if ( (connect(sockClient, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR)) == SOCKET_ERROR ) 
			&& (WSAGetLastError() == WSAEWOULDBLOCK)) 
	{
		fd_set writefds,expectfds;
		struct timeval tv;

		tv.tv_sec = 2;//设置select()超时时间为2s
		tv.tv_usec = 0;
		FD_ZERO(&writefds);
		FD_ZERO(&expectfds);
		FD_SET(sockClient,&writefds);
		FD_SET(sockClient,&expectfds);

		int result = select(sockClient + 1, NULL, &writefds, &expectfds, &tv);
		if (result > 0) 
		{
			if(FD_ISSET(sockClient,&writefds))
				printf("connect success!\n");	
			if(FD_ISSET(sockClient,&expectfds))
			{
				printf("connect failed!\n");	
				int error, error_len;
				error_len = sizeof(error);
				getsockopt(sockClient, SOL_SOCKET, SO_ERROR, (char *)&error, &error_len);//获得错误号
				printf("error is :%d\n",error);
				WSACleanup();
				return -1;
			}
		}
		else if(result == 0)
		{
			printf("connect timeout\n");
			WSACleanup();
			return -1;
		}
		else
		{
			printf("select() error :\n",WSAGetLastError());
			WSACleanup();
			return -1;  
		}
	}
	else
	{
		printf("connect() error :\n",WSAGetLastError());
		WSACleanup();
		return -1;  		
	}

	ul = 0;
	ioctlsocket(sockClient, FIONBIO, &ul);//将socket恢复为非阻塞模式
 	return 0;
}




  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值