鍍金池/ 問答/C  HTML/ TCP RDT 3.0 停等協(xié)議的模擬(失敗了?。。。?/span>

TCP RDT 3.0 停等協(xié)議的模擬(失敗了?。。。?/h1>

說明

這是一份關(guān)于大學(xué)計算機網(wǎng)絡(luò)的作業(yè),作業(yè)要求是根據(jù)rdt 3.0 協(xié)議 實現(xiàn)一個可靠傳輸?shù)哪M程序,程序是老師給好的,當(dāng)然這個程序是不全的,需要自己去修改完善。需要改動的代碼文件是altbit.c,其他的文件都是正確的

程序會有四個測試來檢驗程序是否完成,我已經(jīng)通過3個測試,其中有一個測試沒有被通過,百思不得其解,希望路過的大神幫我瞅兩眼,大恩大德,來世再報。

信息量有點大。。。

具體內(nèi)容如下(原文是英文,自己翻譯的不好):

背景

You've been hired by "Net Source", a company specialising in networking software. Their programmer, Mue, who was working on an implementation of the Alternating Bit protocol has caught the flu and the implementation must absolutely be finished in the next week. Most of the implementation is complete and Mue left comments for parts still to be completed. As the code isn't finished, Mue hasn't completed testing yet.
Mue is an experienced C programmer and there is nothing wrong with the C syntax or structure of the code that Mue has written. So you don't have to correct any C syntax errors, your job is to finish the code, correct any protocol errors and test it. Your boss realises you're not a C expert, but at least you've programmed in some language with C like syntax (e.g. Java, C++) before so you're the closest they have as an expert. Mue has written a C hints for programmers of C like languages programmers sheet which explains what you need to know about C that is different than Java. She's confident that if you stick to the sheet, anything else you need to add or change would be the same if you wrote it in Java.

你已經(jīng)被一家專門從事網(wǎng)絡(luò)軟件的公司聘用了。他們的程序員,Mue,致力于實現(xiàn)一個比特交替協(xié)議,他已經(jīng)感染了流感,并且必須在下周完成。大部分的實現(xiàn)都是完整的,Mue留下了一些有待完成的部分。由于代碼還沒有完成,Mue還沒有完成測試。Mue是一個經(jīng)驗豐富的C語言程序員,并且他已經(jīng)寫的代碼沒有任何語法或則結(jié)構(gòu)錯誤。所以你不需要修改任何C語法錯誤,你的工作就是完成代碼,糾正一些協(xié)議錯誤并且完成測試,你的老板意識到你不是一個有經(jīng)驗的C語言專家,但是至少之前你已經(jīng)使用過一些類似C語言語法(例如java,c++)的語言,所以你是他們最接近的專家,Mue已經(jīng)寫了一篇 《C hints for programmers of C like languages programmers》說明了你需要了解一些關(guān)于C與Java相比的不同,他相信你在寫java時,如果你按照手冊/文檔的說明去做,無論你添加還是修改代碼,都是類似的情況

【這里提到的《C hints for programmers of C like languages programmers》我就不放上來,我覺得c語言應(yīng)該是必須掌握的】

The testing system 測試系統(tǒng)

To help isolate and demonstrate the behaviour of the sender and receiver, you have a simulation system at your disposal. The overall structure of the environment is shown below:

為了幫助隔離和演示發(fā)送方和接收方的行為,您可以使用一個模擬系統(tǒng)。環(huán)境的總體結(jié)構(gòu)如下所示

圖片描述

There are two hosts (A and B). An application on host A is sending messages to an application on host B.
The application messages (layer 5) on host A are sent to layer 4 (transport) on host A, which implements Alternating Bit for reliable delivery. Layer 4 creates packets and sends them to the network (layer 3). The network transfers (unreliably) these packets to host B where they are handed to the transport layer (Alternating Bit receiver) and if not corrupt or out of order, the message is extracted and delivered to the receiving application (layer 5) on host B.

有兩臺主機(A和B)。一個應(yīng)用程序在主機A上發(fā)信息給在主機B上的應(yīng)用程序。主機A上的應(yīng)用程序消息(第5層)被發(fā)送到主機A的第4層(傳輸),它實現(xiàn)了交替的比特來進行可靠的交付。4創(chuàng)建數(shù)據(jù)包并將它們發(fā)送給網(wǎng)絡(luò)層(第三層)。網(wǎng)絡(luò)傳輸(不可靠)這些包給主機B傳輸層(交替接收器),如果不是損壞的或次序混亂的,信息將被提取并交付給在主機B(5層)上的接收應(yīng)用程序。

Mue has supplied the code for the Alternating Bit sender procedures A_output(), A_init(), A_input(), and A_timerinterrupt(). She has also written the code for the Alternating Bit receiver procedures B_input() and B_init(). At this stage, only unidirectional transfer of data (from A to B) is required, so B does not need to implement B_timerinterrupt or B_output. Of course, B will have to send ACK packets to A to acknowledge receipt of data.

Mue提供了比特交替發(fā)送器程序A_output()、A_init()、A_input()和A_timerinterrupt()的代碼。她還編寫了比特交替接收程序B_input()和B_init()的代碼。在這個階段,只需要單向的數(shù)據(jù)傳輸(從A到B),所以B不需要實現(xiàn) B_timerinterrupt或B_output。當(dāng)然,B必須向A發(fā)送ACK數(shù)據(jù)包以確認接收到數(shù)據(jù)。

The routines are detailed below. Such procedures in real-life would be part of the operating system, and would be called by other procedures in the operating system. In the simulator the simulator will call and be called by procedures that emulate the network environment and operating system.

例程如下所示。在現(xiàn)實生活中,這樣的程序?qū)⑹遣僮飨到y(tǒng)的一部分,并且將被操作系統(tǒng)中的其他程序調(diào)用。在模擬器中,模擬器將調(diào)用并被模擬網(wǎng)絡(luò)環(huán)境和操作系統(tǒng)的過程調(diào)用。

