0

クライアント ソケット プログラムをネイティブ コードで記述し、Android アプリケーションで使用しています。サーバーが利用できないときにサーバーに接続するときに、1 つの奇妙な問題に直面しています。

サーバーが利用できない場合、クライアント側の connect() 呼び出しはトスになり、まったく出てきません。これについてネットで調べてみました。いくつかのリンクはこれらの手順を説明していました

  1. ソケットを非ブロックモードに設定
  2. 接続の呼び出し - 接続が成功した場合
  3. それ以外の場合は、ソケットをブロック モードに戻します。
  4. 書き込みセット用のソケットを設定し、必要なタイムアウトで select() に渡します。
  5. ソケットが書き込みセットに設定された状態で選択が出た場合、接続は成功するか、接続は失敗します。

これらの手順を試しましたが、サーバーが実行されているかどうかに関係なく、select() 呼び出しは常にタイムアウトのみで発生します。この問題を解決するにはあなたの助けが必要です。

これが私が使用しているコードの一部です

bool SocketConnect()
{
   ... Creating the socket ....

   int opts;
   if( (opts = fcntl(clientsocket,F_GETFL) < 0 )
   {
       return false;
   }

   // setting socket to non-block mode
   if( fcntl(clientsocket,opts | O_NONBLOCK) < 0 )
   {
      return false;
   }

   //calling connect
   int ret = connect(clientsocket,(const sockaddr*)&serveraddr,sizeof(serveraddr));
   if( ret < 0 )
   {
       if( errno != EINPROGRESS )
       {
          return false;
       }
   }

   if( ret == 0 )
   {
      //connection successful set the socket to block mode
      fcntl(clientsocket,F_SETFL,opts);
      return true;
   }

   //set the socket to block mode
   if( fcntl(clientsocket,F_SETFL,opts) < 0 )
   {
      return false;
   }

   fd_set writeset;
   FD_ZERO(&writeset);
   FD_SET(clientsocket,&writeset);

   timeval val.
   val.tv_sec = 5;
   val.tv_usec = 0;

   int sret = select(clientsocket+1,NULL,&writeset,NULL,&val);
   if( sret > 0 )
   {
      if( FD_ISSET(clientsocket,&writeset) )
      {
          fcntl(clientsocket,F_SETFL,opts);
          return true;
      }
   }

   return false;
}

ブロックされた接続呼び出しを使用すると(上記の手順を使用せずに)サーバーが使用可能な場合、接続を確立するのに1秒もかかりません。

上記の手順を使用して接続を行うとサーバーが利用可能になり、接続が確立されない5秒の時間を与えるとイベントが発生します。イベント選択も5秒待たず、すぐに出て値0を返しました。

このコードを確認して、connection() 呼び出しのタイムアウトを設定する際にどこが間違っているのか教えてください..

達成するための提案や代替方法は大歓迎です。

ありがとうございました。

4

2 に答える 2

0

アラームを使用して接続を中断します。ここにコード例があります

#define CONNECT_TIMEOUT 4

static void AlarmHandler(int sig)
{
sTimeout = 1; 
}
.
.
.
signal(SIGALRM, AlarmHandler); 
sTimeout = 0; 
alarm(CONNECT_TIMEOUT); 
if ( connect(sock, (struct sockaddr *) &server, sizeof(server)) ) 
{ 
if ( sTimeout ) {
NSLog(@"timeout connecting stream socket"); //If connect will remain blocked for 4 seconds after 4 seconds this condition will be triggered
}
}
于 2014-04-17T11:18:47.797 に答える
0

非ブロッキング モードの場合、接続の完了を待っている場所がわかりません。

また、接続が確立される前にアプリが行うべきことが他にあるかどうかを尋ねますか? もしそうなら、pthreads のようなものを使用して、SocketConnect 関数を別のスレッドに再構築することを検討します。アプリの動作がクライアント接続のみに依存する場合は、接続の前にソケットを非ブロックからブロックに切り替え、接続の呼び出しを SocketConnect に保持することを検討します。

于 2012-10-10T10:31:17.743 に答える