0

現在、tcp 接続を開くメソッドにタイムアウトを追加しようとしています。選択の代わりに使用しようとしていることを除いて、ここにあるガイドを大まかに使用しています。ただし、接続が開いていなくても、fdの書き込み準備ができていることを通知するpoll()呼び出しがすぐに返されます。poll()これは、私が作成した縮小コードの例です。

#include <cstring>
#include <poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <iostream>
#include <cstdlib>

int main() {
   struct addrinfo hints;

   ::memset( &hints, 0, sizeof( hints ) );
   hints.ai_socktype = 0;
   hints.ai_family = AF_UNSPEC;
   hints.ai_protocol = 0;
   hints.ai_flags = AI_CANONNAME;


   struct addrinfo * info;

   if( ::getaddrinfo( "127.0.0.1", "49999", &hints, &info ) != 0 ) {
      std::cerr << "Error: getaddrinfo" << std::endl;
      exit( 1 );
   }


   int soc;

   if( (soc = ::socket( info->ai_family, info->ai_socktype, info->ai_protocol ) ) < 0 ) {
      std::cerr << "Erorr: socket" << std::endl;
   }

   // Set mode to non-blocking for timeout handling
   int arg;
   if( (arg = ::fcntl( soc, F_GETFL, 0 )) < 0 ) {
      std::cerr << "Error: fcntl" << std::endl;
      exit( 1 );
   }

   arg |= O_NONBLOCK;
   if( ::fcntl(soc, F_SETFL, arg) < 0) {
      std::cerr << "Error: fcntl" << std::endl;
      exit( 1 );
   }

   int res = ::connect(soc,info->ai_addr,info->ai_addrlen);

   if( (res != 0) && (errno != EINPROGRESS) ) {
      std::cerr << "Error: connect" << std::endl;
      exit( 1 );
   }

   pollfd pfd;
   pfd.fd = soc;
   pfd.events = POLLOUT;

   res = ::poll( &pfd, 1, 50000 );

   if( res < 0 ) {
      std::cerr << "Error: poll" << std::endl;
      exit( 1 );
   }
   else if( res == 0 ) {
      std::cerr << "Error: poll" << std::endl;
      exit( 1 );
   }

   // Set blocking mode again
   if( (arg = ::fcntl(soc, F_GETFL, NULL)) < 0) {
      std::cerr << "Error: fcntl" << std::endl;
      exit( 1 );
   }
   arg &= (~O_NONBLOCK);
   if( ::fcntl(soc, F_SETFL, arg) < 0) {
      std::cerr << "Error: fcntl" << std::endl;
      exit( 1 );
   }

   return 0;
}

49999私のマシンではポートが閉じられているため、エラーが発生することが予想されます。代わりに、プログラムは の戻り値で終了します0

上記のリンクにある選択の例も使用しようとしました。への呼び出しを完全な例に置き換えるとpoll()、次のエラー メッセージが表示されます。

Operation now in progress: Operation now in progres

select を使用してコードを削減しようとしましたが、削減すると正しいconnection refused message.

編集

注:「操作が進行中です」というメッセージは、私の側のエラー処理コードのエラーが原因でした。これを修正すると、「getsockopt()」から正しいエラー メッセージが表示されました。これは、この例を縮小できなかった理由も説明しています。

4

2 に答える 2

1

接続が成功しなかった場合にのみ、ポーリングを行う必要があります。通常、「localhost」に接続するとすぐに成功します。

于 2013-04-17T21:56:18.070 に答える
0

問題は、行方不明のgetsockopt()呼び出しにありました。poll()成功しない場合はエラーが返されると想定しconnect()ていましたが、状態が判断できるとすぐに通過します。getsockopt()例から呼び出しを追加すると、問題なく機能しました。

poll を使用した (あまりクリーンではない) コード例を次に示します。

#include <cstring>
#include <poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <iostream>
#include <cstdlib>
#include <cstdio>

int main() {
   struct addrinfo hints;

   ::memset( &hints, 0, sizeof( hints ) );
   hints.ai_socktype = 0;
   hints.ai_family = AF_UNSPEC;
   hints.ai_protocol = 0;
   hints.ai_flags = AI_CANONNAME;


   struct addrinfo * info;

   if( ::getaddrinfo( "127.0.0.1", "49999", &hints, &info ) != 0 ) {
      std::cerr << "Error: getaddrinfo" << std::endl;
      exit( 1 );
   }


   int soc;

   if( (soc = ::socket( info->ai_family, info->ai_socktype, info->ai_protocol ) ) < 0 ) {
      std::cerr << "Erorr: socket" << std::endl;
   }

   // Set mode to non-blocking for timeout handling
   int arg;
   if( (arg = ::fcntl( soc, F_GETFL, 0 )) < 0 ) {
      std::cerr << "Error: fcntl" << std::endl;
      exit( 1 );
   }

   arg |= O_NONBLOCK;
   if( ::fcntl(soc, F_SETFL, arg) < 0) {
      std::cerr << "Error: fcntl" << std::endl;
      exit( 1 );
   }

   int res = ::connect(soc,info->ai_addr,info->ai_addrlen);

   if( res < 0 ) {
      if( errno == EINPROGRESS ) {
         pollfd pfd;
         pfd.fd = soc;
         pfd.events = POLLOUT;

         std::cout << "Polling" << std::endl;
         res = ::poll( &pfd, 1, 50000 );

         if( res < 0 ) {
            std::cerr << "Error: poll" << std::endl;
            exit( 1 );
         }
         else if( res == 0 ) {
            std::cerr << "Error: poll" << std::endl;
            exit( 1 );
         } else {
            socklen_t lon = sizeof(int);
            int valopt;
            if (getsockopt(soc, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) {
               fprintf(stderr, "Error in getsockopt() %d - %s\n", errno, strerror(errno));
               exit(0);
            }
            // Check the value returned...
            if (valopt) {
               fprintf(stderr, "Error in delayed connection() %d - %s\n", valopt, strerror(valopt));
               exit(0);
            }
         }
      }
      else {
         std::cerr << "Error: connect" << std::endl;
         exit( 1 );
      }
   }

   // Set blocking mode again
   if( (arg = ::fcntl(soc, F_GETFL, NULL)) < 0) {
      std::cerr << "Error: fcntl" << std::endl;
      exit( 1 );
   }
   arg &= (~O_NONBLOCK);
   if( ::fcntl(soc, F_SETFL, arg) < 0) {
      std::cerr << "Error: fcntl" << std::endl;
      exit( 1 );
   }

   return 0;
}
于 2013-04-18T09:57:51.143 に答える