A_output(message), where message is a structure of type struct msg, containing data to be sent to B. This routine will be called whenever the upper layer application at the sending side (A) has a message to send. It is the job of the Alternating Bit protocol to insure that the data in such a message is delivered in-order, and correctly, to the receiving side upper layer.

A_output(message), ·消息是類型struct msg的結(jié)構(gòu),包含要發(fā)送到B的數(shù)據(jù)。每當(dāng)發(fā)送端(A)上的上層應(yīng)用程序有消息要發(fā)送時,這個例程將被調(diào)用。這是比特交替協(xié)議的工作,以確保這樣一條消息中的數(shù)據(jù)按順序正確地傳遞給接收方上層。

A_input(packet), where packet is a structure of type struct pkt . This routine will be called whenever a packet sent from B (i.e., as a result of a tolayer3() being called by a B procedure) arrives at A. packet is the (possibly corrupted) packet sent from B.

A_input(packet),其中信息包是類型struct pkt的結(jié)構(gòu)。這個例程將在從B發(fā)送的數(shù)據(jù)包時被調(diào)用(例如由于一個tolayer3()被B過程調(diào)用)到達A。包是從B發(fā)送的(可能損壞的)數(shù)據(jù)包。

A_timerinterrupt() This routine will be called when A's timer expires (thus generating a timer interrupt). This routine controls the retransmission of packets. See starttimer() and stoptimer() below for how the timer is started and stopped.

A_timerinterrupt()這個例程將在A的計時器到期時調(diào)用(從而產(chǎn)生一個計時器中斷)。這個例程控制數(shù)據(jù)包的重新傳輸。請參閱下面的starttimer()和stoptimer(),了解定時器是如何啟動和停止的。

A_init() This routine will be called once, before any other A-side routines are called. It is used to do any required initialization.
A_init()這個例程將在任何其他的a例程被調(diào)用之前被調(diào)用一次。它被用來做任何必需的初始化。

B_input(packet), where packet is a structure of type struct pkt . This routine will be called whenever a packet sent from A (i.e., as a result of a tolayer3() being called by a A-side procedure) arrives at B. The packet is the (possibly corrupted) packet sent from A.

B_input(packet),其中包是類型struct pkt的結(jié)構(gòu)。這個例程將在從A發(fā)送的數(shù)據(jù)包(即:由于tolayer3()被A方程序調(diào)用)到達B的時候被調(diào)用.數(shù)據(jù)包是來自A的(可能損壞的)數(shù)據(jù)包。

B_init() This routine will be called once, before any other B-side routines are called. It is used to do any required initialization.

B_init()這個例程將在任何其他的b端例程被調(diào)用之前被調(diào)用一次。它被用來做任何必需的初始化。

The unit of data passed between the application layer and the Alternating Bit (transport layer) protocol is a message, which is declared as:

在應(yīng)用程序?qū)雍捅忍亟惶妫▊鬏攲樱﹨f(xié)議之間傳遞的數(shù)據(jù)單元是一條消息,它被聲明為:

struct msg{
    char data[20];
};
That is, data is stored in a msg structure which contains an array of 20 chars. A char is one byte. The sending entity will thus receive data in 20-byte chunks from the sending application; and the receiving entity should deliver 20-byte chunks to the receiving application.

也就是說,數(shù)據(jù)存儲在msg結(jié)構(gòu)中,其中包含20個字符數(shù)組。char是一個字節(jié)。因此,發(fā)送實體將從發(fā)送應(yīng)用程序接收20字節(jié)塊的數(shù)據(jù);接收實體應(yīng)該將20字節(jié)的塊交付給接收應(yīng)用程序。
The unit of data passed between Alternating Bit (transport layer) and the network layer is the packet, which is declared as:
在比特交替(傳輸層)和網(wǎng)絡(luò)層之間傳遞的數(shù)據(jù)單元是包,它被聲明為:

