LINUX忘却録-リナックス(主にdebian)の覚書や、解説を書いています。
[1]  [2
ノンブロッキングとは、ソケット(socket)の命令を、非同期で渡してプログラムに直ぐに返す方法です。
この方法では、通常接続が完了していれば、送受信可能ですが、接続が完了していなければ、送受信は出来ないといった状態を知る事が出来ず、様々な問題があります。
そこで、ノンブロッキングの接続を行う場合は、大抵 Select (ソケットの状態を知る命令)と同時に使用します。

(通常 Select は、ブロッキング送受信で使用する)

ノンブロッキングを利用したタイムアウト付接続のサンプルソース
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#define SOCKADDR_IN             struct sockaddr_in
#define SOCKET                  int
#define BUFSIZE                 8192
#define MAX_PATH                256 

int main( int argc, char *argv[] ){
    SOCKET          sock;
    SOCKADDR_IN     addr;
    char            rbuff[BUFSIZE];
    fd_set          readfds;
    fd_set          writefds;
    struct timeval  timeout;

    int             port = 23;
    int             ret;
    int             addrlen;
    int             val;
    //入力パラメータをチェック
    if( argc <=1 ) return -1;
    if( argc >2 )
            port = atoi( argv[2] );
       //ソケットを作成
        sock = socket( AF_INET, SOCK_STREAM, 0 );
        if( sock == -1 ){
                printf( "err: socket\n" );
                return -1;
        }
    //接続相手先を設定
    memset( &addr, 0, sizeof( addr ) );
    addr.sin_family = AF_INET;
    addr.sin_port = htons( port );
    addr.sin_addr.s_addr = inet_addr( argv[1] );
    //ソケットをノンブロッキングに設定
    val = 1;
    ioctl(sock, FIONBIO, &val);
    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);
    //接続のタイムアウトを5秒に設定
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;
    //指定したサーバに接続要求命令
    ret = connect( sock, (struct sockaddr *)&addr, sizeof( addr ) );

    if( ret != 0 ){
        //ノンブロッキングなので接続が完了していないので、必ずエラーになります。
        printf( "エラー(%d):%s\n", errno, strerror( errno ) );
    }
    //そこで、ソケットが受信可能な状態になれば、接続が完了または、拒否されているのでセレクトを実行
    ret = select(sock+1, &readfds, NULL, NULL, &timeout);
    if( ret == 0 ){
        //セレクトの戻り値が0の時、タイムアウト
        printf( "接続タイムアウト\n" );
    }else{
        //セレクトの対象が自分のソケットなら
        if (FD_ISSET(sock, &readfds)) {
            //受信を試してみます。(ここでは、試すだけなので0バイト受信しようとしてます)
            ret = recv( sock, rbuff, 0, 0 );
            if( ret == -1 ){
                //受信がエラーなら、接続拒否
                printf( "接続拒否(相手サーバは存在するが、指定したポートで待機していない、又は、接続が許可されていない。\n", ret );
                        }else{
                //受信成功なら、接続に成功しています。
                printf( "接続成功\n" );
            }
        }
    }
    //後処理
    close( sock );
    return 0;
}

フリーエリア
Copyright © LINUX忘却録 All Rights Reserved.