select在异步(非阻塞)connect中的使用

select在异步(非阻塞)connect中的使用

socket编程中非阻塞connet调用的处理可以借助select来解决,大致步骤如下:

1. 将打开的socket设为非阻塞的

Windows设置方式


		unsigned long unblock = 1;
    	ret = ioctlsocket(tSock, FIONBIO, (unsigned long *)&unblock);
    	if(ret == SOCKET_ERROR) {
    		printf("Set Socket NonBlock Failed!\n");
    		SockClose(tSock);
    		return INVALID_NODE;
    	}

Linux可以用

   fcntl(socket, F_SETFL, O_NDELAY)

2. 调用connect,非阻塞形式下会返回-1,但是errno被设为EINPROGRESS,意即connect仍旧

在进行还没有完成.

3. 将打开的socket设进被监视的可写(注意不是可读)文件集合用select进行监视, 如果可写,用 getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, sizeof(int)); 来得到error的值,如果为零,则connect成功.

4. 代码流程


    	flags = fcntl(tSock, F_GETFL, 0)
    	fcntl(tSock, F_SETFL, flags | O_NONBLOCK)
    	ret = connect(tSock, (SOCKADDR *)&tSvrINAddr, sizeof(tSvrINAddr))
    	if(ret < 0) {
    	/* if connect error */
    	if (errno != EINPROGRESS) {
    			printf("\nConnecting Failed!\n");
    			SockClose(tSock);
    			return INVALID_NODE;
    	} else {
    		fd_set rset, wset;
    		int error = 0;
    		socklen_t len = sizeof(error);
    		FD_ZERO(&rset);
    		FD_SET(tSock, &rset);
    		wset = rset;
    		bWait = select(tSock + 1, &rset, &wset, NULL, pTimeVal);
    		if (bWait <= 0) {
    			printf("Connect TimeOut!\n");
    			SockClose(tSock);
    			return INVALID_NODE;
    		}
    		if (getsockopt(tSock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
    			printf("Get Socket Error !\n");
    			SockClose(tSock);
    			return INVALID_NODE;
    		}
    		if (error > 0) {
    			printf("\nGet Socket Error %d\n", error);
    			SockClose(tSock);
    			return INVALID_NODE;
    		}
    		}
    	}

5. 注意:

22:参数错误,比如ip地址不合法,没有目标端口等
101:网络不可达,比如不能ping通
111:链接被拒绝,比如目标关闭链接等
115:当链接设置为非阻塞时,目标没有及时应答,返回此错误,socket可以继续使用

猜你喜欢

转载自blog.csdn.net/tsh123321/article/details/88948782