struct pkt{
    int seqnum;
    int acknum;
    int checksum;
    char payload[20];
};
The A_output routine fills in the payload field from the message data passed down from the Application layer. The other packet fields are used by the Alternating Bit protocol to insure reliable delivery, as we've seen in class.

A_output從應(yīng)用程序?qū)觽鬟f的消息數(shù)據(jù)中填充payload 字段。其他的包字段被比特交替協(xié)議使用,以確保可靠的交付,就像我們在課堂上看到的那樣。

These functions implement what the sender and receiver should do when packets arrive.

這些函數(shù)實現(xiàn)了發(fā)送方和接收方在數(shù)據(jù)包到達時應(yīng)該做的事情。

Software Interfaces 軟件界面

The procedures described above implement the Alternating Bit tranport layer protocol. The following emulator procedures are called by the Alternating Bit procedures. They are explained here so you know how they fit in. They are not part of the Alternating Bit implementation and these routines work correctly. Do not modify them:

上面描述的過程實現(xiàn)了比特替換傳輸層協(xié)議。下面的模擬器程序由比特交替程序調(diào)用。它們在這里被解釋,所以你知道它們是如何適應(yīng)的。它們不是比特實現(xiàn)的一部分,這些例程正常工作。不要修改它們:

starttimer(calling_entity,increment), where calling_entity is either A (for starting the A-side timer) or B (for starting the B side timer), and increment is a float value indicating the amount of time that will pass before the timer interrupts. A's timer should only be started (or stopped) by A-side routines, and similarly for the B-side timer. To give you an idea of the appropriate increment value to use: a packet sent into the network takes an average of 5 time units to arrive at the other side when there are no other messages in the medium. You are free to experiment with different timeout values; but when handing in for mark submission linking, the timeout value must be set to 15.0

calling_entity要么是A(用于啟動A-side定時器)或B(用于啟動B側(cè)計時器),而增量是一個浮點值,指示計時器中斷之前的時間量。A的計時器只能由A側(cè)例程啟動(或停止),而b端計時器也同樣如此。為了讓您了解適當(dāng)?shù)脑鲋祪r值:發(fā)送到網(wǎng)絡(luò)的數(shù)據(jù)包在介質(zhì)中沒有其他消息時,平均需要5個時間單位到達另一端。您可以自由地嘗試不同的超時值;但是在提交mark提交鏈接時,超時值必須設(shè)置為15.0

Note that starttimer() is not restarttimer(). If a timer is already running it must be stopped before it is started. Calling starttimer when the timer is already running, or calling stoptimer when the timer is not running, indicates an error in the protocol behaviour and will result in an error message.

請注意starttimer()不是restarttimer()。如果一個計時器已經(jīng)運行,那么它必須在啟動之前停止。當(dāng)定時器已經(jīng)運行時調(diào)用starttimer,或者在定時器沒有運行時調(diào)用stoptimer,在協(xié)議行為中指出一個錯誤,并將導(dǎo)致一條錯誤消息。

The starttimer() call should occur immediately after the tolayer3() call to send the packet being timed.

starttimer()調(diào)用應(yīng)該在tolayer3()調(diào)用之后立即發(fā)生,以發(fā)送計時的數(shù)據(jù)包。

stoptimer(calling_entity), where calling_entity is either A (for stopping the A-side timer) or B (for stopping the B side timer).

stoptimer(calling_entity),其中calling_entity 是A(用于停止A側(cè)計時器)或B(用于停止B側(cè)計時器)。

tolayer3(calling_entity,packet), where calling_entity is either A (for the A-side send) or B (for the B side send), and packet is a structure of type struct pkt. Calling this routine will cause the packet to be sent into the network, destined for the other entity.

tolayer3(calling_entity,packet),其中calling_entity要么是A(對于A端發(fā)送)要么是B(對于B端發(fā)送),packet是類型struct pkt的結(jié)構(gòu)。調(diào)用這個例程將導(dǎo)致數(shù)據(jù)包被發(fā)送到網(wǎng)絡(luò),并被發(fā)送到另一個實體。

tolayer5(calling_entity,message), where calling_entity is either A (for A-side delivery to layer 5) or B (for B-side delivery to layer 5), and message is a structure of type msg. With unidirectional data transfer, you would only be calling this with calling_entity equal to B (delivery to the B-side). Calling this routine will cause data to be passed up to layer 5.

其中calling_entity要么是A(用于向第5層交付)或B(B端交付到第5層),而消息是msg類型的結(jié)構(gòu)。有了單向的數(shù)據(jù)傳輸,您只能調(diào)用callingentity等于B(向B端交付)。調(diào)用這個例程將導(dǎo)致數(shù)據(jù)被傳遞到第5層。

The emulator code is in the file emulator.c

emulator 的代碼文件是emulator.c

