非阻塞connect需要处理的问题

套接字状态默认为阻塞的。对于非阻塞的套接字,如果相应的操作没有满足,就会立即返回EWOULDBLOCK错误,使用比较多即TCP的connect函数。

阻塞的connect要等到3次握手完成才能返回,因此要完成阻塞的connect,需要一个RTT时间,这个RTT时间波动比较大,在局域网中还好,如果在广域网中可能达到几秒,我们可以再这段时间内继续建立其他链接,或者处理其他工作。这就要使用非阻塞connect。

        非阻塞的connec三个用途:

1. 在三次的握手的期间,我们可以处理其他的工作。

2. 我们可以同时建立多个连接,浏览器就是通过这样发起多个连接。

3. 可以通过select,缩短connect的超时时间。

        connect是非阻塞的,那我们如何处理连接错误呢?需要处理的细节:

1. POSIX有关于select和非阻塞connect有两个规则;

   (1)当连接成功时,描述符变为可写;

   (2)当连接出错时,描述符变为可写可读。

2. 如果我们在调用select监听connect套接字时,如果套接字已经连接,那也是可写可读的状态,和连接出错一样的状态,所以要处理在select之前套接字已经连接的情况(一般只会出现在客户端和服务器端在同一台机器上)。

一下是UNP上的非阻塞connect,能够很好的看出,如何解决非阻塞情况下一些问题。

int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec)
{
	int				flags, n, error;
	socklen_t		len;
	fd_set			rset, wset;
	struct timeval	tval;

	flags = Fcntl(sockfd, F_GETFL, 0);
	Fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);  //将套接字设置为非阻塞

	error = 0;
	if ( (n = connect(sockfd, saptr, salen)) < 0)
		if (errno != EINPROGRESS)  //期望的错误为EINPROGRESS,如果不是该错误,那连接肯定出错了。
			return(-1);

	/* Do whatever we want while the connect is taking place. */

	if (n == 0)
		goto done;	//处理在select之前,连接就已经建立的情况。

	//设置select所要监听的套接字
	FD_ZERO(&rset);
	FD_SET(sockfd, &rset);
	wset = rset;
	tval.tv_sec = nsec;
	tval.tv_usec = 0;

	if ( (n = Select(sockfd+1, &rset, &wset, NULL,
					 nsec ? &tval : NULL)) == 0) {
		close(sockfd);		//如果超时,select返回0,那就关闭套接字,设置error为ETIMEOUT
		errno = ETIMEDOUT;
		return(-1);
	}
	//如果套接子可读或者可写,需要检查套接字带处理的错误,这里有一个移植性的问题,getsockopt根据不同的实现会返回0或者-1
	if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
		len = sizeof(error);
		//Solaris返回-1,并把error置为待处理错误
		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
			return(-1);			/* Solaris pending error */ 
	} else
		//返回0,基于Berkeley
		err_quit("select error: sockfd not set");

done:
	Fcntl(sockfd, F_SETFL, flags);	/* restore file status flags */

	if (error) {
		close(sockfd);		/* just in case */
		errno = error;
		return(-1);
	}
	//正确返回
	return(0);
}




  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值