网络编程之非阻塞connect编写
一、connect非阻塞编写
TCP连接的建立涉及到一个三次握手的过程,且socket中connect函数需要一直等到客户接收到对于自己的SYN的ACK为止才返回,
这意味着每 个connect函数总会阻塞其调用进程至少一个到服务器的RTT时间,而RTT波动范围很大,从局域网的几个毫秒到几百个毫秒甚至广域网上的几秒。
这段 时间内,我们可以执行其他处理工作,以便做到并行。在此,需要用到非阻塞connect。
将一个阻塞connect变为非阻塞大概有如下几步:
第一步:将套接字设置为非阻塞模式
设置套接字可以用ioctl()或者fcntl()
(1)用ioctl设置
/*创建套接字*/
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//.................
/*step 1: 将套接字设置为非阻塞*/
flags = ;
ioctl(sockfd, FIONBIO, &flags);
(2)用fcntl函数设置
#include <unistd.h>
#include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ ); //int fcntl(int fd, int cmd, long arg);
参数fd
参数cmd
F_SETLKW F_SETLK 作用相同,但是无法建立锁定时,此调用会一直等到锁定动作成功为止。若在等待锁定的过程中被信号中断时,会立即返回-1,错误代码为EINTR。
返回值
fcntl的返回值与命令有关。如果出错,所有命令都返回-1,如果成功则返回某个其他值。下列四个命令有特定返回值:
F_DUPFD、F_GETFD、F_GETFL、F_GETOWN.
第一个返回新的文件描述符,接下来的两个返回相应标志,最后一个返回一个正的进程ID或负的进程组ID。
/*创建套接字*/
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//.................
/*获取flags标志*/
int flags;
flags = fcntl(sockfd, F_GETFL, );
/*设置套接字为非阻塞*/
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
第二步:调用connect连接判断返回值
ret = connect(sockfd, addr, addrlen);
if (ret == ) {
return TURE;
}
if (ret < && errno == EINPROGRESS) { /*如果调用connect函数会之间返回-1(表示出错),且错误为EINPROGRESS,表示连接建立,建立启动但是尚未完成,*/
}
else
// connect error
实现非阻塞 connect ,首先把 sockfd 设置成非阻塞的。这样调用 connect 可以立刻返回,根据返回值和 errno 处理三种情况
(1) 如果返回 0,表示 connect 成功。
(2) 如果返回值小于 0, errno 为 EINPROGRESS, 表示连接建立已经启动但是尚未完成。这是期望的结果,不是真正的错误
(3) 如果返回值小于0,errno 不是 EINPROGRESS,则连接出错了。
建立connect连接,此时socket设置为非阻塞,connect调用后,无论连接是否建立立即返回-1,同时将errno(包含 errno.h就可以直接使用)设置为EINPROGRESS, 表示此时tcp三次握手仍旧进行,如果errno不是EINPROGRESS,则说明连接错误,程序结束。
当客户端和服务器端在同一台主机上的时候,connect回马上结束,并返回0;无需等待,所以使用goto函数跳过select等待函数,直接进入连接后的处理部分
第三步:将套接字添加到select集合中,判断是否可读可写
ret = connect(sockfd, addr, addrlen);
if (ret < && errno == EINPROGRESS) { /*如果调用connect函数会之间返回-1(表示出错),且错误为EINPROGRESS,表示连接建立,建立启动但是尚未完成;*/
FD_ZERO(&connectfd);
FD_SET(, &connectfd);
FD_SET(sockfd, &connectfd);//将套接字加入到集合中
/*设置超时时间*/
timeout.tv_sec = ;
timeout.tv_usec = ;
if (select(sockfd+, NULL, &connectfd, NULL, &timeout) > )
{
len = sizeof(uint32);
/*获取error值,并进行判断*/
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, (socklen_t*)&len);
if (err == )
{
ret = TURE;
}
else
ret = ERR;
}
else
ret = ERR;
}
设置等待时间,使用select函数等待正在后台连接的connect函数,这里需要说明的是使用select监听socket描述符是否可读或者可写,如果只可写,说明连接成功,可以进行下面的操作。如果描述符既可读又可写,分为两种情况,第一种情况是socket连接出现错误,第二种情况是connect连接成 功,socket读缓冲区得到了远程主机发送的数据。需要通过connect连接后返回给errno的值来进行判定,或者通过调用 getsockopt(sockfd,SOL_SOCKET,SO_ERROR,&error,&len); 函数返回值来判断是否发生错误.当网络发生错误的时候,getsockopt返回-1,return -1,程序结束。网络正常时候返回0,程序继续执行
第四步:恢复套接字描述符状态为非阻塞,并返回
()
/* 恢复套接字非阻塞*/
flags = ;
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); ()
/* 恢复套接字阻塞*/
flags = ;
ioctl(sockfd, FIONBIO, &flags);
下面是整个connect流程代码:
(1) 创建socket,并利用fcntl将其设置为非阻塞
(2) 调用connect函数,如果返回0,则连接建立;如果返回-1,检查errno ,如果值为 EINPROGRESS,则连接正在建立
(3) 为了控制连接建立时间,将该socket描述符加入到select的可写集合中,采用select函数设定超时
(4) 如果规定时间内成功建立,则描述符变为可写;否则,采用getsockopt函数捕获错误信息
(5) 恢复套接字的文件状态并返回
int Connect(uint32 sockfd, struct sockaddr *addr, socklen_t addrlen)
{
struct timeval timeout;
uint32 flags, len;
int err, ret;
fd_set connectfd; if (NULL == addr)
return ERR; /*step 1: 将套接字设置为非阻塞*/
flags = ;
ioctl(sockfd, FIONBIO, &flags); /*step 2: 调用connect连接*/
if ((ret = connect(sockfd, addr, addrlen)) < )
{
if (errno != EINPROGRESS)
ret = ERR; FD_ZERO(&connectfd);
FD_SET(, &connectfd);
FD_SET(sockfd, &connectfd); timeout.tv_sec = ;
timeout.tv_usec = ;
if (select(sockfd+, NULL, &connectfd, NULL, &timeout) > )
{
len = sizeof(uint32);
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, (socklen_t*)&len);
if (err == )
{
ret = TURE;
}
else
ret = ERR;
}
else
ret = ERR;
} 42 /*恢复套接字为阻塞模式*/
flags = ;
ioctl(sockfd, FIONBIO, &flags); return ret;
}
网络编程之非阻塞connect编写的更多相关文章
- UNIX网络编程——非阻塞connect:时间获取客户程序
#include "unp.h" int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec) ...
- UNIX网络编程-非阻塞connect和非阻塞accept
1.非阻塞connect 在看了很多资料之后,我自己的理解是:在socket发起一次连接的时候,这个过程需要一段时间来将三次握手的过程走完,如果在网络状况不好或者是其他的一些情况下,这个过程需要比较长 ...
- UNIX网络编程——非阻塞connect: Web客户程序
非阻塞的connect的实现例子出自Netscape的Web客户程序.客户先建立一个与某个Web服务器的HTTP连接,再获取一个主页.该主页往往含有多个对于其他网页的引用.客户可以使用非阻塞conne ...
- UNIX网络编程——非阻塞connect
当在一个非阻塞的TCP套接字上调用connect时,connect将立即返回一个EINPROGRESS错误,不过已经发起的TCP三次握手继续进行.我们接着使用select检测这个连接或成功或失败的已建 ...
- linux 客户端 Socket 非阻塞connect编程
开发测试环境:虚拟机CentOS,windows网络调试助手 非阻塞模式有3种用途 1.三次握手同时做其他的处理.connect要花一个往返时间完成,从几毫秒的局域网到几百 ...
- 面向连接的socket数据处理过程以及非阻塞connect问题
对于面向连接的socket类型(SOCK_STREAM,SOCK_SEQPACKET)在读写数据之前必须建立连接,首先服务器端socket必须在一个客户端知道的地址进行监听,也就是创建socket之后 ...
- (转)非阻塞Connect对于select时应注意问题
对于面向连接的socket类型(SOCK_STREAM,SOCK_SEQPACKET)在读写数据之前必须建立连接,首先服务器端socket必须在一个客户端知道的地址进行监听,也就是创建socket之后 ...
- 网络IO模型 非阻塞IO模型
网络IO模型 非阻塞IO模型 同步 一件事做完后再做另一件事情 异步 同时做多件事情 相对论 多线程 多进程 协程 异步的程序 宏观角度:异步 并发聊天 阻塞IO 阻塞IO的问题 一旦阻塞就不能做其他 ...
- TCP非阻塞accept和非阻塞connect
http://blog.chinaunix.net/uid-20751538-id-238260.html 非阻塞accept 当一个已完成的连接准备好被accept的时候,select会把监 ...
随机推荐
- 《java入门第一季》之面向对象(继承)
/* 继承的注意事项: A:子类只能继承父类所有(非私有)的成员(成员方法和成员变量),私有的变量和方法没法继承 B:子类(不能)继承父类的(构造方法),但是可以通过super关键字去访问父类构造方法 ...
- 【面试笔试算法】Problem 9: 腾讯2016年研发实习笔试题:最长回文子串
(一)题目 问题:求给定字符串s的回文(palindrome)子串中,长度最大的回文子串的长度. 回文(palindrome)是指从左往右读和从右往左读字符串,看到的字符串都是一样的.比如" ...
- Android 常用的ORM框架详解
1. OrmLite OrmLite 不是 Android 平台专用的ORM框架,它是Java ORM.支持JDBC连接,Spring以及Android平台.语法中广泛使用了注解(Annotation ...
- Java-ServletRequestEvent-ServletRequestAttributeEvent
/** * Events of this kind indicate lifecycle * events for a ServletRequest. * The source of the even ...
- Android服务器——TomCat服务器的搭建
Android服务器--TomCat服务器的搭建 作为一个开发人员,当然是需要自己调试一些程序的,这个时候本地的服务器就十分方便了,一般都会使用TomCat或者IIS服务器,IIS就比较简单了,其实t ...
- 色彩转换——RGB & HSL
RGB to HSL The R,G,B values are divided by 255 to change the range from 0..255 to 0..1: R' = R/255 G ...
- zookeeper 应用开发
由于zookeeper的client只有zookeeper一个对象,使用也比较简单,所以就不许要文字说明了,在代码中注释下就ok 了. 1.测试用的main方法 package ClientExamp ...
- HBase数据字典
数据字典用来存储了系统的元数据.HBase的元数据包括:用户表的定义.表的切分方案.分片的分布情况(即分片分布在哪个regionserver上).分片对应的数据文件和日志文件.其中,分片和数据文件的映 ...
- SQLSERVER 执行过的语句查询
total_worker_time AS [总消耗CPU 时间(ms)], execution_count [运行次数], qs.total_worker_time AS [平均消耗CPU 时间(ms ...
- python--Numpy and Pandas 基本语法
numpy和pandas是python进行数据分析的非常简洁方便的工具,话不多说,下面先简单介绍一些关于他们入门的一些知识.下面我尽量通过一些简单的代码来解释一下他们该怎么使用.以下内容并不是系统的知 ...