The incorrect implementation of Alternating Bit is in the file altbit.c

Alternating Bit(比特交替)的實現(xiàn)代碼在文件altbit.c中

There are also two header files emulator.h and altbit.h

還有兩個頭文件是emulator.h 和altbit.h

which define the procedures and shared variables used in the program.
You should download the 4 files and examine the code in altbit.c with the description above and your knowledge of Alternating Bit and make sure you understand how the program fits together. You do not need to understand emulator.c; but if you want to know how the emulator works, you are welcome to look at the code.
To build the program use the command:

您應(yīng)該下載4個文件并檢查altbit中的代碼。用上面的描述和你對交替位的知識,確保你理解程序是如何組合在一起的。您不需要理解emulator.c;但是如果您想知道模擬器是如何工作的,歡迎您查看代碼。
要構(gòu)建程序,請使用以下命令:

gcc -ansi -Wall -pedantic emulator.c altbit.c 
The executable program will be called a.out. To run the program, type:

可執(zhí)行程序?qū)⒈环Q為a.out。要運行這個程序,輸入:

./a.out

The simulated network environment

模擬的網(wǎng)絡(luò)環(huán)境

The medium is capable of corrupting and losing packets. It will not reorder packets. When you compile and run the resulting program, you will be asked to specify values regarding the simulated network environment:

這種媒介有能力損壞和丟失數(shù)據(jù)包。它不會重新排序數(shù)據(jù)包。當(dāng)你編譯并運行結(jié)果程序時,你將被要求指定關(guān)于模擬網(wǎng)絡(luò)環(huán)境的值:

Number of messages to simulate.The emulator will stop generating messages as soon as this number of messages have been passed down from layer 5.

要模擬的消息數(shù)量。當(dāng)這些消息從第5層傳遞下來時,模擬器將停止生成消息。

Loss. You are asked to specify a packet loss probability. A value of 0.1 would mean that one in ten packets (on average) are lost.
損失。你被要求指定一個包丟失的概率。0.1的值意味著每10個包中的1個(平均)丟失。

Corruption. You are asked to specify a packet corruption probability. A value of 0.2 would mean that one in five packets (on average) are corrupted. Note that the contents of payload, sequence or ack field can be corrupted.

損壞。你被要求指定一個包的損壞概率。0.2的值意味著每5個包中就有一個(平均)被損壞。注意,有效負載、序列或ack字段的內(nèi)容可能被破壞。

Tracing. Setting a tracing value of 1 or 2 will print out useful information about what is going on inside the emulation (e.g., what's happening to packets and timers). A tracing value of 0 will turn this off. A tracing value greater than 2 will display all sorts of messages that detail what is happening inside the emulation code as well. A tracing value of 2 may be helpful to you in debugging your code. You should keep in mind that real implementors do not have underlying networks that provide such nice information about what is going to happen to their packets!

跟蹤。設(shè)置1或2的跟蹤值將打印出關(guān)于仿真中正在發(fā)生的事情的有用信息(例如,數(shù)據(jù)包和計時器發(fā)生了什么)。跟蹤值為0將關(guān)閉該值。一個大于2的跟蹤值將顯示各種消息,這些消息詳細描述了仿真代碼中發(fā)生的事情。在調(diào)試代碼時,跟蹤值2可能對您有幫助。您應(yīng)該記住,真正的實現(xiàn)者沒有底層網(wǎng)絡(luò),提供關(guān)于他們的數(shù)據(jù)包將發(fā)生什么事情的良好信息!

Average time between messages from sender's layer5. You can set this value to any non-zero, positive value. Note that the smaller the value you choose, the faster packets will be generated.

從發(fā)送者的layer5發(fā)送消息的平均時間。你可以把這個值設(shè)置成任何非零的,正的值。請注意,您選擇的值越小,就會生成更快的數(shù)據(jù)包。

Take a moment to experiment with the simulated environment and look at the events that occur. Try sending a few packets with no loss or corruption. Does the protocol work properly? Try with just loss. Try with just corruption. Some of the errors with the Alternating Bit implementation should be apparent.

花點時間來試驗一下模擬環(huán)境,看看發(fā)生的事件。試著發(fā)送一些沒有損失或損壞的包。協(xié)議是否正常工作?嘗試只有損失。比特交替協(xié)議實現(xiàn)的一些錯誤應(yīng)該是顯而易見的。

What to do 要做什么

The implementation of Alternating Bit should be identical to that described in your book (page 244/245, Extended FSM description of Alternating Bit sender and receiver are shown).

比特交替的實現(xiàn)應(yīng)該與您的書中所描述的相同(第244/245頁,擴展的FSM描述,比特交替發(fā)送者和接收方的描述)。

There may be errors in the protocol. You will need to test it. The errors are only in the altbit.c file. The other three files are correct and do not need to be modified. None of the mistakes are with the programming language or the data structures, they are all errors in the protocol behaviour. The program will compile and run as written; but the sender and receiver do not follow the Alternating Bit protocol.

在協(xié)議中可能有錯誤。你需要對它進行測試。這些錯誤只存在于altbit.c文件中。其他三個文件是正確的,不需要修改。這些錯誤都不是編程語言或數(shù)據(jù)結(jié)構(gòu)的錯誤,它們都是協(xié)議行為中的錯誤。該程序?qū)凑站帉懙姆绞竭M行編譯和運行;但是發(fā)送方和接收方不遵循比特交替協(xié)議。

