c语言实现n-ARQ协议
时间: 2023-09-15 19:15:18 浏览: 176
三种ARQ算法
5星 · 资源好评率100%
n-ARQ(n次自动重传请求)是一种数据传输协议,可以在数据传输过程中检测丢失的数据包并进行重传,以确保数据的完整性和可靠性。下面是一个简单的C语言实现n-ARQ协议的示例:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SEQ 1
#define MAX_PKT 1024
#define TIMEOUT 5
typedef enum {frame_arrival, timeout, crc_err} event_type;
typedef struct {
char data[MAX_PKT];
} packet;
typedef struct {
int seq;
int ack;
int crc;
packet info;
} frame;
static int phl_ready = 0;
int between(int a, int b, int c) {
if(((a <= b) && (b < c)) || ((c < a) && (a <= b)) || ((b < c) && (c < a))) {
return 1;
} else {
return 0;
}
}
void send_data(int frame_nr, int frame_expected, packet buffer[]) {
frame s;
s.info = buffer[frame_nr % MAX_SEQ];
s.seq = frame_nr;
s.ack = (frame_expected + MAX_SEQ - 1) % MAX_SEQ;
s.crc = 0;
for(int i = 0; i < sizeof(frame); i++) {
s.crc += *((char*)&s + i);
}
printf("Sending frame %d\n", frame_nr);
phl_ready = 0;
send_frame(s);
start_timer(frame_nr % MAX_SEQ);
}
void protocol5(void) {
int ack_expected = 0;
int next_frame_to_send = 0;
int frame_expected = 0;
int too_far = MAX_SEQ;
packet buffer[MAX_SEQ];
frame r;
int nbuffered = 0;
int i;
for(i = 0; i < MAX_SEQ; i++) {
buffer[i].data[0] = '0' + i;
}
while(1) {
wait_for_event(&event);
switch(event.type) {
case(frame_arrival):
recv_frame(&r);
if(r.seq == frame_expected) {
printf("Receiving frame %d\n", frame_expected);
if(r.crc != 0) {
printf("CRC error\n");
send_data((ack_expected + MAX_SEQ - 1) % MAX_SEQ, frame_expected, buffer);
} else {
nbuffered--;
frame_expected = (frame_expected + 1) % MAX_SEQ;
ack_expected = (ack_expected + 1) % MAX_SEQ;
stop_timer(frame_expected % MAX_SEQ);
}
} else {
printf("Receiving frame %d\n", r.seq);
}
while(between(ack_expected, r.ack, next_frame_to_send)) {
nbuffered--;
stop_timer(ack_expected % MAX_SEQ);
ack_expected = (ack_expected + 1) % MAX_SEQ;
}
break;
case(timeout):
printf("Timeout %d\n", frame_expected);
send_data((ack_expected + MAX_SEQ - 1) % MAX_SEQ, frame_expected, buffer);
break;
case(crc_err):
printf("CRC error\n");
send_data((ack_expected + MAX_SEQ - 1) % MAX_SEQ, frame_expected, buffer);
break;
default:
break;
}
if(nbuffered < MAX_SEQ && phl_ready) {
printf("Buffering packet %d\n", next_frame_to_send);
send_data(next_frame_to_send, frame_expected, buffer);
next_frame_to_send = (next_frame_to_send + 1) % MAX_SEQ;
nbuffered++;
}
if(between(ack_expected, r.ack, next_frame_to_send)) {
printf("Acknowledge %d\n", r.ack);
}
}
}
int main(int argc, char const *argv[]) {
protocol5();
return 0;
}
```
在这个示例中,我们使用了一个简单的环形缓冲区来存储数据包。我们使用一个循环变量`next_frame_to_send`来追踪下一个要发送的数据包,使用`frame_expected`来追踪下一个期望接收的数据包,使用`ack_expected`来追踪下一个期望接收的确认帧。
在主程序中,我们调用了`protocol5`函数来实现n-ARQ协议。在该函数中,我们使用一个无限循环来等待事件的发生。当一个帧到达时,我们首先检查它的序号是否与期望的一致,如果一致,则说明这是我们期望的帧。我们首先检查CRC校验是否通过,如果通过,则将帧的数据包存入缓冲区,然后更新期望的帧号和确认帧号,并停止计时器。如果CRC校验失败,则重新发送上一个确认帧。
如果我们收到的不是期望的帧,则说明它是一个老的或未来的帧,我们只需简单地丢弃即可。
当一个计时器超时时,我们重新发送上一个确认帧。如果我们收到了一个CRC校验错误,则也重新发送上一个确认帧。
如果我们的缓冲区中有空闲空间,并且物理层准备好了发送下一个帧,则我们将下一个帧发送出去,并更新`next_frame_to_send`和`nbuffered`变量。
最后,如果我们收到了一个确认帧,则我们更新`ack_expected`变量并打印一条确认消息。
阅读全文