计算机网络滑动窗口协议的模拟(仅作记录)
环境:Microsoft Visual C++ 6.0
参考:《计算机网络》第五版,清华大学出版社
帧格式定义 :
/* FRAME kind */
/*
DATA Frame
+=========+========+========+===============+========+
| KIND(1) | SEQ(1) | ACK(1) | DATA(240~256) | CRC(4) |
+=========+========+========+===============+========+
ACK Frame
+=========+========+========+
| KIND(1) | ACK(1) | CRC(4) |
+=========+========+========+
NAK Frame
+=========+========+========+
| KIND(1) | ACK(1) | CRC(4) |
+=========+========+========+
*/
datalink.cpp
#include "YHL.h"
int main ( int argc , char **argv ) {
YHL::Init_Protocol ( argc , argv ) ;
while ( true ) {
// 获取一个事件
int event = YHL::Get_event () ;
switch ( event ) {
// 网络层准备好了
case NETWORK_LAYER_READY : YHL::Net_Layer_OK () ; break ;
// 收到了一个帧
case FRAME_RECEIVED : YHL::Recieve_Data () ; break ;
// 物理层准备好了
case PHYSICAL_LAYER_READY : YHL::phl_ready = 1 ; break ;
// 数据帧确认超时了
case DATA_TIMEOUT : YHL::Data_Time_Out () ; break ;
// ack 辅助定时器超时
case ACK_TIMEOUT : YHL::Ack_Time_Out () ; break ;
//
default : break ;
}
// 随时控制网络层流量
YHL::Enable_Net_Layer () ;
}
return 0 ;
}
YHL.h
#include <iostream>
#include <cstring>
#include "protocol.h"
using namespace std ;
#pragma comment ( lib , "Protocol.lib" )
#define rep ( i , j , n ) for ( int i = int(j) ; i < int(n) ; ++i )
// 帧类型
#define FRAME_DATA 1
#define FRAME_ACK 2
#define FRAME_NAK 3
// 窗口大小定义
#define MAX_SEQ 15
#define NR_BUFS ( ( MAX_SEQ + 1 ) >> 1 )
// 超时规定
#define DATA_TIMER 2000
#define ACK_TIMER 200
namespace YHL {
// 帧数据结构定义
class FRAME {
public:
unsigned char type ; // 种类
unsigned char ack ; // ack
unsigned char seq ; // 序号
unsigned char data[PKT_LEN] ; // 数据帧
unsigned int padding ;
public:
FRAME () {}
FRAME ( unsigned char _type , unsigned char _seq , unsigned char _ack )
: type ( _type )
, seq ( _seq )
, ack ( _ack )
{}
} ;
extern FRAME One ;
// 事件参数
extern int arg ;
// 判断当前是否存在 NAK, NAK 只是请求重传, 可以有也可以没有
extern bool no_nak ;
// 作为接收方, 判断当前是接收重复帧
extern bool arrived[NR_BUFS] ;
// 物理层准备好的标志
extern int phl_ready ;
// 发送窗口的左边
extern unsigned char ack_expected ;
// 发送窗口的右边
extern unsigned char next_frame_to_send ;
// 接收窗口的左边
extern unsigned char frame_expected ;
// 接收窗口的右边
extern unsigned char too_far ;
// 当前的发送窗口数
extern unsigned char nbuffered ;
// 发送缓冲区
extern unsigned char out_buf[NR_BUFS][PKT_LEN] ;
// 接收缓冲区
extern unsigned char in_buf[NR_BUFS][PKT_LEN] ;
// 窗口继续移动
unsigned char Go_On ( unsigned char &NO ) ;
// 判断是否落在窗口内
int between ( unsigned char a , unsigned char b , unsigned char c ) ;
// 加上 CRC 循环冗余校验, 然后 send_frame
void Add_crc_and_Send ( unsigned char *frame , int len ) ;
// 发送一个特定类型的帧
void Send_Data_Frame ( unsigned char fk , unsigned char frame_nr ) ;
// CRC 校验判断是否收到了一个错误的帧
bool Bad_Package ( const int len ) ;
void Recieve_Data () ;
void Init_Protocol ( int argc , char **argv ) ;
// 如果网络层准备好了, 就从网络层接收一个数据包
void Net_Layer_OK () ;
// 超时重发
void Data_Time_Out () ;
// ack timer 之前没有数据帧要发送, 先发送一个 ACK 帧
void Ack_Time_Out () ;
// 控制网络层的流量
void Enable_Net_Layer () ;
int Get_event () ;
}
YHL.cpp
#include "YHL.h"
YHL::FRAME YHL::One ;
// 事件参数
int YHL::arg = 0 ;
// 判断当前是否存在 NAK, NAK 只是请求重传, 可以有也可以没有
bool YHL::no_nak = true ;
// 作为接收方, 判断当前是接收重复帧
bool YHL::arrived[NR_BUFS] ;
// 物理层准备好的标志
int YHL::phl_ready = 0 ;
// 发送窗口的左边
unsigned char YHL::ack_expected = 0 ;
// 发送窗口的右边
unsigned char YHL::next_frame_to_send = 0 ;
// 接收窗口的左边
unsigned char YHL::frame_expected = 0 ;
// 接收窗口的右边
unsigned char YHL::too_far = NR_BUFS ;
// 当前的发送窗口数
unsigned char YHL::nbuffered ;
// 发送缓冲区
unsigned char YHL::out_buf[NR_BUFS][PKT_LEN] ;
// 接收缓冲区
unsigned char YHL::in_buf[NR_BUFS][PKT_LEN] ;
// 窗口继续移动
unsigned char YHL::Go_On ( unsigned char &NO ) {
return NO = ( NO + 1 ) % ( MAX_SEQ + 1 ) ;
}
// 判断是否落在窗口内
int YHL::between ( unsigned char a , unsigned char b , unsigned char c ) {
return ( ( ( a <= b ) && ( b < c ) )
|| ( ( c < a ) && ( a <= b ) )
|| ( ( b < c ) && ( c < a ) ) ) ;
}
// 加上 CRC 循环冗余校验, 然后 send_frame
void YHL::Add_crc_and_Send ( unsigned char *frame , int len ) {
*(unsigned int *)( frame + len ) = crc32 ( frame , len ) ;
send_frame ( frame , len + 4 ) ; // 4 个校验位
phl_ready = 0 ; // 每发一个帧, 物理层先缓冲一下, 控制流量
}
// 发送一个特定类型的帧
void YHL::Send_Data_Frame ( unsigned char type ,
unsigned char frame_nr ) {
// 选择重传是有累积效应的
// ( frame_expected -1 + ( Max_SEQ + 1 ) ) % ( MAX_SEQ + 1 )
int ack = ( frame_expected + MAX_SEQ ) % ( MAX_SEQ + 1 ) ;
FRAME One ( type , frame_nr , ack ) ;
switch ( type ) {
case FRAME_DATA : {
memcpy ( One.data , out_buf[frame_nr % NR_BUFS] , PKT_LEN ) ;
dbg_frame ( "Send DATA %d %d , ID %d\n" , One.seq , One.ack , *(short *)One.data ) ;
Add_crc_and_Send ( (unsigned char *)&One , 3 + PKT_LEN ) ;
start_timer ( frame_nr % NR_BUFS , DATA_TIMER ) ;
break ;
}
case FRAME_ACK : {
dbg_frame("Send ACK %d\n" , One.ack ) ;
Add_crc_and_Send ( (unsigned char *)&One , 3 ) ;
break ;
}
case FRAME_NAK : {
no_nak = false ; // 当前有 NAK, 请求重传, 暂时屏蔽其他的 NAK
dbg_frame("Send NAK\n" , One.ack + 1 ) ;
Add_crc_and_Send ( (unsigned char *)&One , 3 ) ;
}
}
stop_ack_timer () ;
}
// CRC 校验判断是否收到了一个错误的帧
bool YHL::Bad_Package ( const int len ) {
if ( len < 5 || crc32 ( (unsigned char *)&One , len ) ) {
// 当前 NAK 是否被占用了
if ( no_nak == true ) {
Send_Data_Frame ( FRAME_NAK , 0 ) ;
dbg_event ( "**** Receive Frame Error , Bad CRC Checksum ,sent nak \n" ) ;
}
return false ; // 这里坑死我了
}
return true ;
}
void YHL::Recieve_Data () {
int len = recv_frame ( (unsigned char *)&One , sizeof One ) ;
if ( !Bad_Package ( len ) )
return ;
if ( One.type == FRAME_DATA ) {
if ( ( One.seq != frame_expected ) && no_nak == true )
Send_Data_Frame ( FRAME_NAK , 0 ) ;
else if ( One.seq == frame_expected )
start_ack_timer ( ACK_TIMER ) ; // 是我想要的帧
if ( between ( frame_expected , One.seq , too_far ) == 1
&& arrived[One.seq % NR_BUFS] == false ) { // 收到的帧落在接收窗口内, 而且不是重复的
dbg_frame ( "Recv DATA %d %d , ID %d\n" , One.seq , One.ack , *(short *)One.data ) ;
arrived[One.seq % NR_BUFS] = true ;
memcpy ( in_buf[One.seq % NR_BUFS] , One.data , len - 7 ) ;
// 每次收到一个完整的帧, 检查一下, 从左边开始腾出位置
while ( arrived[frame_expected % NR_BUFS] ) {
put_packet ( in_buf[frame_expected % NR_BUFS] , len - 7 ) ;
no_nak = true ;
arrived[frame_expected % NR_BUFS] = false ;
Go_On ( frame_expected ) ;
Go_On ( too_far ) ;
start_ack_timer ( ACK_TIMER ) ; // 收到了帧, 如果超时没有帧要发送, 就先发一个 ACk
}
}
}
// 如果这次收到了 NAK
// nak 帧里边的 ack 依旧是 frame_expected 的前一个被确认了
// 所以发的是 ack + 1
if ( ( One.type == FRAME_NAK ) &&
between ( ack_expected , ( One.ack + 1 ) % (MAX_SEQ + 1 ) , next_frame_to_send ) ) {
dbg_frame ( "Recv NAK %d\n" , One.ack + 1 ) ;
Send_Data_Frame ( FRAME_DATA , ( One.ack + 1 ) % ( MAX_SEQ + 1 ) ) ;
}
// 发出去的帧确认被接收了, 腾出空间, 窗口移动
while ( between ( ack_expected , One.ack , next_frame_to_send ) ) {
--nbuffered ;
stop_timer ( ack_expected % NR_BUFS ) ;
Go_On ( ack_expected ) ;
}
}
// 初始化窗口为 false
void YHL::Init_Protocol ( int argc , char **argv ) {
protocol_init ( argc , argv ) ;
lprintf ( "Fluence_YHL : " __DATE__" "__TIME__"\n" ) ;
for ( int i = 0 ; i < NR_BUFS ; ++i )
arrived[i] = false ;
disable_network_layer () ;
}
// 如果网络层准备好了, 就从网络层接收一个帧
void YHL::Net_Layer_OK () {
++nbuffered ;
get_packet ( out_buf[next_frame_to_send % NR_BUFS] ) ;
Send_Data_Frame ( FRAME_DATA , next_frame_to_send ) ;
Go_On ( next_frame_to_send ) ;
}
// 超时重发
void YHL::Data_Time_Out () {
dbg_event ( "---- DATA %d timeout\n" , arg ) ;
Send_Data_Frame ( FRAME_DATA , ack_expected ) ;
}
// ack timer 之前没有数据帧要发送, 先发送一个 ACK 帧
void YHL::Ack_Time_Out () {
dbg_event ( "---- ACK %d timeout\n" , arg ) ;
Send_Data_Frame ( FRAME_ACK , 0 ) ;
}
// 控制网络层的流量
void YHL::Enable_Net_Layer () {
if ( nbuffered < NR_BUFS && phl_ready )
enable_network_layer() ;
else
disable_network_layer() ;
}
int YHL::Get_event () {
return wait_for_event ( &arg ) ;
}