This part has 4 tests which test that you have correctly finished the code. Since mark submission link will show you what should have happened if you submit an incorrect solution,there is a 1 mark penalty for each submission you make after the first. You should test and correct any errors before submission. If you rely on mark submission link to do your testing, then your mark will reflect this. However, if you are really stuck, realise that this is a small percentage of the marks for each test, and the output should help clarify any misconception. We have provided an Oracle (see details below in the Handing In section) which will tell you if you pass the tests or not; but will give you no other information. There is no mark penalty to use the Oracle.

這部分有4個測試,測試您是否正確地完成了代碼。由于mark提交鏈接將向您展示如果提交了一個不正確的解決方案,應(yīng)該發(fā)生什么,那么在第一次提交之后,每個提交的提交都將受到1個標記的懲罰。您應(yīng)該在提交之前測試并糾正任何錯誤。如果您依賴于mark提交鏈接來進行測試,那么您的標記將反映這一點。然而,如果你真的被困住了,要意識到這只是每個測試的一小部分分數(shù),而輸出應(yīng)該有助于澄清任何誤解。我們已經(jīng)提供了一個Oracle(請參閱下面的詳細信息),它將告訴您是否通過了測試;但不會給你任何其他信息。使用Oracle是沒有任何標記的。

I suggest the following strategy for this practical. In each step I'd recommend focussing on getting the receiver behaving correctly first and then turn your attention to the sender (the receiver behaviour is simpler and therefore easier to get right and test). :

我建議采取以下策略。在每一個步驟中,我建議集中于讓接收方先正確地操作,然后將注意力轉(zhuǎn)移到發(fā)送方(接收方的行為更簡單,因此更容易獲得正確和測試)。:

1.Compile the code and do a simple test sending just one packet with no corruption or loss. Does both the sender and receiver behave properly in this scenario? If not fix any problems. At this stage you should be able to pass test 1 (you can check with Oracle). If not, look at what your sender and receiver do in your test. (10 marks)

編譯代碼并做一個簡單的測試,只發(fā)送一個包,不存在任何損壞或損失。在這個場景中,發(fā)送方和接收方都表現(xiàn)得很好嗎?如果不解決任何問題。在這個階段,您應(yīng)該能夠通過測試1(您可以與Oracle進行核對【這里提到Oracle是一個可以檢查自己代碼是否正確的系統(tǒng),它能顯示出哪些測試沒有通過,但是不會提示具體是哪里錯誤】)。如果沒有,看看您的發(fā)送者和接收者在您的測試中做了什么。(10分)

2.Fill in the code items numbered 1. Now run some small tests with loss. Does your sender follow the protocol properly when a packet is lost? If not, fix the behaviour. You should now be able to pass test 2.(10 marks)

填寫編號為1的代碼項?,F(xiàn)在運行一些帶有損失的小測試。當(dāng)數(shù)據(jù)包丟失時,發(fā)送方是否正確地遵循協(xié)議?如果沒有,那就修正行為。您現(xiàn)在應(yīng)該能夠通過測試2。(10分)

3.Fill in the code items number 2 (check if ACK is a duplicate ACK) and 3 (B receives wrong sequence number or corrupt packet). When you have this correct you should be able to pass test 3. (20 marks)
填寫代碼項2(檢查ACK是否為重復(fù)的ACK)和3(B接收錯誤的序列號或損壞的數(shù)據(jù)包)。當(dāng)你有這個正確的時候,你應(yīng)該能夠通過測試3。(20分)

4.Fill in the code item numbered 4. Now run a small test with corruption. Do your sender and receiver detect corruption when it occurs and do they react correctly when a corrupted packet or ACK is received? You should now be able to pass test 4. (10 marks)

填寫編號為4的代碼項?,F(xiàn)在用損壞來做一個小測試。當(dāng)收到損壞的數(shù)據(jù)包或ACK時,您的發(fā)送方和接收方是否會檢測到損壞,并且在收到損壞的數(shù)據(jù)包時是否正確地做出反應(yīng)?您現(xiàn)在應(yīng)該能夠通過測試4。(10分)

代碼

altbit.h

extern void A_init(void);
extern void B_init(void);
extern void A_input(struct pkt);
extern void B_input(struct pkt);
extern void A_output(struct msg);
extern void A_timerinterrupt(void);

