TCP/IP Connect時間自主設定

2679 ワード

最近私の担当する制御システムはクライアントとして、遠端のUIはサーバーとして、起動する時、もしサーバーの起動が遅延したら、クライアントconnectは2-3分カードができて、これはあまりよくなくて、最適化が必要で、30 s以内に完成することを要求して、多くの資料を見て、connectがわがままであることを発見して、timeoutパラメータが設定できないことを発見して、そして彼のtimeout時間は完全にシステム制御されている.そのため、ネット上で各道の大神の文章を助けて、以下の1つの比価の良い方法を得て、そのため整理して、自分のバックアップを残して、他の友达にも参考にします(多くの考えは他の人を参考にして、しかしやはり自分のオリジナルのために書いて、剽窃があれば、許してください)
ネットワークプログラミングではsocketはよく知られていますが、socketはスイートインタフェースです.スイートインタフェースプログラミングでは、タイムアウトの概念といえば、送信タイムアウト、受信タイムアウト、selectタイムアウトの3つが考えられます.このタイムアウトは私たちが設定しません.しかし、通常はこのタイムアウトが長く、connectはまたブロック方法で、1つのホストが接続できないので、connectが戻ってくるのを待っていても我慢できます.あなたのプログラムが複数のホストに接続しようとすると、接続できない複数のホストに遭遇すると、耐えられません.本文はすでにLinuxの下のプログラムを例にしていますが、Windowsを手に入れる方法も同じで、いくつかの関数の名前を変えるにすぎません.
1.まずioctlを呼び出しフラグビットをNon-blockingモードに設定し、非ブロックモードでconnect関数を呼び出す準備をする
2.connectを呼び出します.TCPが3回握手するのに時間がかかるため、ブロックするのではなく、すぐに接続を完了できないとすぐにエラーが返されるので、ここではEINPROGRESSに戻り、接続を確立しているがまだ完了していないことを示します.
3.リードソケット記述子セット(fd_set rset)およびライトソケット記述子セット(fd_set wset)において、現在のソケットをセット(FD_ZERO()、FD_SET()マクロを設定し、タイムアウト時間(struct timeval*timeout)を設定します.
4.select(socket,&rset,&wset,NULL,timeout)を呼び出してconnectタイムアウトを0に戻します
もしあなたが設定したタイムアウト時間が75秒より大きい場合(ほとんどのシステムがこのtimeout時間であることが調査されている)は、カーネルにconnectにタイムアウト制限があるのは75秒だから、そうする必要はありません.Linuxでconnectにタイムアウトを設定するには、2つの方法があるはずです.一つはこのシステムのいくつかのパラメータで、この方法は私が言わないで、私がはっきり言えないためです:P、それはプログラミングで実現したのではありません.もう一つの方法はconnectのタイムアウトを実現することです原理的には、1.socketを確立する2.このsocketを非ブロックモードに設定する3.connect()を呼び出す4.このsocket記述子が書き込み可能かどうかをselect()を使用してチェックする5.select()から返された結果からconnect()結果を判断する6.socketをブロックモードに設定する(プログラムがブロックモードを使う必要がなければ、このステップは省けますが、一般的にはブロックモードを使うので、管理も容易です)
#include 
#include 
#include 
#define TIME_OUT_TIME 30
int connect_with_cust_timeout(int sockfd) {
    int error=-1, len;
    len = sizeof(int);
    timeval tm;
    fd_set set;
    unsigned long ul = 1;
    ioctl(sockfd, FIONBIO, &ul); //        
    bool ret = false;
    if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
        tm.tv_sec = TIME_OUT_TIME;   //  timeout  30s
        tm.tv_usec = 0;
        FD_ZERO(&set);
        FD_SET(sockfd, &set);
        if(select(sockfd+1, NULL, &set, NULL, &tm) > 0)
        {
            //    sockfd    , SO_ERROR
            getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);
            if(error == 0)
                ret = true;
            else
                ret = false;
        } else
            ret = false;
    } else {
        ret = true;
    }
    ul = 0;
    ioctl(sockfd, FIONBIO, &ul); //       
    return ret;
}