计算机网络实验 选择重传协议 Code 记录

计算机网络滑动窗口协议的模拟(仅作记录)

环境: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 ) ;
}





猜你喜欢

转载自blog.csdn.net/nishisiyuetian/article/details/80264903