/* included for extension to bidirectional communication */
#define BIDIRECTIONAL 0       /*  0 = A->B  1 =  A<->B */
extern void B_output(struct msg);
extern void B_timerinterrupt(void);

altbit.c

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "emulator.h"
#include "altbit.h"

/* ******************************************************************
   Unfinished Alternating bit protocol.  Adapted from
   ALTERNATING BIT AND GO-BACK-N NETWORK EMULATOR: VERSION 1.1  J.F.Kurose

   Network properties:
   - one way network delay averages five time units (longer if there
   are other messages in the channel for GBN), but can be larger
   - packets can be corrupted (either the header or the data portion)
   or lost, according to user-defined probabilities
   - packets will be delivered in the order in which they were sent
   (although some can be lost).

   Modifications (6/6/2008 - CLP): 
   - removed bidirectional code and other code not used by prac. 
   - fixed C style to adhere to current programming style
   (7/8/2009 - CLP)
   - converted to Alt Bit
**********************************************************************/

#define RTT  15.0       /* round trip time.  MUST BE SET TO 15.0 when submitting assignment */
#define WINDOWSIZE 1    /* alternating bit only allows one unacked packet */
#define NOTINUSE (-1)   /* used to fill header fields that are not being used 用于填充未被使用的頭字段 */

/* generic procedure to compute the checksum of a packet.  Used by both sender and receiver  
   the simulator will overwrite part of your packet with 'z's.  It will not overwrite your 
   original checksum.  This procedure must generate a different checksum to the original if
   the packet is corrupted.
*/
/**計算校驗和*/
int ComputeChecksum(struct pkt packet)
{
  int checksum = 0;

  /****** 4. FILL IN CODE to calculate the checksum of packet 填入代碼來計算數(shù)據(jù)包的校驗和*****/
  ///
  for (int i = 0; i < 20;i++) {
      checksum += packet.payload[i];
  }
  checksum += packet.acknum;
  checksum += packet.seqnum;
  checksum = ~checksum;
  ///

  return checksum;
}

/**檢查一個包是不是損壞的*/
bool IsCorrupted(struct pkt packet)
{
  if (packet.checksum == ComputeChecksum(packet))
    return (false);
  else
    return (true);
}

/********* Sender (A) variables and functions ************/

static struct pkt buffer[WINDOWSIZE];  /* array for storing packets waiting for ACK */
static int windowfirst, windowlast;    /* array indexes of the first/last packet awaiting ACK */
static int windowcount;                /* the number of packets currently awaiting an ACK 當(dāng)前等待ACK的數(shù)據(jù)包的數(shù)量 */
static int A_nextseqnum;               /* the next sequence number to be used by the sender */

/* called from layer 5 (application layer), passed the message to be sent to other side */
void A_output(struct msg message)
{
  struct pkt sendpkt;
  int i;

  /* if not blocked waiting on ACK */
  if ( windowcount < WINDOWSIZE) {
    if (TRACE > 1)
      printf("----A: New message arrives, send window is not full, send new messge to layer3!\n");

    /* create packet */
    sendpkt.seqnum = A_nextseqnum;
    sendpkt.acknum = NOTINUSE;
    for ( i=0; i<20 ; i++ ) 
      sendpkt.payload[i] = message.data[i];
    sendpkt.checksum = ComputeChecksum(sendpkt); 

    /* put packet in window buffer */
    /* windowlast will always be 0 for alternating bit; but not for GoBackN */
    windowlast = (windowlast + 1) % WINDOWSIZE; 
    buffer[windowlast] = sendpkt;
    for (i=0; i<20; i++)
      buffer[windowlast].payload[i]=sendpkt.payload[i];  /* copy the array */
    windowcount++;

    /* send out packet */
    if (TRACE > 0)
      printf("Sending packet %d to layer 3\n", sendpkt.seqnum);
    tolayer3 (A, sendpkt);
    /**** 1. FILL IN CODE There's something else A needs to do when it sends a packet. *****/
    /////////
    starttimer(A, RTT);
    /////////
    A_nextseqnum = (A_nextseqnum + 1) % 2;  /* we only have seqnum 0 and 1 */
  }
  /* if blocked,  window is full */
  else {
    if (TRACE > 0)
      printf("----A: New message arrives, send window is full\n");
    window_full++;
  }
}


