回去N比选择性重复

时间:2015-03-16 09:48:51

标签: networking tcp protocols tcp-ip

是否有任何理由为什么Go Back N优先于选择性重复进行流水线错误恢复?

显然,SR在接收端需要缓冲区(大小合适),这是它唯一的弱点吗?

GBN会独占优先的任何情况吗?

1 个答案:

答案 0 :(得分:0)

我的回答可能与你的问题不太相关,但它侧重于选择性重复的接收缓冲问题。

选择性重复是处理UDP不可靠性的更加智能和有效的方法。

但前提是它的实施得很好。 如果我们很好地实现它,那么我们不需要担心接收缓冲区。

例如,如果您选择线程方式,那么将数据保存在缓冲区中非常容易。 现在,您不需要为整个早到数据制作一个缓冲区。

因此,线程方式实际上是这样的:

  1. 接收方计划转到接收数据包。
  2. 检查校验和
  3. 如果未损坏,请使用包号
  4. 检查重复
  5. 发送确认
  6. 如果它第一次发送数据包,我们将执行后续步骤,否则 DO Nothing
  7. 为此数据包创建一个。无论序列如何,我们都将平均处理每个数据包。
  8. 这个线程的功能将使用简单的信号量等待和信号机制,我们将在后面讨论。
  9. 将此数据包保存到缓冲区*,因此我们不需要为所有早到的数据包提供单个缓冲区,但我们可以为每个数据包制作不同的指针。我们稍后会讨论这个问题。
  10. 创建线程后,我们将检查此数据包编号是否仅仅是我们上次保存的数据包旁边。因此,我们可以使用packetCounter来实现此目的。
  11. 如果接下来,我们将信号(信号量[thisPacketNumber])。这将告诉该数据包的线程轮到您继续执行任务,这只是将此数据包保存到文件
  12. 如果它不是最后一个保存的数据包的下一个,我们将把它放在等待队列中,即waitingQueue[thisPacketNumber] = true;
  13. 这就是while循环部分。 我们不需要一个缓冲区来存储在它们之前的兄弟(数据包)之前到达的所有这些数据包或数据包。

    现在我们有两个挑战,一个是找到正确的 数据结构 来分别存储每个数据包,另一个是保持我们的< strong> 线程队列 流畅。

    让我们先看看第二次挑战的解决方案

    这是我们的函数,我们将为每个原始数据包传递给我们的线程。

    //this is our packetQueue
    //Each packet will be alloted one instance of this functionality using threads
    //So here, we have packetNumber of each respective packet
    //Each packet will call wait(on Its Respective Semaphore) , shown below.
    //Since we are going to initiate there respective semaphores from 0;
    //They will enter in a waiting state and will only awake after getting signal from somewhere else or another packet.
    //So As we saw in the while loop section, we are signaling the current packet if it's next to last saved packet.
    //Once this packet got signaled, it will perform it's task, i.e. saving this packet into file.
    //*****Increment the packetCounter++
    //And then check if next packet in the sequence is waiting in the queue.....
    //here we are using waitingThread[] boolean array for that purpose, you can use waitingQueue[] as it's name.
    //if yes then signal next packet.
    //And **TADA** it's done
    
    unsigned long CALLBACK packetQueue(void *pn){
    
    
            int packetNumber = (int) pn;
            wait(packet[packetNumber]);
    
            char *dt = dataBucket[packetNumber]->data;
            save_line_into_file(dt);
            waitingThread[packetNumber] = false;
            packetCounter++;
    
            if(waitingThread[packetNumber+1]){
                signal(packet[packetNumber+1]);
            }
    
    
    }
    

    类型声明在Windows和&amp; Linux操作系统。 这个适用于Windows。

    正如您可以在代码提供的评论中阅读它的功能,我们可以谈论下一个挑战,即第一次挑战

    用于单独保存每个数据包的数据结构。

    我们只是定义一个结构并为它指定一些内存。

    所以我们有:

    typedef struct{
        char data[200];
    } DataBuffer;
    
    DataBuffer* dataBucket[ESTIMATED_NO_OF_PACKETS];
    

    ESTIMATED_NO_OF_PACKETS可以是任意数字,具体取决于您估算的接收数据大小(无需更正),例如500

    或者我们使用像Recycler Buffer这样的东西, 通过将指针的内存保存到文件后释放它。 我们可以使用base和window方法,如:

    Set window = 100
    AND base = 0
    AND ESTIMATED_NO_OF_PACKETS = 100;
    

    成功保存100个数据包后,使base = 100 所以我们可以像缓冲区*dataBucket[base+thisPacketNumber];

    那样访问缓冲区中的数据

    在每次保存操作后,不要忘记释放每个指针的内存。

    所以最后这就是我们原始数据包处理部分的样子:

    //After sending ACK of this packet
    //We can check if this is duplicate packet or not
                //if(original){...
                    //Create Semaphore for this packetThread
                    packet[packetNumber] = create(0);
    
    
                    //Create Thread for this packet
                    //We gonna treat each request equally
                    //that's why we are putting each thread in queue.
                    //And a dataBucket Structure to pass parameters to thread
    
    
                    dataBucket[packetNumber]  = (DataBuffer*)malloc(sizeof(DataBuffer));
                    strcpy(dataBucket[packetNumber]->data, data);
    
                    CreateThread(NULL,0,packetQueue,(void *)packetNumber,0,&tid);
    
    
                    //Now check if this the next packet in queue of not.
                    //If yes then signal this packet
                    //else put it in queue
                    if((packetCounter+1) == packetNumber){
                        signal(packet[packetNumber]);
                    }else{
                        waitingThread[packetNumber] = true;
                    }
    

    此代码仅与Windows兼容,但您可以轻松地为Linux或Mac更改它们

    其他一些有用的功能:

    void wait(semaphore h) {     // wait for a semaphore
        WaitForSingleObject( h, MAXLONG);
    }
    
    void signal(semaphore h) {   // signal a semaphore
        ReleaseSemaphore(h,1,NULL);
    }
    
    semaphore create(int v) {    // create a semaphore with value v
        return CreateSemaphore(NULL,(long)v, MAXLONG, NULL);
    }   
    

    如果我忘记添加任何内容,请提供一些反馈。