一、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

参数fd代表欲设置的文件描述符

参数cmd

参数cmd代表打算操作的指令
有以下几种情况:
F_DUPFD用来查找大于或等于参数arg的最小且仍未使用的文件描述符,并且复制参数fd的文件描述符。
F_GETFD取得close-on-exec旗标。若此旗标的FD_CLOEXEC位为0,代表在调用exec()相关函数时文件将不会关闭。
F_SETFD 设置close-on-exec 旗标。该旗标以参数arg 的FD_CLOEXEC位决定。
F_GETFL 取得文件描述符状态旗标,此旗标为open()的参数flags。
F_SETFL 设置文件描述符状态旗标,参数arg为新旗标,但只允许O_APPEND、O_NONBLOCK和O_ASYNC位的改变,其他位的改变将不受影响。
F_GETLK 取得文件锁定的状态。
F_SETLK 设置文件锁定的状态。此时flcok 结构的l_type 值必须是F_RDLCK、F_WRLCK或F_UNLCK。如果无法建立锁定,则返回-1,错误代码为EACCES 或EAGAIN。

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编写的更多相关文章

  1. UNIX网络编程——非阻塞connect:时间获取客户程序

    #include "unp.h" int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec) ...

  2. UNIX网络编程-非阻塞connect和非阻塞accept

    1.非阻塞connect 在看了很多资料之后,我自己的理解是:在socket发起一次连接的时候,这个过程需要一段时间来将三次握手的过程走完,如果在网络状况不好或者是其他的一些情况下,这个过程需要比较长 ...

  3. UNIX网络编程——非阻塞connect: Web客户程序

    非阻塞的connect的实现例子出自Netscape的Web客户程序.客户先建立一个与某个Web服务器的HTTP连接,再获取一个主页.该主页往往含有多个对于其他网页的引用.客户可以使用非阻塞conne ...

  4. UNIX网络编程——非阻塞connect

    当在一个非阻塞的TCP套接字上调用connect时,connect将立即返回一个EINPROGRESS错误,不过已经发起的TCP三次握手继续进行.我们接着使用select检测这个连接或成功或失败的已建 ...

  5. linux 客户端 Socket 非阻塞connect编程

    开发测试环境:虚拟机CentOS,windows网络调试助手        非阻塞模式有3种用途        1.三次握手同时做其他的处理.connect要花一个往返时间完成,从几毫秒的局域网到几百 ...

  6. 面向连接的socket数据处理过程以及非阻塞connect问题

    对于面向连接的socket类型(SOCK_STREAM,SOCK_SEQPACKET)在读写数据之前必须建立连接,首先服务器端socket必须在一个客户端知道的地址进行监听,也就是创建socket之后 ...

  7. (转)非阻塞Connect对于select时应注意问题

    对于面向连接的socket类型(SOCK_STREAM,SOCK_SEQPACKET)在读写数据之前必须建立连接,首先服务器端socket必须在一个客户端知道的地址进行监听,也就是创建socket之后 ...

  8. 网络IO模型 非阻塞IO模型

    网络IO模型 非阻塞IO模型 同步 一件事做完后再做另一件事情 异步 同时做多件事情 相对论 多线程 多进程 协程 异步的程序 宏观角度:异步 并发聊天 阻塞IO 阻塞IO的问题 一旦阻塞就不能做其他 ...

  9. TCP非阻塞accept和非阻塞connect

    http://blog.chinaunix.net/uid-20751538-id-238260.html 非阻塞accept     当一个已完成的连接准备好被accept的时候,select会把监 ...

随机推荐

  1. 《java入门第一季》之面向对象(继承)

    /* 继承的注意事项: A:子类只能继承父类所有(非私有)的成员(成员方法和成员变量),私有的变量和方法没法继承 B:子类(不能)继承父类的(构造方法),但是可以通过super关键字去访问父类构造方法 ...

  2. 【面试笔试算法】Problem 9: 腾讯2016年研发实习笔试题:最长回文子串

    (一)题目 问题:求给定字符串s的回文(palindrome)子串中,长度最大的回文子串的长度. 回文(palindrome)是指从左往右读和从右往左读字符串,看到的字符串都是一样的.比如" ...

  3. Android 常用的ORM框架详解

    1. OrmLite OrmLite 不是 Android 平台专用的ORM框架,它是Java ORM.支持JDBC连接,Spring以及Android平台.语法中广泛使用了注解(Annotation ...

  4. Java-ServletRequestEvent-ServletRequestAttributeEvent

    /** * Events of this kind indicate lifecycle * events for a ServletRequest. * The source of the even ...

  5. Android服务器——TomCat服务器的搭建

    Android服务器--TomCat服务器的搭建 作为一个开发人员,当然是需要自己调试一些程序的,这个时候本地的服务器就十分方便了,一般都会使用TomCat或者IIS服务器,IIS就比较简单了,其实t ...

  6. 色彩转换——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 ...

  7. zookeeper 应用开发

    由于zookeeper的client只有zookeeper一个对象,使用也比较简单,所以就不许要文字说明了,在代码中注释下就ok 了. 1.测试用的main方法 package ClientExamp ...

  8. HBase数据字典

    数据字典用来存储了系统的元数据.HBase的元数据包括:用户表的定义.表的切分方案.分片的分布情况(即分片分布在哪个regionserver上).分片对应的数据文件和日志文件.其中,分片和数据文件的映 ...

  9. SQLSERVER 执行过的语句查询

    total_worker_time AS [总消耗CPU 时间(ms)], execution_count [运行次数], qs.total_worker_time AS [平均消耗CPU 时间(ms ...

  10. python--Numpy and Pandas 基本语法

    numpy和pandas是python进行数据分析的非常简洁方便的工具,话不多说,下面先简单介绍一些关于他们入门的一些知识.下面我尽量通过一些简单的代码来解释一下他们该怎么使用.以下内容并不是系统的知 ...