/* called from layer 3, when a packet arrives for layer 4 
   In this practical this will always be an ACK as B never sends data.
*/
void A_input(struct pkt packet)
{

  /* if received ACK is not corrupted 如果收到的ACK沒有損壞*/ 
  if (!IsCorrupted(packet)) {
    if (TRACE > 0)
      printf("----A: uncorrupted ACK %d is received\n",packet.acknum);
    total_ACKs_received++;

    /* check if new ACK or duplicate 檢查ACK是新的還是原來的*/
    if (packet.acknum!= A_nextseqnum) {    /**** 2. FILL IN CODE replace TRUE with test whether this is a new ACK ***/
      /* packet is a new ACK */
      if (TRACE > 0)
        printf("----A: ACK %d is not a duplicate\n",packet.acknum);
      new_ACKs++;

      /* delete the acked packets from window buffer 從緩存窗口中刪除已經(jīng)確認的包 */
      windowcount--;

      /***** 1. FILL IN CODE  What else needs to be done when an ACK arrives
       besides removing the packet from the window?  ****/
      ////
      stoptimer(A);
      ////
    }
    else
      if (TRACE > 0)
        printf ("----A: duplicate ACK received, do nothing!\n");
  }
  else 
    if (TRACE > 0)
      printf ("----A: corrupted ACK is received, do nothing!\n");
}

/* called when A's timer goes off */
void A_timerinterrupt(void)
{

  if (TRACE > 0)
    printf("----A: time out,resend packets!\n");

  if (TRACE > 0)
    printf ("---A: resending packet %d\n", (buffer[windowfirst]).seqnum);
  tolayer3(A,buffer[windowfirst]);
  /**** 1. FILL IN CODE What state should the timer be in at this point? *****/
  ////
  starttimer(A, RTT);
  /////
  packets_resent++;
}       



/* the following routine will be called once (only) before any other */
/* entity A routines are called. You can use it to do any initialization */
void A_init(void)
{
  /* initialise A's window, buffer and sequence number */
  A_nextseqnum = 0;  /* A starts with seq num 0, do not change this */
  windowfirst = 0;
  windowlast = -1;   /* windowlast is where the last packet sent is stored.  
             new packets are placed in winlast + 1 
             so initially this is set to -1           */
  windowcount = 0;
}



/********* Receiver (B)  variables and procedures ************/

static int expectedseqnum; /* the sequence number expected next by the receiver */
static int B_nextseqnum;   /* the sequence number for the next packets sent by B */


/* called from layer 3, when a packet arrives for layer 4 at B*/
void B_input(struct pkt packet)
{
  struct pkt sendpkt;
  int i;

  /* if not corrupted and received packet is in order */
  if  ( (!IsCorrupted(packet))  && (packet.seqnum == expectedseqnum) ) {
    if (TRACE > 0)
      printf("----B: packet %d is correctly received, send ACK!\n",packet.seqnum);
    packets_received++;

    /* deliver to receiving application */
    tolayer5(B, packet.payload);

    /* send an ACK for the received packet */
    sendpkt.acknum = expectedseqnum;

    /* update state variables */
    expectedseqnum = (expectedseqnum + 1) % 2;        
  }
  else {
    /* packet is corrupted or out of order */
    if (TRACE > 0) 
      printf("----B: packet corrupted or not expected sequence number, resend ACK!\n");
    /***** 3. FILL IN CODE  What ACK number should be sent if the packet
       was corrupted or out of order? *******/ 
    /////
    sendpkt.acknum = (expectedseqnum + 1) % 2;
    /////

  }

  /* create packet */
  sendpkt.seqnum = B_nextseqnum;
  B_nextseqnum = (B_nextseqnum + 1) % 2;
    
  /* we don't have any data to send.  fill payload with 0's */
  for ( i=0; i<20 ; i++ ) 
    sendpkt.payload[i] = '0';  

  /* computer checksum */
  sendpkt.checksum = ComputeChecksum(sendpkt); 

  /* send out packet */
  tolayer3 (B, sendpkt);
}

/* the following routine will be called once (only) before any other */
/* entity B routines are called. You can use it to do any initialization */
void B_init(void)
{
  expectedseqnum = 0;
  B_nextseqnum = 1;
}

/******************************************************************************
 * The following functions need be completed only for bi-directional messages *
 * They do not need to be completed for this practical                        *
 *****************************************************************************/

/* Note that with simplex transfer from a-to-B, there is no B_output() */
void B_output(struct msg message)  
{
}

/* called when B's timer goes off */
void B_timerinterrupt(void)
{
}

emulator.h

extern int TRACE;

/* statistics updated by GBN */
extern int total_ACKs_received;
extern int packets_resent;       /* count of the number of packets resent  */
extern int new_ACKs;      /* count of the number of acks correctly received */
extern int packets_received;  /* count of the packets received by receiver */
extern int window_full; /* count of the number of messages dropped due to full window */

#define   A    0
#define   B    1

/* a "msg" is the data unit passed from layer 5 (teachers code) to layer  */
/* 4 (students' code).  It contains the data (characters) to be delivered */
/* to layer 5 via the students transport level protocol entities.         */
struct msg {
  char data[20];
};

/* a packet is the data unit passed from layer 4 (students code) to layer */
/* 3 (teachers code).  Note the pre-defined packet structure, which all   */
/* students must follow. */
struct pkt {
  int seqnum;
  int acknum;
  int checksum;
  char payload[20];
};

/* send to A or B (int), packet to send */
extern void tolayer3(int, struct pkt);  

