按照自己的理解实现比特交换协议(alternating-bit protocol)
一开始的思路是想写两个程序的,发送端和接收端。但是后来想了下,因为是模拟的,所以不用这么麻烦,直接自己定制场景(比如说丢包阿,包出错阿,超时之类的)。
基本上是根据上图所写的,一个函数发包,一个函数接包(比如上图的wait_for_ack0),在这个发包函数里定制场景,在接包函数里处理场景。
说到处理场景,仔细看看wait for ack0上所写的:
翻译一下:
if ( rdt_rcv(rcvpkt) && (corrupt(rcvpkt)) || isACK(rcvpkt, 1) ) // 如果有接受到包且包坏了, 或者接受到的ACK是1,那么就什么都不用做,因为会执行下面的超时函数 { ;// do nothing,静静地等待超时然后重新发包 }
if (timeout) // 如果超时,重新发包然后重新启动计时器 { udt_send(sndpkt); start_timer; }
if ( rdt_rcv(rcvpkt) && notcorrupt(rcvpkt) && isACK(rcvpkt, 0) ) // 只有凑齐接收到包且包正确且收到的回复正确,那么就可以停止计时了 { stop timer; }
因为这是停等协议(stop and wait),所以顺序是先发0包,再发1包,再发0包这样持续下去。
根据场景,我定义了这个一个数组:数据包丢失,确认包丢失,数据包出错,确认包出错,超时 5个场景。 丢失就会超时,出错就是验证校验和。
不过因为我懒,所以没有计算RTT之类的时间,校验和也忽略掉的。
这里给个思路,可以根据公式(大家可以看看计算机网路的书,上面有写算RTT的公式),只要你定义了数据包的大小,网速的话,根据包的个数是可以算出来RTT的。
下面是我自己定义的场景。
#define PACKAGE_LOSS 0 #define ACK_LOSS 1 #define PACK_CORRUPT 2 #define ACK_CORRUPT 3 #define TIME_OUT 4 int Flag[5] = {0}; // 0代表没有,1代表有
你在调用发包这个函数时就询问会出现哪种场景,我写得代码一次发包只能实现一种场景(不过根据场景的不同,有可能引发其他场景。比如丢包,这样自然就会引起超时了)。
在接收包的函数时,就定义解决场景,根据上图写。
下面给出完整代码(有一些地方可能会出错,但也弄出个大概,仅供参考)
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #define DATA_LENGTH 20 5 6 struct Pkt 7 { 8 int seqnum; 9 int checksum; 10 char data[DATA_LENGTH]; 11 }; 12 13 #define PACKAGE_LOSS 0 14 #define ACK_LOSS 1 15 #define PACK_CORRUPT 2 16 #define ACK_CORRUPT 3 17 #define TIME_OUT 4 18 19 int Flag[5] = {0}; 20 21 int nsimmax = 0; // the number of message 22 int n_package = 0; 23 struct Pkt *pkt_ptr = NULL; 24 25 void init() 26 { 27 int i = 0; 28 int j = 0; 29 int k = 0; 30 31 printf("---- Stop and Wait Network Simulator Version 1.0 ----\n"); 32 printf("Enter the number of messages to simulate: "); 33 scanf("%d", &nsimmax); 34 35 pkt_ptr = (struct Pkt *)malloc(nsimmax * sizeof(struct Pkt)); // nsimmax packages 36 if (pkt_ptr == NULL) 37 { 38 perror("Malloc Error: "); 39 exit(1); 40 } 41 42 // Fill some data in Pkt.data 43 44 for (i = 0; i < nsimmax; i++) 45 { 46 for (j = 0; j < DATA_LENGTH; j++) 47 { 48 pkt_ptr[i].data[j] = 97 + k; 49 } 50 51 k++; 52 } 53 54 } 55 56 void Question(int *p) 57 { 58 int i = 0; 59 60 printf("--------------\n"); 61 printf("0 - Nothing wrong\n"); 62 printf("1 - Packet loss\n"); 63 printf("2 - ACK loss\n"); 64 printf("3 - Packet error\n"); 65 printf("4 - ACK error\n"); 66 printf("5 - Time out\n"); 67 printf("--------------\n"); 68 69 printf("Choice: "); 70 scanf("%d", &i); 71 72 if (i != 0) 73 { 74 p[i - 1] = 1; 75 } 76 } 77 78 void send() 79 { 80 81 if (Flag[0] == 1) 82 { 83 printf("SEND: Package loss\n"); 84 Flag[4] = 1; // time out 85 } 86 87 else if (Flag[1] == 1) 88 { 89 printf("SEND: ACK loss\n"); 90 Flag[4] = 1; // time out 91 } 92 93 else if (Flag[2] == 1) 94 { 95 printf("SEND: Packet error\n"); 96 } 97 98 else if (Flag[3] == 1) 99 { 100 printf("SEND: ACK error\n"); 101 } 102 103 else if (Flag[4] == 1) 104 { 105 printf("SEND: Time out\n"); 106 } 107 108 else 109 { 110 printf("SEND: Nothing wrong\n"); 111 } 112 113 printf("\n"); 114 115 116 } 117 118 void rdt_send0() 119 { 120 Question(Flag); 121 122 printf("SEND: Send package 0\n"); 123 printf("SEND: Start timer\n\n"); 124 125 send(); 126 127 } 128 129 void rdt_send1() 130 { 131 Question(Flag); 132 133 printf("SEND: Send package 1\n"); 134 printf("SEND: Start timer\n\n"); 135 136 send(); 137 138 } 139 140 void waitACK0() 141 { 142 int i = 0; 143 144 while (1) 145 { 146 if ((Flag[0] == 0 && Flag[2] == 1) || Flag[3] == 1) 147 { 148 printf("-------------------\n"); 149 if (Flag[2] == 1) // Send error package 150 { 151 printf("RECV: SEND NAK0\n"); 152 } 153 154 if (Flag[3] == 1) // Error ACK0 means ACK1 155 { 156 printf("RECV: Receive package 0\n"); 157 158 printf("The data is: "); 159 for (i = 0; i < DATA_LENGTH; i++) 160 printf("%c", pkt_ptr[n_package].data[i]); 161 printf("\n"); 162 163 printf("RECV: SEND ACK1\n"); 164 printf("SEND: ACK should be 0\n"); 165 } 166 printf("-------------------\n"); 167 168 Flag[4] = 1; // package error or error ACK can lead to time out 169 } 170 171 if (Flag[4] == 1) // time out 172 { 173 printf("SEND: Time out\n"); 174 printf("SEND: Resend package0...\n"); 175 if (Flag[0] == 1) // package 0 loss 176 { 177 Flag[0] = 0; 178 } 179 180 if (Flag[1] == 1) // ACK 0 loss 181 { 182 printf("RECV: Detetch the redundant, discard the package0\n"); 183 Flag[1] = 0; 184 } 185 186 if (Flag[2] == 1) // package 0 error 187 { 188 Flag[2] = 0; 189 } 190 191 if (Flag[3] == 1) 192 { 193 printf("RECV: Detetch the redundant, discard the package0\n"); 194 Flag[3] = 0; 195 } 196 197 printf("SEND: Start timer\n"); 198 Flag[4] = 0; 199 } 200 201 if (Flag[0] == 0 && Flag[2] == 0 && Flag[3] == 0) 202 { 203 printf("SEND: Stop timer\n"); 204 printf("-------------------\n"); 205 printf("RECV: reveive package0\n"); 206 printf("RECV: send ACK0\n"); 207 208 printf("The data is: "); 209 for (i = 0; i < DATA_LENGTH; i++) 210 printf("%c", pkt_ptr[n_package].data[i]); 211 printf("\n"); 212 213 break; 214 } 215 } 216 } 217 218 219 void waitACK1() 220 { 221 int i = 0; 222 223 while (1) 224 { 225 if ((Flag[0] == 0 && Flag[2] == 1) || Flag[3] == 1) 226 { 227 printf("-------------------\n"); 228 if (Flag[2] == 1) // Send error package 229 { 230 printf("RECV: SEND NAK0\n"); 231 } 232 233 if (Flag[3] == 1) // Error ACK0 means ACK1 234 { 235 printf("RECV: Receive package 0\n"); 236 237 printf("The data is: "); 238 for (i = 0; i < DATA_LENGTH; i++) 239 printf("%c", pkt_ptr[n_package].data[i]); 240 printf("\n"); 241 242 printf("RECV: SEND ACK1\n"); 243 printf("SEND: ACK should be 0\n"); 244 } 245 printf("-------------------\n"); 246 247 Flag[4] = 1; // package error or error ACK can lead to time out 248 } 249 250 if (Flag[4] == 1) // time out 251 { 252 printf("SEND: Time out\n"); 253 printf("SEND: Resend package0...\n"); 254 if (Flag[0] == 1) // package 1 loss 255 { 256 Flag[0] = 0; 257 } 258 259 if (Flag[1] == 1) // ACK 1 loss 260 { 261 printf("RECV: Detetch the redundant, discard the package1\n"); 262 Flag[1] = 0; 263 } 264 265 if (Flag[2] == 1) // package 1 error 266 { 267 Flag[2] = 0; 268 } 269 270 if (Flag[3] == 1) 271 { 272 printf("RECV: Detetch the redundant, discard the package1\n"); 273 Flag[3] = 0; 274 } 275 276 printf("SEND: Start timer\n"); 277 Flag[4] = 0; 278 } 279 280 281 if (Flag[0] == 0 && Flag[2] == 0 && Flag[3] == 0) 282 { 283 printf("SEND: Stop timer\n"); 284 printf("-------------------\n"); 285 printf("RECV: reveive package1\n"); 286 printf("RECV: send ACK1\n"); 287 288 printf("The data is: "); 289 for (i = 0; i < DATA_LENGTH; i++) 290 printf("%c", pkt_ptr[n_package].data[i]); 291 printf("\n"); 292 293 break; 294 } 295 } 296 } 297 298 void run() 299 { 300 init(); 301 while (1) 302 { 303 printf("--------%d package ------------\n", n_package); 304 rdt_send0(); 305 waitACK0(); 306 n_package++; 307 if (n_package == nsimmax) 308 break; 309 310 printf("--------%d package ------------\n", n_package); 311 rdt_send1(); 312 waitACK1(); 313 n_package++; 314 315 if (n_package == nsimmax) 316 break; 317 } 318 319 return; 320 321 } 322 323 int main(void) 324 { 325 run(); 326 return 0; 327 }
因为是停等协议,所以有两个send函数,有两个wait for ACK函数,都是差不多的,只是一个是发0包,接0包,一个是发1包,接1包。
下面给出运行结果: