计算机网络滑动窗口协议的模拟(仅作记录)
环境: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 ) ; }