/* deliver to A or B (int), data to deliver */
extern void tolayer5(int, char[20]); 

/* start timer at A or B (int), increment */
extern void starttimer(int, double);       

/* stop timer at A or B (int) */
extern void stoptimer(int);               

emulator.c

#define _CRT_SECURE_NO_WARNINGS
/* ***** THIS FILE SHOULD NOT BE MODIFIED ****************************
   THERE IS NOT REASON THAT ANY STUDENT SHOULD HAVE TO READ OR UNDERSTAND
   THE CODE BELOW.  YOU SHOLD NOT TOUCH, OR REFERENCE (in your code) ANY
   OF THE DATA STRUCTURES BELOW.  If you're interested in how I designed
   the emulator, you're welcome to look at the code - but again, you should have
   to, and you defeinitely should not have to modify
   This file contains the code that emulates the network.  It does not
   implement any of the Go-Back-N protocol.
   ********************************************************************

   ******************************************************************
   ALTERNATING BIT AND GO-BACK-N NETWORK EMULATOR: VERSION 1.1  J.F.Kurose
   The code below emulates the layer 3 and below network environment:
   - emulates the tranmission and delivery (possibly with bit-level corruption
   and packet loss) of packets across the layer 3/4 interface
   - handles the starting/stopping of a timer, and generates timer
   interrupts (resulting in calling students timer handler).
   - generates message to be sent (passed from later 5 to 4)

   Network properties:
   - one way network delay averages five time units (longer if there
   are other messages in the channel for GBN), but can be larger
   - packets can be corrupted (either the header or the data portion)
   or lost, according to user-defined probabilities
   - packets will be delivered in the order in which they were sent
   (although some can be lost).

   Modifications (6/6/2008 - CLP): 
   - removed bidirectional GBN code and other code not used by prac. 
   - removed hard coded maximum random number, use library defined
   RAND_MAX value 
   - simulator stops when no events are left rather than stopping as
   soon as n packets are sent.
   - fixed C style to adhere to current programming style

   ********************************************************************* */
#include <stdlib.h>
#include <stdio.h>
#include "emulator.h"
#include "altbit.h"



struct event {
  float evtime;           /* event time */
  int evtype;             /* event type code */
  int eventity;           /* entity where event occurs */
  struct pkt *pktptr;     /* ptr to packet (if any) assoc w/ this event */
  struct event *prev;
  struct event *next;
};

struct event *evlist = NULL;   /* the event list */

/* possible events:可能事件 */
#define  TIMER_INTERRUPT 0  
#define  FROM_LAYER5     1
#define  FROM_LAYER3     2

#define  OFF             0
#define  ON              1

int TRACE = 3;

/* statistics updated by GBN */
int window_full;   /* count of the number of messages dropped due to full window */
int total_ACKs_received;
int packets_resent;       /* count of the number of packets resent  */
int new_ACKs;           /* count of the number of acks correctly received */
int packets_received;  /* count of the packets received by receiver */

/* statistics updated by emulator */
static int packets_lost;  
static int packets_corrupt;
static int packets_sent;
static int packets_timeout;
static int messages_delivered;

static int nsim = 0;              /* number of messages from 5 to 4 so far */ 
static int nsimmax = 0;           /* number of msgs to generate, then stop */
static float time = 0.000;
static float lossprob;            /* probability that a packet is dropped  */
static float corruptprob;   /* probability that one bit is packet is flipped */
static int corruptdirection; /* A->B A<-B or bidirectional corruption/loss */
static float lambda;        /* arrival rate of messages from layer 5 */   
static int   ntolayer3;           /* number sent into layer 3 */
static int   nlost;               /* number lost in media */
static int ncorrupt;              /* number corrupted by media*/

/****************************************************************************/
/* jimsrand(): return a double in range [0,1].  The routine below is used to */
/* isolate all random number generation in one location.  We assume that the*/
/* system-supplied rand() function return an int in therange [0,mmm]        */
/****************************************************************************/
/**返回一個0-1的double類型的隨機數(shù)*/
double jimsrand(void) 
{
  /**RAND_MAX 指的是 C 語言標準庫 中定義的一個宏。經(jīng)預(yù)編譯階段處理后,
  它展開為一個整數(shù)類型的常量表達式。RAND_MAX 是 中偽隨機數(shù)生成函數(shù) rand 
  所能返回的最大數(shù)值。這意味著,任何一次對 rand 的調(diào)用,都將得

回答
編輯回答
久不遇

自己提的問題還是自己答吧:
在別人的暗示下我把
代碼altbit.c中的A_input函數(shù)中的判斷

if (packet.acknum!= A_nextseqnum)

改成

if (packet.acknum!= A_nextseqnum && windowcount>=WINDOWSIZE)

雖然通過了測試,但是還不知道為什么
希望路過的人知道了說一下
我也繼續(xù)在思考

2017年1月25日 04:42