0

私はネットワーク クラスの Go Back N プロトコルを実装しています。WaitForSingleObject を使用して、受信スレッドのソケットにデータが含まれていることを認識しています。

int result = WaitForSingleObject(dataReady, INFINITE);

Go Back N の場合、一度に複数のパケットを受信者に送信し、データを操作してから、ACK パケットを送信者に送り返す必要があります。ACK を送信するたびにインクリメントする変数 expectedSEQ があるので、パケットが順不同で到着したかどうかがわかります。

ただし、最初のパケットが到着すると、デバッガーは expectedSEQ がインクリメントされていることを通知しますが、次のパケットが操作されているとき、expectedSEQ は元の値のままです。

なぜこれが起こっているのか誰にも分かりますか?if文をそのまま入れたら

if(recvHeader->seq == expectedSeq+1)

2 番目のパケットは正しく登録され、ack を送信します。明らかに、これは 2 tho を超えるパケットの量に対しては機能しません。

セクション全体 (元の WaitForSingleObject を含む) をセマフォでラップして、変数がインクリメントされるまですべてを待機させようとしましたが、これも機能しませんでした。

ご協力いただきありがとうございます!

エリック

リクエストごと: もっとコードを!

WaitForSingleObject(semaphore, INFINITE);
int result = WaitForSingleObject(dataReady, timeout);
if(result == WAIT_TIMEOUT)
   rp->m->printf("Receiver:\tThe packet was lost on the network.\n");
else {
  int bytes = recvfrom(sock, recv_buf, MAX_PKT_SIZE, 0, 0, 0);
  if(bytes > 0) {
   rp->m->printf("Receiver:\tPacket Received\n");
   if(recvHeader->syn == 1 && recvHeader->win > 0)
       windowSize = recvHeader->win;

   //FORMER BUG: (recvHeader->syn == 1 ? expectedSeq = recvHeader->seq : expectedSeq = 0);
   if(recvHeader->syn)
      expectedSeq = recvHeader->seq;
   switch(rp->protocol) {
      case RDT3:
         ...
      break;
      case GBN:
         if(recvHeader->seq == expectedSeq) {
            GBNlastACK = expectedACK;
            //Setup sendHeader for the protocol
            sendHeader->ack = recvHeader->seq;
            ...
            sendto(sock, send_buf, sizeof(send_buf), 0, (struct sockaddr*) &send_addr, sizeof(struct sockaddr_in));
            if(sendHeader->syn == 0) { //make sure its not the first SYN connection packet
               WaitForSingleObject(mutex, INFINITE);
               expectedSeq++;
               ReleaseMutex(mutex);
               if(recvHeader->fin) {
                  fin = true;
                  rp->m->printf("Receiver:\tFin packet has been received. SendingOK\n");
               }          
            }
         }
    break;
    }//end switch
}
4

2 に答える 2

0

正確にどのように、いつインクリメントしますexpectedSeqか? メモリ バリアの問題が関係している可能性があるためexpectedSeq、クリティカル セクション内にアクセスする (または他の同期オブジェクトによって保護されている) か、InterlockedAPI を使用して変数にアクセスする必要がある場合があります。

たとえば、コンパイラが の値をexpectedSeqレジスタにキャッシュしている可能性があるため、コードの重要な領域でそれが発生するのを防ぐために、同期 API が必要になる場合があります。volatileキーワードを使用すると役立つように見えるかもしれませんが、おそらく完全には十分ではないことに注意してください(ただし、Microsoft のコンパイラはvolatileオブジェクトを処理するときに完全なメモリ バリアを使用するため、MSVC の場合はそうなる可能性があります)。

正確にどのように処理しているかを示すコードをさらに投稿する必要があると思いますexpectedSeq

于 2010-10-25T17:28:27.250 に答える
0

コードを入力しているときに (私のコードは別のコンピューターにあったため、手で入力していました)、expectedSeq の元の値を設定していたときに、非常にばかげたバグに気付きました。パケットを通過するたびに0に設定していました。

午前 5 時までコーディングしているときに出てくるコードを気に入らなければなりません。

于 2010-10-25T17:56:13.210 に答える