この方法では、通常接続が完了していれば、送受信可能ですが、接続が完了していなければ、送受信は出来ないといった状態を知る事が出来ず、様々な問題があります。
そこで、ノンブロッキングの接続を行う場合は、大抵 Select (ソケットの状態を知る命令)と同時に使用します。
(通常 Select は、ブロッキング送受信で使用する)
ノンブロッキングを利用したタイムアウト付接続のサンプルソース
#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;
}