2012-02-06 7 views
6

私はソケットプログラミングの初心者ですが、select()FD_SET()がどのように動作するのか理解できません。ソケットプログラミングでselectとFD_SETを使用するには?

Beejのチュートリアルの例を変更してみてみましょう。私がforループでやりたいことは、各反復で4秒待つことです。読み込みが可能な場合は、「Aキーが押されました」と表示され、タイムアウトした場合は「タイムアウト」と表示されます。それから私はセットをクリアし、プロセスを9回以上繰り返す。しかし、一旦ファイル記述子0が設定されると、FD_ZERO()および/またはFD_CLR()の呼び出しの後でも決して解除されないように見えます。言い換えれば、ループの最初の反復でキーを押すと、残りの反復のためにファイル記述子が設定され、それ以上の待機は行われません。だから私が紛失しているものがなければならないが、何がわからない。

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 

#define SERVERPORT 4950 

int main(int argc, char *argv[]) { 
    struct sockaddr_in their_addr; // connector's address information 
    struct hostent *he; 
    int numbytes; 
    int broadcast = 1; 

    if ((he=gethostbyname(argv[1])) == NULL) { // get the host info 
     perror("gethostbyname"); 
     exit(1); 
    } 

    // this call is what allows broadcast packets to be sent: 
    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, 
     sizeof broadcast) == -1) { 
     perror("setsockopt (SO_BROADCAST)"); 
     exit(1); 
    } 
    their_addr.sin_family = AF_INET;  // host byte order 
    their_addr.sin_port = htons(SERVERPORT); // short, network byte order 
    their_addr.sin_addr = *((struct in_addr *)he->h_addr); 
    memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero); 

    struct timeval tv; 
    fd_set broadcastfds; 

    int i; 
    for(i=0; i < 10; i++) { 
     tv.tv_sec = 4; 
     tv.tv_usec = 500000; 

     FD_ZERO(&broadcastfds); 
     FD_CLR(0, &broadcastfds); 
     FD_SET(0, &broadcastfds); 
     if(select(0+1, &broadcastfds, NULL, NULL, &tv) == -1) perror("select"); 

     if (FD_ISSET(0, &broadcastfds)) printf("A key was pressed!\n"); 
     else printf("Timed out.\n"); 
     fflush(stdout); 
    } 
    close(sockfd); 
    return 0; 
} 

答えて

3

FD_SETを正しく使用しています。 select()に、ファイル記述子0(標準入力)が読み込み可能になったときに通知するように要求しています。それはこれを行います。問題は、利用可能な入力を消費するために標準入力を読み取っていないことです。したがって、ループバックしてselect()を再度呼び出すと、標準入力は読み込みの準備ができており、すぐに戻ります。

(通常は良いオプションである、またはpoll()select()を使用するための正しい方法は次のとおりです。ノンブロッキングモードに関連するファイル記述子のすべてを設定し

  • 。ほとんどの使用例では、個々のファイルディスクリプタを処理しているときではなく、select()(またはpoll())のすべてのブロッキングを実行したいからです。
  • に興味がありますどのファイルディスクリプタに登録するselect()またはpoll()に引数を設定します。
  • コールselect()またはpoll()
  • 入力と書き込み出力を消費することで通知される通知に反応します。
  • ループバック2.

P.Sに進む。:あなたのUDPソケットsockfdを何ものとしなければなりませんか?あなたはそれを開きますが、それは何にも使われません。

+0

何もする必要はありません。申し訳ありませんが、私は質問のために不要な部分を取り除くという悪い仕事をしました。 – user1161604

3

問題は、ファイルディスクリプタからデータを読み取ることがないことです。

select()は、イベントではなく状態を報告します。

最初にselect()が返された後、常に読み込み可能なデータがあるため、select()は直ちにそれを報告します。

PS。あなたがそのコードを入手しようとしているとき、それは約15歳に見えます。 poll()はselect()より一般的に便利で、getaddrinfo()はgethostbyname()よりも便利です。 [そして、彼らはより良く働く]。

関連する問題