【问题标题】:Go Back N Vs. Selective Repeat返回 N VS。选择性重复
【发布时间】:2015-05-18 09:12:55
【问题描述】:

对于流水线式错误恢复,Go Back N 是否比选择性重复更受青睐?

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

在任何情况下都优先选择 GBN?

【问题讨论】:

    标签: networking tcp protocols tcp-ip


    【解决方案1】:

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

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

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

    例如如果你选择threading方式,那么将数据保存在缓冲区中是很容易的。 现在您不需要为整个早期到达的数据创建一个缓冲区。

    所以线程的方式实际上是这样的:

    1. 接收程序将接收数据包。
    2. 检查校验和
    3. 如果没有损坏,请使用数据包编号检查重复
    4. 发送 ACK
    5. 如果是第一次打包,我们将进行下一步,否则什么都不做
    6. 为此数据包创建一个线程。我们将平等地处理每个数据包,而不考虑它们的顺序。
    7. 该线程的功能将使用简单的信号量等待和信号机制,我们将在后面讨论。
    8. 将此数据包保存到缓冲区*,因此我们不需要为所有提前到达的数据包使用单个缓冲区,但我们可以为每个数据包创建不同的指针。我们稍后会讨论这个问题。
    9. 创建线程后,我们将检查此数据包编号是否就在我们上次保存的数据包旁边。所以我们可以为此目的使用packetCounter
    10. 如果只是下一个,我们将转到 signal(semaphore[thisPacketNumber])。这将告诉该数据包的线程轮到您继续执行您的任务,这只是将此数据包保存到文件
    11. 如果它不是最后一个保存的数据包,我们会将其放入等待队列中,即waitingQueue[thisPacketNumber] = true;

    这就是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 和 Linux 中可能有所不同。 这个适用于 Windows。

    您可以在随代码提供的 cmets 中阅读它的功能,我们可以讨论下一个挑战,即第一个挑战

    分别保存每个数据包的数据结构。

    我们只需定义一个结构并为其指针分配一些内存。

    所以我们有:

    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);
    }   
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 2016-05-12
      • 2016-09-10
      • 2021-09-24
      相关资源
      最近更新 更多