异步非阻塞模式,connect返回-1,errno为115

出现两个错误:

1,connect返回出现-1,errno为115
2,FD_ISSET(sock, &rset) 检测读集合出现异常

异常代码:

// socket 创建
if((sock = socket(addinfo->ai_family, addinfo->ai_socktype, addinfo->ai_protocol))== INVALID_FD_)
	return NET_ERR;

// 设置socket为阻塞
// if( fcntl(sock, F_SETFL, fcntl(sock, F_GETFL)&(~O_NONBLOCK)) == -1)
// 设置socket为非阻塞
if( fcntl(sock, F_SETFL, fcntl(sock, F_GETFL)|O_NONBLOCK) == -1)
{
	return NET_ERR;
}
// 链接 
if(connect(sock, addinfo->ip_addr,addinfo->ip_addrlen) == -1)
{
	LOG(ERROR,"tcpConnect,Connect cut code is:%d", errno);
	if (errno == EINPROGRESS && flags & NET_CONNECT_NONBLOCK)
	{
		return NET_OK;
	}
	else 
		return NET_ERR;
}
fd_set rset,wset;
FD_ZERO(&wset);
// 将文件描述符加入集合之中
FD_SET(sock,&wset);
rset = wset;

// 监视文件描述符(读或写的文件集中的文件描述符)的状态变化情况
if ((ret = select(sock + 1, &rset,&wset, NULL&tval)) < 0 )
{
	LOG(ERROR,"tcpConnect,Connect timeout.");
	return NET_ERR;
}
// 检测集合中的状态是否变化,当检测到fd状态发生变化时返回真
if (!FD_ISSET(sock, &rset) || !FD_ISSET(sock, &wset))
{
	LOG(ERROR,"connectTo, none socket int fd isset.");
	return NET_ERR;
}
return NET_OK;

错误日志:

[ERROR]tcpConnect,Connect cut code is 115
[ERROR]connectTo, none socket int fd isset

结论

客户端链接的时候,读文件集中的文件描述符是不会发生变化,所以上方程序会出现返回异常退出。需要修改:
1.connect 的时候返回-1,且errno是115(EINPROGRESS)的情况是正常的,所以下方错误日志需要去掉。

LOG(ERROR,"tcpConnect,Connect cut code is:%d", errno);

2.select之后去除读文件集中的文件描述符判断。原因(此问题在windows环境下是正常的,但是在linux环境下是异常的,这个问题是一个历史的问题。linux环境下出现这种写法比较早,当时只判定写的文件集中的文件描述符,但是后来windows下也发展出现了这种写法,但是windows下读写都判断,读默认是被修改过的。实际上读的文件描述符在linux和windows都未改动了,只是windows默认让它改动了。)

if (!FD_ISSET(sock, &rset) || !FD_ISSET(sock, &wset))
改为:
if (!FD_ISSET(sock, &wset))

文件描述符的操作函数

fd_set 结构体:可以理解为一个集合,这个集合中存放的是文件描述符(file descriptor),即文件句柄。

FD_ZERO
用法:FD_ZERO(fd_set*);
用来清空fd_set集合,即让fd_set集合不再包含任何文件句柄。
FD_SET
用法:FD_SET(int ,fd_set );
用来将一个给定的文件描述符加入集合之中
FD_CLR
用法:FD_CLR(int ,fd_set
);
用来将一个给定的文件描述符从集合中删除
FD_ISSET
用法:FD_ISSET(int ,fd_set*);
检测fd在fdset集合中的状态是否变化,当检测到fd状态发生变化时返回真,否则,返回假(也可以认为集合中指定的文件描述符是否可以读写)。
函数select
用法:int select(int maxfdp, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
作用:用来够监视我们需要监视的文件描述符(读或写的文件集中的文件描述符)的状态变化情况。并能通过返回的值告知我们。
参数解释:
int maxfdp:集合中所有文件描述符的范围,为所有文件描述符的最大值加1。
fd_set *readfds:要进行监视的读文件集,客户端连接时,该集合不会被触发。
fd_set *writefds :要进行监视的写文件集。
fd_set errorfds:用于监视异常数据。
struct timeval
timeout:select的超时时间,它可以使select处于三种状态:
第一,若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;(文件描述符发生变化是什么意思?指由不可写可读变成可读可写??)
第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数, 不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;
第三,timeout的值大于0,这就是等待的超时时间,即 select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回。
返回值介绍:
小于0 :被监视的文件描述符有变化
-1:出错
0 :超时

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值