2

私は奇妙な問題に直面しています。おそらく簡単ですが、ソケットに関する知識があまりないため、役に立ちません。

私はソケットプログラムを作成しましたが、別のプログラム、つまりメイン内で独立したexeとして実行すると完全に機能します。コードでわかるように、この別のプログラムで実行すると、返されるソケット fd は常に 3 です。

同じコードをコピーして、これを独自のfdが開いている別のサーバープログラムに統合すると、選択は常に0を返します。この場合、私のプログラムで作成された fd は常に 6 です。

以下の私のプログラムを参照してください。このコードに問題はありません。これが別のサーバー内で実行された場合、select は常に 0 を返します。

プログラムに既存の UDP ソケット fd がある場合、新しい UDP ソケット fd を作成できますか? ソケット fd がプログラム内で既に開かれているのとは異なる場合に、なぜこれが起こるのですか?

なぜこれが起こっているのですか、何をすべきか、または何か指針があれば教えてください。

#define MY_TIMEOUT_S    5   
    int mySock;
    if ((mySock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("Cannot create UDP socket");
        return -1;
    }

    struct sockaddr_in myAddr;
    myAddr.sin_family       = AF_INET;
    myAddr.sin_port         = 0;
    myAddr.sin_addr.s_addr  = INADDR_ANY;
    memset(&(myAddr.sin_zero), '\0', 8);
    if (bind(mySock, (struct sockaddr*)&myAddr, 
            sizeof(struct sockaddr)) == -1) {
        perror("Cannot bind UDP socket to desired port");
        close(mySock);
        return -1;
    }

    // here send to remote target host on udp socket and port 

    char buf[MAX_UDP_PACKET_SIZE];
    struct sockaddr_in theirAddr;
    int addrLen = sizeof(struct sockaddr);

    fd_set readSet, curReadSet;
    FD_ZERO(&readSet);
    FD_SET(mySock, &readSet);
    int maxFD = mySock;
    while (true) {
        struct timeval timeOutTV = {MY_TIMEOUT_S, 0};

        memcpy(&curReadSet, &readSet, sizeof(fd_set));

        int selectRet = select(maxFD+1, &curReadSet, NULL, NULL, &timeOutTV);
        cout<<"select value =" <<selectRet<<endl;

        if (selectRet == -1) {
            if (errno == EINTR) {
                continue; // Interrupted by signal, retry
            }
            close(mySock);
            return -1;

        } else if (selectRet == 0) {
            close(mySock);
            return -1;
        }
        if (FD_ISSET(mySock, &curReadSet)) {
            int numBytes = recvfrom(mySock, buf, MAX_UDP_PACKET_SIZE, 0,
                    (struct sockaddr*)&theirAddr, (socklen_t*)&addrLen);
            if (numBytes == -1) {
                close(mySock);
            }   

        }
    }

lsof 出力からの詳細の追加

1)これは、データを送信する必要があるターゲットです sudo lsof -a -p 16061

target 16061 root 3r FIFO 0,8 0t0 153467 pipe
target 16061 root 4u IPv4 153470 0t0 UDP *:3290
target 16061 root 5u sock 0,6 0t0 153471 can't identify protocol
target 16061 root 6u IPv4 153472 0t0 TCP *:3290 (LISTEN )
ターゲット 16061 ルート 7u 生 0t0 153473 00000000:0001->00000000:0000 st=07

2)これは、別のexeで実行した場合の上記のコードです。FD = 3が正常に機能するため、メイン内で実行されるコードはこれだけです

sudo lsof -a -p 16112

myProg 16112 ルート 0u CHR 136,4 0t0 7 /dev/pts/4
myProg 16112 ルート 1u CHR 136,4 0t0 7 /dev/pts/4
myProg 16112 ルート 2u CHR 136,4 0t0 7 /dev/pts/4
myProg 16112ルート 3u IPv4 153564 0t0 UDP *:60503

3)これは、独立して動作している上記の同じコードを統合したWebサーバーですが、現在はそうではありません

これは、実行中の私のWebサーバーの出力です

webServ 18431 ルート 3u unix 0xc09f9b00 0t0 157975 ソケット
webServ 18431 ルート 4u IPv4 157976 0t0 UDP *:8080
webServ 18431 ルート 5u IPv4 157977 0t0 TCP *:8080 (リッスン)

今、私はリクエストを送信し、サーバー側で新しい統合コードが実行され、無限ループを配置し、lsof出力を表示するためだけにソケットを閉じませんでした

4) 統合後の出力

webServ 18449 ルート 3u unix 0xc09f9b00 0t0 157975 ソケット
webServ 18449 ルート 4u IPv4 157976 0t0 UDP *:8080
webServ 18449 ルート 5u IPv4 157977 0t0 TCP *:8080 (リッスン)
webServ 18449 ルート 6u IPv4 15805 U7 *4

唯一の違いは、サーバーに統合されている場合、ソケット FD が異なることです。それが唯一の違いです。

これが私の質問に答えるのに役立つことを願っています。

なぜこれが起こっているのかわかりません。助けてください

4

2 に答える 2

0

おそらく助けselectmaxFd + 1なるでしょうか?

編集:私はあなたのコードをもう一度見ました(あなたはおそらくすでに自分で解決しているでしょうが)。3つの提案があります。

まず、bindソケットを差し込むとmyAddr.sin_port0. そのため、エフェメラル ポート番号が選択されます。このポート番号は、myProg プログラムと webServ プログラムで異なります。

myProg  16112 root 3u IPv4 153564 0t0 UDP *:60503  
webServ 18449 root 6u IPv4 158389 0t0 UDP *:48057  

したがって、UDP を myProg に送信するために使用しているポート番号について、私は困惑しています。

次に、タイムアウトselectは 5 秒です。その後、ソケットを閉じて立ち去ります。ポートを開いてから 5 秒以内にパケットが受信されることをどのように確認できますか? これを確実にするために、送信プログラムは (たとえば) 4 秒以下ごとに継続的にパケットを送信しようとする必要がありますが、これは合理的ではないようです。

第三に、これはマイナーな点である可能性がありますが、次の点で問題になる可能性があります。

        if (numBytes == -1) {
            close(mySock);
        }

他の場所で使用しているを省略すると、EINTR などのエラーが返されたreturn -1;場合に無限ループに陥ります。また、ここや他の場所でrecvfrom電話をかけるのもいいでしょう。perror

最後に、コメント:

  // here send to remote target host on udp socket and port

は正しくありませ

于 2012-11-22T07:16:15.217 に答える
0

それを作る:

int maxFD = mySock + 1;

select(2)のman ページには次のように書かれています。

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

nfdsは、3 つのセットのいずれかで最大のファイル記述子に1 を加えたものです。

于 2012-11-22T07:16:28.673 に答える