6

特定のタイプのネットワーク マルチメディア デバイス用に一種の IP ファインダーを実装しています。LAN 内のそのタイプのすべての動作中のデバイスを、その IP アドレスやその他の詳細とともに見つけたいと考えています。

デバイスには、デバイス検出の独自の方法があります。

次のように動作します。クライアントは、UDP 経由で LAN 経由でブロードキャスト要求を送信します。
宛先ポート番号は固定です。
応答として、この要求の形式を理解する LAN 内のすべてのサーバーが、この要求に応答して、自身に関する情報を提供します。

sendto() を使用して UDP 要求メッセージをブロードキャストしています。

ここでの問題は、要求に応答するデバイス (すなわちサーバー) の数がわからないことです。

recvfrom() を何回呼び出す必要がありますか?
すべてのデバイスからの応答を処理したことはいつわかりますか?
または、一般的に、recvfrom() は複数のサーバーから応答を受信するための正しい選択ですか?
同じことを達成するためのより良い(またはここで間違っている場合は正しい)方法はありますか?

私は C/C++ でプログラミングしており、Windows と Linux の両方でコーディングする予定です。
よろしくお願いします。

編集:ここにいるすべてのネットワークプログラミングウィザードの助けを借りて、私は私の問題の解決策を見つけました:)
select()は私にとってまさにものです...
時間を割いて助けてくれた皆さんに感謝します自分

4

4 に答える 4

2

recvfrom()を何回呼び出す必要がありますか?すべてのデバイス/サーバーからの応答を処理したことがいつわかりますか?

デバイス/サーバーの数がわからない場合は、何回電話をかける必要があるrecvfrom()か、またはすべての応答をいつ処理したかを知ることはできません。

select()ループ(タイムアウトまで)をrecvfrom()使用して、データが読み取り可能になったときに呼び出すことを検討してください。これは、メインスレッドまたは別のスレッドにある可能性があります。

データが処理できるよりも早く到着すると、データグラムが失われます。これは、データが受信された後に解析および保存される速度に大きく依存します。データの処理が集中的な操作である場合は、別のスレッドで処理を実行するか、受信ループがタイムアウトするまでデータを保存してから処理を続行する必要がある場合があります。

UDPは信頼性が低いため、数回再ブロードキャストするためのループは、損失の一部を説明するのに役立ち、処理は重複を説明する必要があります。

次の擬似コードは、私が問題に取り組む方法です。


/* get socket to receive responses */
sd = socket( ... );

do
{
    /* set receive timeout */
    timeout.tv_sec = 5;     

    /* broadcast request */
    sendto( ... );

    /* wait for responses (or timeout) */
    while(select(sd+1, &readfds, NULL, NULL, &timeout) > 0)
    {
        /* receive the response */
        recvfrom( ... );

        /* process the response (or queue for another thread / later processing) */
        ...

        /* reset receive timeout */
        timeout.tv_sec = 5; 
    }

    /* process any response queued for later (and not another thread) */

} while (necessary);

または、一般的に、recvfrom()は、複数のサーバーから応答を受信するための正しい選択ですか?

recvfrom()アプリケーションが受信データの送信元アドレスを取得できるようにするため、コネクションレスモードソケットで一般的に使用されます。

于 2010-03-02T16:15:07.890 に答える
2

応答するサーバーの数がわからない場合は、recvfrom() を何回呼び出さなければならないかわかりません。おそらく、次のような適切なタイムアウトを指定した select() ループでこれを処理しますが、これは完全にテストされておらず、おそらくばかげたバグでいっぱいです。

/* create and bind socket */

fd_set fds;
struct timeval tv;

tv.tv_sec = 2; 
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(sock, &fds);
int ret;

while((ret = select(sock + 1, &fds, NULL, NULL, &tv)) > 0) {
    char buf[BUFLEN];
    struct sockaddr addr;

    if(recvfrom(sock, buf, BUFLEN, MSG_DONTWAIT, &addr, sizeof(struct sockaddr)) > 0) {
        /* handle response */
    } else {
        /* handle error */
    }        
}
if(ret < 0) {
    /* handle error */
} else {
    /* select() timed out; we're theoretically done */
}

これは、応答が 2 秒間受信されなくなるまで recvfrom() を呼び出し続けます。これはもちろん、最低 2 秒間ブロックされることを意味します。基盤となるプロトコルによっては、タイムアウトを大幅に短縮できる可能性があります。実際、各応答でそれを減らすことができます。最適な構成を見つけるには、いくつかのテストと調整が必要になります。サーバーが同時に応答することを心配する必要はありません。イーサネット層がそれを処理します。

于 2010-03-02T16:52:25.793 に答える
2

ループ内でタイムアウトを指定して を使用select(2)/poll(2)し、デバイスから応答を受け取るたびにタイムアウトを減らします。自分で適切なタイムアウトを考え出す必要があります。

または、検出応答メッセージを認識/解析できる場合は、そのようなメッセージを受信したときにデバイスをリストに追加します。

デバイスが登録されたが、後で失敗する場合は、おそらくタイムアウトに対処する必要があります。

于 2010-03-02T16:49:05.537 に答える
0

あなたは知ることができません。それはわかりません。

おそらく、あなたの説明:I want to find out all the alive devicesから、デバイスは必要に応じていつでもデッドからアライブに移行でき、また元に戻ることができます。これは、継続的にポーリングする必要があることを意味します。つまり、ブロードキャスト リクエストを数秒おきに (ただしそれほど頻繁ではありません) 送信し、誰が応答するかを確認します。

私がこれを正しく理解していれば、UDP は本質的に信頼性が低く、UDP の上に信頼性を後付けする必要があります。

  • デバイスは毎回ブロードキャストを受信するとは限らないため、数秒ごとにブロードキャストを送信します。
  • 返信は届かないかもしれませんが、次回は届くかもしれません。
  • 応答は、デバイスが有効であることを確認します。
  • デバイスが死んでいると宣言する前に、「n」回の無応答を待ちます。

可能なデバイスの最大数を知っていますか? その場合、recvfrom() を何回も呼び出さなければならないことに気付くかもしれません。

于 2010-03-02T19:14:29.920 に答える