http://doc.chinaunix.net/linux/201002/389886.shtml
方案1:
int connect_socket_timeout(int sockfd,char *dest_host, int port, int timeout)
{
struct sockaddr_in address;
struct in_addr inaddr;
struct hostent *host;
int err, noblock=1 , connect_ok=0, begin_time=time(NULL);
log_debug("connect_socket to %s:%d\n",dest_host,port);
if (inet_aton(dest_host, &inaddr))
{
// log_debug("inet_aton ok now gethostbyaddr %s\n",dest_host);
memcpy(&address.sin_addr, &inaddr, sizeof(address.sin_addr));
}
else
{
log_debug("inet_aton fail now gethostbyname %s \n",dest_host);
host = gethostbyname(dest_host);
if (!host) {
/* We can't find an IP number */
log_error("error looking up host %s : %d\n",dest_host,errno);
return -1;
}
memcpy(&address.sin_addr, host->h_addr_list[0], sizeof(address.sin_addr));
}
address.sin_family = AF_INET;
address.sin_port = htons(port);
/* Take the first IP address associated with this hostname */
ioctl(sockfd,FIONBIO,&noblock);
/** connect until timeout */
/*
EINPROGRESS A nonblocking socket connection cannot be completed immediately.
EALREADY The socket is nonblocking and a previous connection attempt has not been completed.
EISCONN The socket is already connected.
*/
if (connect(sockfd, (struct sockaddr *) &address, sizeof(address)) < 0)
{
err = errno;
if (err != EINPROGRESS)
{
log_error("connect = %d connecting to host %s\n", err,dest_host);
}
else
{
// log_notice("connect pending, return %d \n", err);
while (1) /* is noblocking connect, check it until ok or timeout */
{
connect(sockfd, (struct sockaddr *) &address, sizeof(address));
err = errno;
switch (err)
{
case EISCONN: /* connect ok */
connect_ok = 1;
break;
case EALREADY: /* is connecting, need to check again */
// log_info("connect again return EALREADY check again...\n");
usleep(50000);
break;
// default: /* failed, retry again ? */
log_error("connect fail err=%d \n",err);
// connect_ok = -1;
// break;
}
if (connect_ok==1)
{
// log_info ("connect ok try time =%d \n", (time(NULL) - begin_time) );
break;
}
if (connect_ok==-1)
{
log_notice ("connect failed try time =%d \n", (time(NULL) - begin_time) );
break;
}
if ( (timeout>0) && ((time(NULL) - begin_time)>timeout) )
{
log_notice("connect failed, timeout %d seconds\n", (time(NULL) - begin_time));
break;
}
}
}
}
else /* Connect successful immediately */
{
// log_info("connect immediate success to host %s\n", dest_host);
connect_ok = 1;
}
/** end of try connect */
return ((connect_ok==1)?sockfd:-1);
}
方案2:
补充关于select在异步(非阻塞)connect中的应用,刚开始搞socket编程的时候
我一直都用阻塞式的connect,非阻塞connect的问题是由于当时搞proxy scan
而提出的呵呵
通过在网上与网友们的交流及查找相关FAQ,总算知道了怎么解决这一问题.同样
用select可以很好地解决这一问题.大致过程是这样的:
1.将打开的socket设为非阻塞的,可以用fcntl(socket, F_SETFL, O_NDELAY)完
成(有的系统用FNEDLAY也可).
2.发connect调用,这时返回-1,但是errno被设为EINPROGRESS,意即connect仍旧
在进行还没有完成.
3.将打开的socket设进被监视的可写(注意不是可读)文件集合用select进行监视,
如果可写,用
getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, sizeof(int));
来得到error的值,如果为零,则connect成功.
在许多unix版本的proxyscan程序你都可以看到类似的过程,另外在solaris精华
区->编程技巧中有一个通用的带超时参数的connect模块.
我们知道,缺省状态下的套接字都是阻塞方式的,这意味着一个套接口的调用不能立即完成时,进程将进入睡眠状态,并等待操作完成。对于某些应用,需要及时可控的客户响应,而阻塞的方式可能会导致一个较长的时间段内,连接没有响应。造成套接字阻塞的操作主要有recv, send, accept, connect.
下面主要以connect为例,讲讲非阻塞的connect的工作原理。当一个TCP套接字设置为非阻塞后,调用connect,会立刻返回一个EINPROCESS的错误。但TCP的三路握手继续进行,我们将用select函数检查这个连接是否建立成功。建立非阻塞的connect有下面三个用途:
1. 可以在系统做三路握手的时候做些其它事情,这段时间你可以为所欲为。
2. 可以用这个技术同时建立多个连接,在web应用中很普遍。
3. 可以缩短connect的超时时间,多数实现中,connect的超时在75秒到几分钟之间,累傻小子呢?
虽然非阻塞的conncet实现起来并不复杂,但我们必须注意以下的细节:
* 即使套接字是非阻塞的,如果连接的服务器是在同一台主机,connect通常会立刻建立。(connect 返回 0 而不是 EINPROCESS)
* 当连接成功建立时,描述字变成可写
* 当连接出错时,描述字变成可读可写
例程:定义一个非阻塞的 connect 函数 connect_nonb
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;
// 获取当前socket的属性, 并设置 noblocking 属性
flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NOBLOCK);
errno = 0;
if ( (n = connect(sockfd, saptr, salen)) < 0)
if (errno != EINPROGRESS)
return (-1);
// 可以做任何其它的操作
if (n == 0)
goto done; // 一般是同一台主机调用,会返回 0
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
wset = rset; // 这里会做 block copy
tval.tv_sec = nsec;
tval.tv_usec = 0;
// 如果nsec 为0,将使用缺省的超时时间,即其结构指针为 NULL
// 如果tval结构中的时间为0,表示不做任何等待,立刻返回
if ((n = select(sockfd+1, &rset, &west, NULL,nsec ?tval:NULL)) == 0) {
close(sockfd);
errno = ETIMEOUT;
return (-1);
}
if(FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &west)) {
len = sizeof(error);
// 如果连接成功,此调用返回 0
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
return (-1);
}
else err_quit(“select error: sockfd not set”);
done:
fcntl(sockfd, F_SETFL, flags); // 恢复socket 属性
if (error) {
close(sockfd);
errno = error;
return (-1);
}
Return (0);
}
注意事项:
* 如果select调用之前,连接已经建立成功,并且有数据发送过来了,这时套接字将是即可读又可写,和连接失败时是一样的。所以我们必须用getsockopt来检查套接字的状态。
* 如果我们不能确定套接字可写是成功的唯一情况时,我们可以采用以下的调用
(1) 调用getpeername,如果调用失败,返回ENOTCONN,表示连接失败
(2) 调用read,长度参数为0,如果read失败,表示connect失败。
(3) 再调用connect一次,其应该失败,如果错误是EISCONN,表示套接字已建立而且连接成功。
* 如果在一个阻塞的套接字上调用的connect,在TCP三路握手前被中断,如果connect不被自动重启,会返回EINTR。但是我们不能调用connect等待连接完成,这样会返回EADDRINUSE,此时我们必须调用select,和非阻塞的方式一样。
相关推荐
支持跨平台的非阻塞socket连接,no-block socket connect
C++ Socket编程示例; 阻塞和非阻塞,涉及多线程编程,以及定时清除服务器连接资源;
● SocketChannel:Socket的替代类,支持阻塞通信与非阻塞通信。 ● Selector:为ServerSocketChannel监控接收连接就绪事件,为SocketChannel监控连接就绪、读就绪和写就绪事件。 ● SelectionKey:代表...
1. 编程理解(36) 1. 经典资料(15) 1. 开源项目(16) 9.SaaS-云存储,云服务(38) 9.SaaS-云计算-学习(38)
非阻塞模式实现面向连接一个服务器和多个客户端的收发数据(select模型) 阻塞模式实现面向无连接的一对一的通信 1.学习通过winsock编程实现网络通信。 2.学习面向连接和面向无连接的网络通讯方式的编程。 3.学习...
socket使用demo, 多个client连接到一个server,实现clients间通信
分析协议构造验证数据,采用异步非阻塞socket发送数据,不采用request的方式。 采用非阻塞的connect,每个IP测试4个端口。 之前没分清国内和国外的IP段,导致去扫国外的,一片超时。所以才有下文的超时处理,但是国内...
这个程序要完成一个聊天室的功能,它是用纯的winsock的去写,而不用任何CSocket的东西, 即可以用来做客户端又可以用来做服务器端,它要求是非阻塞方式的连接。
C语言长连接服务器Demo,TCP SOCKET利用epoll非阻塞,大大提升效率。只是一个简单的demo。
1、把发送、接收消息转为 Window窗口...2、可以只用一个主线程即负责界面、又负责socket通信,而界面不会卡 3、构建了一个Server可以与多个Client连接的模型。 4、基于VC6.0平台,源作者的源码基于VS2008.非原创,3ks。
利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信。 首先,先了解下SocketServer模块中可供使用的类: BaseServer:包含服务器的核心功能与混合(mix-in)类挂钩;这个类只用于派生,所以不会生成这...
多线程C语言爬虫。采用libcvent实现DNS的异步解析,使用epoll实现socket连接的非阻塞读取。
linux系统下的非阻塞套接字的服务端实现,使用函数fcntl更改套接字为非阻塞,使用select函数和fd宏轮询描述符集,使用stl list管理客户端连接
简介 Python 中的 Socket 编程 说明 译者注 授权 ...阻塞调用 关闭连接 字节序 结语 回调模型(selectors模块) 1. 前言 2. 核心类 3. SelectSelector 核心函数代码分析 4. 别名 5. 总结 6. 代码报错问题
1.采用重叠I/O方式实现的socket网络编程,异步非阻塞方式,代码效率比阻塞式的socket编程方式高。2.实现了TCP server方式,只用于服务端,可以支持多客户端。3.可以使用在各种场合用于监控网络数据。4.代码封装成库...
本文实例讲述了PHP中Socket连接及读写数据超时问题。分享给大家供大家参考,具体如下: 虽然PHP中对fsockopen()方法有连接socket的超时参数,但是没有类似C中的连接成功后对数据的读写超时参数设置。没关系...
selectors 模块允许socket 以非阻塞的方式进行通信,selectors 相当于事件注册中心,程序只要将所有事件注册给selectors 管理,当selectors 检测到socket 中的特定事件后,程序就调用相关的监听方法进行处理。...
使用面向连接的流式套接字,采用非阻塞的工作机制,程序只要调用这些函数查询网络消息并作出相 应的响应即可。这些函数包括: InitSocketsStruct:初始化 socket 结构,获取服务端口号。客户程序使用。 InitPassiveSock:...
linux socket编程server和多client连接c++代码;select非阻塞监听;可直接运行./tcp-server和./tcp-client测试;移植性好;
利用socketNIO实现的多客户端聊天室,非阻塞式IO,java代码编写,使用方法:先启动服务端代码再启动客户端代码,可启动多个客户端代码。若使用多个电脑启动客户端,需在客户端代码中更改一下ip地址。