首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 系统运维 >

非堵塞connect

2013-10-10 
非阻塞connect通常的socket描述符是阻塞式的,connect连接时可能出现长时间没有连接成功的情形,若将socket

非阻塞connect

通常的socket描述符是阻塞式的,connect连接时可能出现长时间没有连接成功的情形,若将socket描述符设置为非阻塞,那么调用connect后三次握手还可能没有完全建立connect立即返回EINPROGRESS,这个过程中可以设置超时等待或者做其它的事情。

非阻塞式有3种用途:

       1.三次握手同时做其他的处理。connect要花一个往返时间完成,从几毫秒的局域网到几百毫秒或几秒的广域网。这段时间可能有一些其他的处理要执行,比如数据准备,预处理等。
  2.用这种技术建立多个连接。这在web浏览器中很普遍.
  3.由于程序用select等待连接完成,可以设置一个select等待时间限制,从而缩短connect超时时间。多数实现中,connect的超时时间在75秒到几分钟之间。有时程序希望在等待一定时间内结束,使用非阻塞connect可以防止阻塞75秒,在多线程网络编程中,尤其必要。 例如有一个通过建立线程与其他主机进行socket通信的应用程序,如果建立的线程使用阻塞connect与远程通信,当有几百个线程并发的时候,由于网络延迟而全部阻塞,阻塞的线程不会释放系统的资源,同一时刻阻塞线程超过一定数量时候,系统就不再允许建立新的线程(每个进程由于进程空间的原因能产生的线程有限),如果使用非阻塞的connect,连接失败使用select等待很短时间,如果还没有连接后,线程立刻结束释放资源,防止大量线程阻塞而使程序崩溃。

非阻塞式connect的实现方式:客户端发起对服务器的socket的连接请求(connect调用,如果客户端socket描述符为阻塞模式则会一直阻塞到连接建立或者连接失败,注意阻塞模式的超时时间可能为75秒到几分钟之间),而如果为非阻塞模式,则调用connect之后如果连接不能马上建立则返回-1(errno设置为EINPROGRESS,注意连接也可能马上建立成功比如连接本机的服务器进程),如果没有马上建立返回,此时TCP的三路握手动作在背后继续,而程序可以做其他的东西,然后调用select检测非阻塞connect是否完成(此时可以指定select的超时时间,这个超时时间可以设置为比connect的超时时间短),如果select超时则关闭socket,然后可以尝试创建新的socket重新连接,如果select返回非阻塞socket描述符可写则表明连接建立成功。给出一个实例:

客户端非阻塞connect代码:

#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<assert.h>#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<errno.h>#include<string.h>#include<iostream>#define BUF_SIZE 1024using namespace std;int main(int argc,char* argv[]){    if(argc<=2){        cout<<"argc<=2"<<endl;        return 1;    }    const char* ip=argv[1];    int port=atoi(argv[2]);    struct sockaddr_in address;    bzero(&address,sizeof(address));    address.sin_family=AF_INET;    inet_pton(AF_INET,ip,&address.sin_addr);    address.sin_port=htons(port);    int sock=socket(PF_INET,SOCK_STREAM,0);    assert(sock>=0);    int ret=bind(sock,(struct sockaddr*)&address,sizeof(address));    assert(ret!=-1);    ret=listen(sock,5);    assert(ret!=-1);    struct sockaddr_in client;    socklen_t client_addrlength=sizeof(client);    int connfd=accept(sock,(struct sockaddr*)&client,&client_addrlength);    if(connfd<0){        cout<<"errno is:"<<errno<<endl;    }    else{        char buf[BUF_SIZE];        memset(buf,'\0',BUF_SIZE);        ret=recv(connfd,buf,BUF_SIZE-1,0);        cout<<buf<<endl;        close(connfd);    }    close(sock);    return 0;}



热点排行