#include <stdio.h>
#include <string.h>
#include "protocol.h"
#include "datalink.h"
#define MAX_SEQ 15
#define CACHE_SIZE ((MAX_SEQ+1)/2)
#define ACK_TIMEOUT_LMT 240
#define DATA_TIMEOUT_LMT 2800
#define INCREASE(X) do { \
if(X < MAX_SEQ) { \
X++; \
} else { \
X = 0; \
} \
} while(0) \
typedef enum {
false,
true
} bool;
typedef unsigned char byte;
typedef struct {
byte kind; /* FRAME_DATA, FRAME_ACK, FRAME_NAK */
byte ack;
byte seq;
byte data[PKT_LEN];
unsigned int crc32;
} FRAME;
static bool phyLayerReady = false; // 物理層狀態
static bool noNAK = true; // 發NAK了嗎
static void putFrame(byte* frame, int len) {
*(unsigned int*)(frame + len) = crc32(frame, len);
send_frame(frame, len + 4);
phyLayerReady = false;
}
static int between(byte a, byte b, byte c) {
return ((a <= b) && (b < c)) ||
((c < a) && (a <= b)) ||
((b < c) && (c < a));
}
static void sendFrame(
byte kind,
byte seq,
byte expFrame,
byte buffer[][PKT_LEN]
) {
// 數據幀長度爲PKT_LEN + 3 + 4
// ACK & NAK所需要的幀的長度爲2
FRAME frame;
frame.kind = kind;
frame.ack = (expFrame + MAX_SEQ) % (MAX_SEQ + 1);
if (kind == FRAME_DATA) {
frame.seq = seq;
memcpy(frame.data, buffer[seq % CACHE_SIZE], PKT_LEN);
putFrame((byte*)&frame, 3 + PKT_LEN);
start_timer(seq % CACHE_SIZE, DATA_TIMEOUT_LMT);
}
else if (kind == FRAME_NAK) {
noNAK = false;
putFrame((byte*)&frame, 2);
}
else if (kind == FRAME_ACK) {
putFrame((byte*)&frame, 2);
}
stop_ack_timer();
}
int main(int argc, char* argv[]) {
static byte expACK = 0, // 發送窗口下界
nextFrame2Send = 0; // 發送窗口上界
static byte expFrame = 0, // 接收窗口下界
tooFar = CACHE_SIZE; // 接收窗口上界+1
static byte nbuffered = 0; // 記錄bufferIndex
static byte
oBuf[CACHE_SIZE][PKT_LEN], // 輸出暫存區
iBuf[CACHE_SIZE][PKT_LEN]; // 輸入暫存區
bool arrived[CACHE_SIZE] = { false };
FRAME frame;
size_t length = 0;
int event,
arg;
protocol_init(argc, argv);
enable_network_layer();
while (1) {
event = wait_for_event(&arg);
switch (event) {
case NETWORK_LAYER_READY:
nbuffered++;
get_packet(oBuf[nextFrame2Send % CACHE_SIZE]);
sendFrame(FRAME_DATA, nextFrame2Send, expFrame, oBuf);
INCREASE(nextFrame2Send);
break;
case PHYSICAL_LAYER_READY:
phyLayerReady = true;
break;
case FRAME_RECEIVED:
length = recv_frame((byte*)&frame, sizeof frame);
// 如果爲正常數據幀,檢測seqNum判斷是否應該接收
if (length < 5 || crc32((byte*)&frame, length) != 0) {
if (noNAK)
sendFrame(FRAME_NAK, 0, expFrame, oBuf);
dbg_event("--------Bad CRC Checksum--------\n");
break;
}
if (frame.kind == FRAME_ACK) {
dbg_frame("Recv ACK %d\n", frame.ack);
}
else if (frame.kind == FRAME_DATA) {
if ((frame.seq != expFrame) && noNAK) {
sendFrame(FRAME_NAK, 0, expFrame, oBuf);
}
else {
// 是需要的幀
// 啓動ACK定時器,確定發送獨立幀的ACK
start_ack_timer(ACK_TIMEOUT_LMT);
}
// 如果窗口內的幀未到達過,移動接收窗口
if (between(expFrame, frame.seq, tooFar) &&
(arrived[frame.seq % CACHE_SIZE] == 0)
) {
dbg_frame("Recv DATA %d %d, ID %d\n", frame.seq, frame.ack, *(short*)frame.data);
arrived[frame.seq % CACHE_SIZE] = 1;
memcpy(iBuf[frame.seq % CACHE_SIZE], frame.data, length - 7);
// 一次性移動接收窗口 & 上傳一個幀到應用層
while (arrived[expFrame % CACHE_SIZE]) {
put_packet(
iBuf[expFrame % CACHE_SIZE], length - 7);
// 清理狀態變量
noNAK = true;
arrived[expFrame % CACHE_SIZE] = 0;
// 移動窗口
INCREASE(expFrame);
INCREASE(tooFar);
// 檢查獨立幀的ACK是否被需要
start_ack_timer(ACK_TIMEOUT_LMT);
}
}
}
else if ((frame.kind == FRAME_NAK) && between(expACK, (frame.ack + 1) % (MAX_SEQ + 1), nextFrame2Send)) {
dbg_frame("Recv NAK %d\n", frame.ack);
// 選擇重傳
sendFrame(
FRAME_DATA,
(frame.ack + 1) % (MAX_SEQ + 1),
expFrame,
oBuf
);
}
while (between(expACK, frame.ack, nextFrame2Send)) {
nbuffered--;
stop_timer(expACK % CACHE_SIZE);
INCREASE(expACK);
}
break;
case DATA_TIMEOUT:
dbg_event("--------DATA %d timeout--------\n", arg);
// 超時重傳
sendFrame(FRAME_DATA, expACK, expFrame, oBuf);
break;
case ACK_TIMEOUT:
dbg_event("--------ACK %d timeout--------\n", arg);
// ACK超時,嘗試確認
sendFrame(FRAME_ACK, 0, expFrame, oBuf);
}
if (nbuffered < CACHE_SIZE && phyLayerReady) {
enable_network_layer();
}
else {
disable_network_layer();
}
}
}
烤全羊啊嗯
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.