步骤1: 设置非阻塞,启动连接
实现非阻塞 connect ,首先把 sockfd 设置成非阻塞的。这样调用
connect 可以立刻返回,根据返回值和 errno 处理三种情况:
(1) 如果返回 0,表示 connect 成功。
(2) 如果返回值小于 0, errno 为 EINPROGRESS, 表示连接
建立已经启动但是尚未完成。这是期望的结果,不是真正的错误。
(3) 如果返回值小于0,errno 不是 EINPROGRESS,则连接出错了。
步骤2:判断可读和可写
然后把 sockfd 加入 select 的读写监听集合,通过 select 判断 sockfd
是否可写,处理三种情况:
(1) 如果连接建立好了,对方没有数据到达,那么 sockfd 是可写的
(2) 如果在 select 之前,连接就建立好了,而且对方的数据已到达,
那么 sockfd 是可读和可写的。
(3) 如果连接发生错误,sockfd 也是可读和可写的。
判断 connect 是否成功,就得区别 (2) 和 (3),这两种情况下 sockfd 都是
可读和可写的,区分的方法是,调用 getsockopt 检查是否出错。
步骤3:使用 getsockopt 函数检查错误
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len)
在 sockfd 都是可读和可写的情况下,我们使用 getsockopt 来检查连接
是否出错。但这里有一个可移植性的问题。
如果发生错误,getsockopt 源自 Berkeley 的实现将在变量 error 中
返回错误,getsockopt 本身返回0;然而 Solaris 却让 getsockopt 返回 -1,
并把错误保存在 errno 变量中。所以在判断是否有错误的时候,要处理
这两种情况。
代码:
int conn_nonb(int sockfd, const struct sockaddr_in *saptr, socklen_t salen, int nsec)
{
int flags, n, error, code;
socklen_t len;
fd_set 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) {
goto done;
} else if (n < 0 && errno != EINPROGRESS){
return (-1);
}
/* Do whatever we want while the connect is taking place */
FD_ZERO(&wset);
FD_SET(sockfd, &wset);
tval.tv_sec = nsec;
tval.tv_usec = 0;
if ((n = select(sockfd+1, NULL, &wset,
NULL, nsec ? &tval : NULL)) == 0) {
close(sockfd); /* timeout */
errno = ETIMEDOUT;
return (-1);
}
if (FD_ISSET(sockfd, &wset)) {
len = sizeof(error);
code = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
/* 如果发生错误,Solaris实现的getsockopt返回-1,
* 把pending error设置给errno. Berkeley实现的
* getsockopt返回0, pending error返回给error.
* 我们需要处理这两种情况 */
if (code < 0 || error) {
close(sockfd);
if (error)
errno = error;
return (-1);
}
} else {
fprintf(stderr, "select error: sockfd not set");
exit(0);
}
done:
fcntl(sockfd, F_SETFL, flags); /* restore file status flags */
return (0);
}
分享到:
相关推荐
网络实现非阻塞connect,select带超时
1. 编程理解(36) 1. 经典资料(15) 1. 开源项目(16) 9.SaaS-云存储,云服务(38) 9.SaaS-云计算-学习(38)
2.将该socket设置为非阻塞模式 3.调用connect() 4.使用select()检查该socket描述符是否可写(注意,是可写) 5.根据select()返回的结果判断connect()结果 6.将socket设置为阻塞模式(如果你的程序不需要用阻塞...
异步消息通知 消息队列 发送队列 接口实现
创建tcp socket,实现非阻塞的connect()
socket客户端封装类,实现connect,read,write的非阻塞操作.
使用非阻塞I/O允许你设置一个低的时间用尽周期,同时观察多个套接字。但这种方法的缺点是很容易被发觉,并且被过滤掉。目标计算机的logs文件会显示一连串的连接和连接是出错的服务消息,并且能很快的使它关闭。 TCP ...
oauth.apisample.javaspringboot概述使用OAuth和Open Id... AWS Cognito用作默认授权服务器用于实现OAuth自定义过滤器用于通过简单的代码实现非阻塞API 可以将API日志汇总到以支持SSL证书certs文件夹中的证书源自存储库
但它屏蔽了Socket的异步、非阻塞等概念,开发人员无需了解异步、非阻塞Socket的原理和工作机制。因此,建议初学者学习编网络通信程序时,暂且不要用MFC提供的类,而先用Winsock2 API,这样有助于对异步、非阻塞...
否则它就是一个标准的非阻塞socket对象。 底层的事件在特定事件或特定的连接状态告诉异步循环,某些高级事件发生了。例如, 我们要求一个socket连接到另一个主机。 (1)handle_connect() 第一次读或写事件。 (2)...
连接时(connect),重写的connect函数自动把socket设置为非阻塞。 当在协程中进行读写时,如果socket未就绪(不可读或不可写), 重写的send,recv,read,write函数自动会挂起当前协程, 返回到主程序处理其它请求。在挂...
尽管Socketry提供了类似于Ruby自己的TCPSocket和UDPSocket类的同步阻塞API,但在后台它却使用非阻塞I / O来实现线程安全超时。安装将此行添加到您的应用程序的Gemfile中: gem "socketry" 然后执行: $ bundle或将...
9.2 poll系统调用 9.3 epoll系列系统调用 9.3.1 内核事件表 9.3.2 epoll_wait函数 9.3.3 LT和ET模式 9.3.4 EPOLLONESHOT事件 9.4 三组IO复用函数的比较 9.5 IO复用的高级应用一:非阻塞connect 9.6 IO复用...
构建一个connect pool,然后再调用它, 8.j2ee平台与dotnet平台的区别 9.ejb的life cycle 10.session bean 和 entity bean的区别 11.ejb中的transaction机制 12.synchronized (生产者和消费) 13.String 和 ...
5.3 阻塞、等待与安全设计 80 5.3.1 驱动主动通知应用 80 5.3.2 通信接口的测试 81 5.3.3 内核中的缓冲区链表结构 83 5.3.4 输入:内核中的请求处理中的安全检查 84 5.3.5 输出处理与卸载清理 85 第6章 64位和...
5.3 阻塞、等待与安全设计 80 5.3.1 驱动主动通知应用 80 5.3.2 通信接口的测试 81 5.3.3 内核中的缓冲区链表结构 83 5.3.4 输入:内核中的请求处理中的安全检查 84 5.3.5 输出处理与卸载清理 85 第6章 64位和...
// 设置通道为非阻塞 channel.configureBlocking(false); // 获得一个通道管理器 this.selector = Selector.open(); // 客户端连接服务器,其实方法执行并没有实现连接,需要在listen()方法中调 //用...
glibc 是 posix 的实现 所以用 PF代替了 AF,不过我们都可以使用的). type:我们网络程序所采用的通讯协议(SOCK_STREAM,SOCK_DGRAM 等) SOCK_STREAM 表明 我们用的是 TCP协议,这样会提供按顺序的,可靠,双向,面向...
CONNECT:拥有Connect权限的用户只可以登录Oracle,不可以创建实体,不可以创建数据库结构。 注意: 对于普通用户:授予connect, resource权限。 对于DBA管理用户:授予connect,resource, dba权限。 授予系统...