2009-05-09 13:09:00 HOHOwenzi 阅读数 2618
  • Android开源项目实践之UI篇

    本课程主要展现了如何利用Android开源代码进行app的开发。例如: 1.异步网络请求(android-async-http); 2.百变圆形滚动条(ProgressWheel);3.滑动导航栏(PagerSlidingTabStrip);4.瀑布流与上拉刷新,下拉加载完美结合(PinterestLikeAdapterView)...

    21768 人正在学习 去看看 李忠义

天杀的NetRiver...发泄完毕...

 

开始正题。以下代码在NetRiver1.21系统下通过。首先,这个滑动窗口实验应该主要参考Computer Networks 4th Edition中的 3.4 滑动窗口协议,结构定义与流程书上完全相同。然后,不要相信guide.pdf...另外,在提供一个FAQ,很有用。

 

再说一点,在NetRiver中调试是相当费时的工作。编译一次需要两分钟以上...不懂原因...所以,尽量将重要信息log出来,写到一个文件中,给自己提供更多调试的信息。

 

下面简要解释源码。

 

程序中,我为每个协议申请了一个与窗口等大小的帧缓冲区frameBuffer。帧缓冲区内存储可能需要重发的帧,并在窗口变化时更新缓冲区的内容。我还维护了两个变量upper, lower,用于指示窗口的上下界。对于等待发送队列,我为其维护一个链表队列,并动态申请缓存空间。帧队列的数据结构定义为WaitingList,具体结构见源代码。


停等协议与回退N协议本质完全一样。两个函数我使用了几乎一样的源码,只改动了窗口大小宏。两个函数分别处理了三种不同的帧事件:发送帧、接收帧和帧超时。当网络层有新帧需要发送时,先检查窗口大小。若窗口未开满,则直接发送帧。若窗口已开满,则将帧入队等待。当接收到新帧时,检查帧的确认号,并更新窗口下界,处理等待队列。当帧超时事件发生时,重传超时帧之后的所有帧。


选择重传协议的发送端大体结构与回退N协议基本一致,只有几个微小差别。第一,当帧超时事件发生时,选择重传协议只重传超时的一帧。第二,选择重传协议接收到确认帧中会出现特殊的“否定确认NAK”。当接收到这样的NAK时,发送端需要重发否定确认的这一帧。

 

  

 

2012-11-13 23:10:19 xiangshimoni 阅读数 4859
  • Android开源项目实践之UI篇

    本课程主要展现了如何利用Android开源代码进行app的开发。例如: 1.异步网络请求(android-async-http); 2.百变圆形滚动条(ProgressWheel);3.滑动导航栏(PagerSlidingTabStrip);4.瀑布流与上拉刷新,下拉加载完美结合(PinterestLikeAdapterView)...

    21768 人正在学习 去看看 李忠义

一.实验目的

实现一个滑动窗口协议的数据传送部分,目的在于使学生更好地理解基本滑动窗口协议的基本工作原理,掌握计算机网络协议的基本实现技术。

二.实验原理

1)窗口机制

滑动窗口协议的基本原理就是在任意时刻,发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口;同时,接收方也维持了一个连续的允许接收的帧的序号,称为接收窗口。发送窗口和接收窗口的序号的上下界不一定要一样,甚至大小也可以不同。不同的滑动窗口协议窗口大小一般不同。发送方窗口内的序列号代表了那些已经被发送,但是还没有被确认的帧,或者是那些可以被发送的帧。

21比特滑动窗口协议

当发送窗口和接收窗口的大小固定为1时,滑动窗口协议退化为停等协议(stop-and-wait)。该协议规定发送方每发送一帧后就要停下来,等待接收方已正确接收的确认(acknowledgement)返回后才能继续发送下一帧。由于接收方需要判断接收到的帧是新发的帧还是重新发送的帧,因此发送方要为每一个帧加一个序号。由于停等协议规定只有一帧完全发送成功后才能发送新的帧,因而只用一比特来编号就够了。

3)后退n协议

由于停等协议要为每一个帧进行确认后才继续发送下一帧,大大降低了信道利用率,因此又提出了后退n协议。后退n协议中,发送方在发完一个数据帧后,不停下来等待应答帧,而是连续发送若干个数据帧,即使在连续发送过程中收到了接收方发来的应答帧,也可以继续发送,且发送方在每发送完一个数据帧时都要设置超时定时器,只要在所设置的超时时间内仍收到确认帧,就要重发相应的数据帧。如:当发送方发送了N个帧后,若发现该N帧的前一个帧在计时器超时后仍未返回其确认信息,则该帧被判为出错或丢失,此时发送方就不得不重新发送出错帧及其后的N帧。

三.实验步骤

1.编写滑动窗口协议的实现程序;

2.在模拟实现,调试并运行自己编写的协议实现程序;

3.了解协议的工作轨迹,如出现异常情况,在实验报告中写出原因分析。

四.实验报告

1.详细描述实验过程。

2.实现具体的窗口滑动协议。

实验在Fedora 16 Linux下完成。实验模拟了滑动窗口协议,服务器向客户端发送数据,客户端判断数据是否错误,错误就重传错误的帧。

主要代码如下,包含一个客户端文件和服务器文件:

/* ****************************************************************
 *      文件名:  client.c
 *      描述:    本文件用于模拟滑窗协议客户端
 *      编译:    Linux:   gcc -lm -o client client.c
 *      可执行文件:      ./client
 *      作者:    段聪 01091138
 ******************************************************************/
#include<stdio.h> 
#include<string.h> 
#include<sys/socket.h> 
#include<sys/types.h> 
#include<netinet/in.h> 
#include<arpa/inet.h> 
#define server_ipaddr "127.0.0.1"
/*************************************************************************
  *      函数名:           main
  *      参数:             NIL
  *      返回值:           NIL
  *      描述:             主函数
***************************************************************************/
main() 
{ 
int std, lfd, len, choice, cport; 
char str[20], str1[20], err[20]; 
struct sockaddr_in saddr, caddr; 
printf("输入端口号:"); 
scanf("%d", &cport); 
std = socket(AF_INET, SOCK_STREAM, 0); 
if(std<0) 
perror("创建socket错误"); 
bzero(&saddr, sizeof(saddr)); 
saddr.sin_family = AF_INET; 
inet_pton(AF_INET, server_ipaddr, &saddr.sin_addr); 
saddr.sin_port = htons(cport); 
connect(std, (struct sockaddr *)&saddr, sizeof(saddr)); 
while(1)
{ 
read(std, str, 20); 
if(strcmp(str, "Exit") == 0) 
{ 
printf("正在退出!\n"); 
break; 
} 
printf("收到: %s   错误?(1 - 是  0 - 否): ", str); 
scanf("%d", &choice); 
if(choice == 0)write(std, "-1", sizeof("-1")); 
else
{
printf("输入发生错误序列的帧号:"); 
scanf("%s", err); 
write(std, err, sizeof(err)); 
read(std, str, 20); 
printf("收到传输帧: %s\n", str); 
} 
} 
close(std); 
}


/* ****************************************************************
 *      文件名:  server.c
 *      描述:    本文件用于模拟滑窗协议服务器端
 *      编译:    Linux:   gcc -o server server.c
 *      可执行文件:      ./server
 *      作者:    段聪 01091138
 ******************************************************************/
#include<sys/types.h> 
#include<netinet/in.h> 
#include<arpa/inet.h> 
//滑动窗口大小
#define SIZE 4 
/*************************************************************************
  *      函数名:           main
  *      参数:             NIL
  *      返回值:           NIL
  *      描述:             主函数
***************************************************************************/
main() 
{ 
int std, lfd, len, i, j, status, sport; 
char str[20], frame[20], temp[20], ack[20]; 
struct sockaddr_in saddr, caddr; 
printf("输入端口号:"); 
scanf("%d", &sport); 
std = socket(AF_INET, SOCK_STREAM, 0); 
if(std<0) 
perror("创建socket错误"); 
bzero(&saddr, sizeof(saddr)); 
saddr.sin_family = AF_INET; 
saddr.sin_addr.s_addr = htonl(INADDR_ANY); 
saddr.sin_port = htons(sport); 
lfd = bind(std, (struct sockaddr *)&saddr, sizeof(saddr)); 
if(lfd) 
perror("绑定错误"); 
listen(std, 5); 
len = sizeof(&caddr); 
lfd = accept(std, (struct sockaddr *)&caddr, &len); 
printf("输入要发送的文本:"); 
scanf("%s", str);i = 0; 
while(i<strlen(str)) 
{ 
memset(frame, 0, 20); 
strncpy(frame, str+i, SIZE); 
printf("\n传输帧:"); 
len = strlen(frame); 
for(j=0; j<len; j++) 
{ 
printf("%d", i+j); 
sprintf(temp, "%d", i+j); 
strcat(frame, temp); 
} 
write(lfd, frame, sizeof(frame)); 
read(lfd, ack, 20); 
sscanf(ack, "%d", &status); 
if(status == -1) 
printf("\n传输成功!"); 
else 
{ 
printf("接收错误: %d", status); 
printf("\n重传帧:"); 
frame[0] = str[status]; 
frame[1] = '\0';write(lfd, frame, sizeof(frame)); 
} 
i = i + SIZE; 
} 
write(lfd, "Exit", sizeof("Exit")); 
printf("\n正在退出!\n"); 
sleep(2); 
close(lfd); 
close(std); 
} 


使用gcc进行编译:

gcc -o client client.c
gcc -o server server.c


产生两个可执行文件client server

运行程序



2018-08-01 17:36:45 nishisiyuetian 阅读数 1377
  • Android开源项目实践之UI篇

    本课程主要展现了如何利用Android开源代码进行app的开发。例如: 1.异步网络请求(android-async-http); 2.百变圆形滚动条(ProgressWheel);3.滑动导航栏(PagerSlidingTabStrip);4.瀑布流与上拉刷新,下拉加载完美结合(PinterestLikeAdapterView)...

    21768 人正在学习 去看看 李忠义

续上次 计算机网络实验 Go Back N (不含 ACK)滑动窗口协议 C++

今天实现了 带有 ACK 的

环境 :Microsoft Visual C++ 6.0

代码实现:

#include <iostream>
#include <cstring>
#include "protocol.h"
#include "datalink.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 MAX_SEQ 7  
// 超时规定   
#define DATA_TIMER  1200    
#define ACK_TIMER 300    
// 帧数据结构定义

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 )
            , ack ( _ack ) 
            , seq ( _seq )
        {}
    } One ;    // One 作为反复使用的帧

    // 事件参数
    int arg = 0 ;   
    // 物理层是否准备好了              
    int phl_ready = 0 ; 
    // 发送方的左边界    
    unsigned char ack_expected = 0 ;
    // 发送方的右边界 + 1
    unsigned char next_frame_to_send = 0 ;
    // 接受窗口正在移动的号
    unsigned char frame_expected = 0 ;
    // 发送窗口的数量
    unsigned char nbuffered = 0 ;
    // 存储发送窗口
    unsigned char out_buf[MAX_SEQ+1][PKT_LEN] ;
    // 令窗口滑动, 不超过 MAX_SEQ
    unsigned char Go_On ( unsigned char &NO ) {
        return NO = ( NO + 1 ) % ( MAX_SEQ + 1 ) ;
    }        
    // 判断 ack 是否落在发送窗口内
    int between ( unsigned char a , unsigned char b , unsigned char c ) {
        return ( ( ( a <= b ) && ( b < c ) ) 
              || ( ( c < a ) && ( a <= b ) ) 
              || ( ( b < c ) && ( c < a ) ) ) ;
    }
    // 添加 CRC 校验, 发往物理层
    void Add_Crc_and_Send ( unsigned char *frame , int len ) { 
        *(unsigned int *)( frame + len ) = crc32 ( frame , len ) ;
        send_frame ( frame , len + 4 ) ;
        phl_ready = 0 ;
    }
    // 发送一个数据帧
    void Send_Data_Frame ( unsigned char type , unsigned char frame_nr , 
                unsigned char frame_expected ) {
        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] , 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 , DATA_TIMER ) ;    
                break ;
            }
            case FRAME_ACK : {
                dbg_frame("Send ACK  %d\n" , One.ack ) ;
                Add_Crc_and_Send ( (unsigned char *)&One , 3 ) ;
                break ;
            }
        }    
        stop_ack_timer () ; // 现在我已经发出去了, 所以先暂停 ack          
    }
    // 网络层准备好了
    void Net_Layer_OK ()  {
        ++nbuffered ;                
        get_packet ( out_buf[next_frame_to_send] ) ;
        Send_Data_Frame ( FRAME_DATA , next_frame_to_send , frame_expected ) ;
        Go_On ( next_frame_to_send ) ;
    }
    // 收到一个数据帧
    void Recieve_Data () {
        // 先进行校验
        int len = recv_frame ( (unsigned char *)&One , sizeof One ) ;
        if ( len < 5 || crc32 ( (unsigned char *)&One , len ) ) {
            dbg_frame ( "Recv Bad packet\n" ) ;
            return ;
        }
        switch ( One.type ) {
            // 收到的是数据帧
            case FRAME_DATA : {
                if ( One.seq == frame_expected ) {
                    dbg_frame ( "Recv DATA %d %d , ID %d\n" , One.seq , One.ack , *(short *)One.data ) ; 
                    put_packet ( One.data , len - 7 ) ; // 减去七位非数据位
                    Go_On ( frame_expected ) ;
                    start_ack_timer ( ACK_TIMER ) ;
                }
                break ;
            }
            // 收到的是 ACK 帧
            case FRAME_ACK : {
                dbg_event ( "Recv ACK  %d\n" , One.ack ) ; 
                break ;
            }
            default : break ;
        }
        // 看是否可以腾出发送窗口的左边
        while ( between ( ack_expected , One.ack , next_frame_to_send ) ) {
            --nbuffered ;
            stop_timer ( ack_expected ) ;
            Go_On ( ack_expected ) ;
        }
    }
    // 协议初始化
    void Init_Protocol ( int argc , char **argv ) {
        protocol_init ( argc , argv ) ;
        lprintf ( "Fluence_YHL : " __DATE__"  "__TIME__"\n" ) ;
        disable_network_layer () ;
    }
    // 如果 ack 超时了
    void Data_Time_Out () {
        dbg_event ( "---- DATA %d timeout\n" , arg ) ;  
        // 要传的下一帧是 ack_expected, 也就是左边界    // Go Back N 就体现在这里   
        next_frame_to_send = ack_expected ;
        for ( int i = 1 ; i <= nbuffered ; ++i ) {
            Send_Data_Frame ( FRAME_DATA , next_frame_to_send , frame_expected ) ;
            Go_On ( next_frame_to_send ) ;
        }
    }

    void ACK_Time_Out () {
        dbg_event ( "ACK  %d  time is out " , arg ) ;
        Send_Data_Frame ( FRAME_ACK , next_frame_to_send , frame_expected ) ;
    }
    // 控制网络层开闭
    void Enable_Net_Layer () {
        if ( nbuffered < MAX_SEQ && phl_ready )
            enable_network_layer() ;
        else
            disable_network_layer() ;
    }
    // 获取一个事件
    int Get_event () {
        return wait_for_event ( &arg ) ;
    }
}

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 ;
            // 
            case ACK_TIMEOUT : YHL::ACK_Time_Out () ; break ;
            default : break ;
        }
        // 控制网络层流量
        YHL::Enable_Net_Layer () ;
    }
    return 0 ;
}

程序结果:
这里写图片描述
这里写图片描述

2014-04-09 17:44:17 Geggis 阅读数 1150
  • Android开源项目实践之UI篇

    本课程主要展现了如何利用Android开源代码进行app的开发。例如: 1.异步网络请求(android-async-http); 2.百变圆形滚动条(ProgressWheel);3.滑动导航栏(PagerSlidingTabStrip);4.瀑布流与上拉刷新,下拉加载完美结合(PinterestLikeAdapterView)...

    21768 人正在学习 去看看 李忠义


//NetRiver平台上的一个实验,用c语言实验1比特滑动窗口协议、回退N帧协议和选择性重传协议
//使用队列实现
#include "sysinclude.h"
#include <deque>

extern void SendFRAMEPacket(unsigned char* pData, unsigned int len);

#define WINDOW_SIZE_STOP_WAIT 1
#define WINDOW_SIZE_BACK_N_FRAME 4

bool fullWin = false;

typedef enum {data, ack, nak} frame_kind;
typedef struct frame
{
	frame_kind kind;	//帧类型
	unsigned int seq;	//序列号
	unsigned int ack;	//确认号
	unsigned char data[100];	//数据	
};

typedef struct Buffer {	//窗口中的帧
	frame *pframe;
	unsigned int size;
};
int back_n_frame_win = 0;
int choice_frame_resend_win = 0;
deque<Buffer> queue;

/*
* 停等协议测试函数
*/
int stud_slide_window_stop_and_wait(char *pBuffer, int bufferSize, UINT8 messageType)
{
	Buffer buffer;
	switch(messageType) {
		case MSG_TYPE_TIMEOUT: {	//某个帧超时
			buffer = queue.front();
			int serial;
			serial = ntohl(*(unsigned int *)pBuffer);
			//if(serial == ntohl(buffer.pframe->seq))
				SendFRAMEPacket((unsigned char *)buffer.pframe, buffer.size);
			break;
		}
		case MSG_TYPE_SEND: {		//系统要发送一个帧
			buffer.pframe = new frame;
			*buffer.pframe = *(frame *)pBuffer;
			buffer.size = bufferSize;
			queue.push_back(buffer);	//放入队尾
			if(fullWin == false) {
				buffer = queue.front();
				SendFRAMEPacket((unsigned char *)buffer.pframe, buffer.size);
				fullWin = true;
			}
			break;
		}
		case MSG_TYPE_RECEIVE: {	//系统接收到一个帧的ACK
			buffer = queue.front();
			unsigned int ack;
			ack = ntohl(((frame *)pBuffer)->ack);
			if(ntohl(buffer.pframe->seq) == ack) {	//发送序列号等于返回确认号
				queue.pop_front();
				buffer = queue.front();
				fullWin = false;
				if(queue.empty() == false)	//发送队列存在等待发送的帧
					SendFRAMEPacket((unsigned char *)buffer.pframe, buffer.size);
					fullWin = true;
			}
			break;
		}
		default: 
			return -1;
			break;
	}
	return 0;
}

/*
* 回退n帧测试函数
*/
int stud_slide_window_back_n_frame(char *pBuffer, int bufferSize, UINT8 messageType)
{
	Buffer buffer;
	switch(messageType) {
		case MSG_TYPE_TIMEOUT: {	//某个帧超时
			printf("timeout\n");
			int serial;
			serial = ntohl(*(unsigned int *)pBuffer);
			int i;
			for(i=0; i<WINDOW_SIZE_BACK_N_FRAME && i<queue.size(); i++) {
				buffer = queue[i];
				SendFRAMEPacket((unsigned char *)buffer.pframe, buffer.size);
			}
			break;
		}
		case MSG_TYPE_SEND: {	//系统要发送一个帧
			buffer.pframe = new frame;
			*buffer.pframe = *(frame *)pBuffer;
			buffer.size = bufferSize;
			queue.push_back(buffer);	//放入队尾
			//int i;
			//for(i=back_n_frame_win; i<WINDOW_SIZE_BACK_N_FRAME && i<queue.size(); i++) {
			buffer = queue[back_n_frame_win];
			if(back_n_frame_win < WINDOW_SIZE_BACK_N_FRAME && back_n_frame_win < queue.size()) {	
				SendFRAMEPacket((unsigned char *)buffer.pframe, buffer.size);
				back_n_frame_win ++;
			}
			break;
		}
		case MSG_TYPE_RECEIVE: {	//系统接收到一个帧的ACK
			int i, j;
			unsigned int ack;
			ack = ntohl(((frame *)pBuffer)->ack);
			for(i=0; i<WINDOW_SIZE_BACK_N_FRAME && i<queue.size(); i++) {
				buffer = queue[i];
				if(ntohl(buffer.pframe->seq) == ack) {	//发送序列号等于返回确认号
					for(j=0; j<=i; j++) {
						queue.pop_front();
						back_n_frame_win--;
						//printf("back_n_frame_win is %d\n", back_n_frame_win);
					}
					for(j=back_n_frame_win; j<WINDOW_SIZE_BACK_N_FRAME && j<queue.size(); j++) {
						buffer = queue[j];
						SendFRAMEPacket((unsigned char *)buffer.pframe, buffer.size);
						back_n_frame_win++;
					}
					break;
				}
			}
			break;
		}
		default: 
			return -1;
			break;
	}
	return 0;
}

/*
* 选择性重传测试函数
*/
int stud_slide_window_choice_frame_resend(char *pBuffer, int bufferSize, UINT8 messageType)
{
	Buffer buffer;
	switch(messageType) {
		case MSG_TYPE_TIMEOUT: {	//某个帧超时
			printf("timeout\n");
			int serial;
			serial = ntohl(*(unsigned int *)pBuffer);
			int i;
			for(i=0; i<WINDOW_SIZE_BACK_N_FRAME && i<queue.size(); i++) {
				buffer = queue[i];
				//if(serial == ntohl(buffer.pframe->seq))
				SendFRAMEPacket((unsigned char *)buffer.pframe, buffer.size);
			}
			break;
		}
		case MSG_TYPE_SEND: {	//系统要发送一个帧
			buffer.pframe = new frame;
			*buffer.pframe = *(frame *)pBuffer;
			buffer.size = bufferSize;
			queue.push_back(buffer);	//放入队尾
			//int i;
			//for(i=choice_frame_resend_win; i<WINDOW_SIZE_BACK_N_FRAME && i<queue.size(); i++) {	
			buffer = queue[choice_frame_resend_win];
			if(choice_frame_resend_win < WINDOW_SIZE_BACK_N_FRAME && choice_frame_resend_win < queue.size()) {	
				SendFRAMEPacket((unsigned char *)buffer.pframe, buffer.size);
				choice_frame_resend_win ++;
			}			
			break;
		}
		case MSG_TYPE_RECEIVE: {	//系统接收到一个帧的ACK
			int i, j;
			unsigned int ack;
			ack = ntohl(((frame *)pBuffer)->ack);
			if(ntohl(((frame *)pBuffer)->kind) == nak) {
				printf("nak\n");
				for(i=0; i<WINDOW_SIZE_BACK_N_FRAME && i<queue.size(); i++) {
					buffer = queue[i];
					if(ntohl(buffer.pframe->seq) == ack) {
						SendFRAMEPacket((unsigned char *)buffer.pframe, buffer.size);
						break;
					}
				}
			}
			else {	
				for(i=0; i<WINDOW_SIZE_BACK_N_FRAME && i<queue.size(); i++) {
					buffer = queue[i];
					if(ntohl(buffer.pframe->seq) == ack) {	//发送序列号等于返回确认号
						for(j=0; j<=i; j++) {
							queue.pop_front();
							choice_frame_resend_win--;
						}
						for(j=choice_frame_resend_win; j<WINDOW_SIZE_BACK_N_FRAME && j<queue.size(); j++) {
							buffer = queue[j];
							SendFRAMEPacket((unsigned char *)buffer.pframe, buffer.size);
							choice_frame_resend_win++;
						}
						break;
					}
				}
			}
			break;
		}
		default: 
			//return -1;
			break;
	}
	return 0;
}


2018-08-01 17:38:41 nishisiyuetian 阅读数 798
  • Android开源项目实践之UI篇

    本课程主要展现了如何利用Android开源代码进行app的开发。例如: 1.异步网络请求(android-async-http); 2.百变圆形滚动条(ProgressWheel);3.滑动导航栏(PagerSlidingTabStrip);4.瀑布流与上拉刷新,下拉加载完美结合(PinterestLikeAdapterView)...

    21768 人正在学习 去看看 李忠义

环境 : Microsoft Visual C++ 6.0

Go Back N 协议  ( 暂无 ack )

#include <iostream>
#include <cstring>
#include "protocol.h"
#include "datalink.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 MAX_SEQ 7  
// 超时规定   
#define DATA_TIMER  1200        
// 帧数据结构定义

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 _seq , unsigned char _ack )
            : seq ( _seq )
            , ack ( _ack ) 
        {}
    } One ;    // One 作为反复使用的帧
    
    // 事件参数
    int arg = 0 ;   
    // 物理层是否准备好了              
    int phl_ready = 0 ; 
    // 发送方的左边界    
    unsigned char ack_expected = 0 ;
    // 发送方的右边界 + 1
    unsigned char next_frame_to_send = 0 ;
    // 接受窗口正在移动的号
    unsigned char frame_expected = 0 ;
    // 发送窗口的数量
    unsigned char nbuffered = 0 ;
    // 存储发送窗口
    unsigned char out_buf[MAX_SEQ+1][PKT_LEN] ;
    // 令窗口滑动, 不超过 MAX_SEQ
    unsigned char Go_On ( unsigned char &NO ) {
        return NO = ( NO + 1 ) % ( MAX_SEQ + 1 ) ;
    }        
    // 判断 ack 是否落在发送窗口内
    int between ( unsigned char a , unsigned char b , unsigned char c ) {
        return ( ( ( a <= b ) && ( b < c ) ) 
              || ( ( c < a ) && ( a <= b ) ) 
              || ( ( b < c ) && ( c < a ) ) ) ;
    }
    // 添加 CRC 校验, 发往物理层
    void Add_Crc_and_Send ( unsigned char *frame , int len ) { 
        *(unsigned int *)( frame + len ) = crc32 ( frame , len ) ;
        send_frame ( frame , len + 4 ) ;
        phl_ready = 0 ;
    }
    // 发送一个数据帧
    void Send_Data_Frame ( unsigned char frame_nr , 
                unsigned char frame_expected ) {
        int ack = ( frame_expected + MAX_SEQ ) % ( MAX_SEQ + 1 ) ;
        FRAME One ( frame_nr , ack ) ;
        // 根据序号 frame_nr 获取要发送的数据字段
        memcpy ( One.data , out_buf[frame_nr] , 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 % MAX_SEQ , DATA_TIMER ) ;             
    }
    // 网络层准备好了
    void Net_Layer_OK ()  {
        ++nbuffered ;                
        get_packet ( out_buf[next_frame_to_send] ) ;
        Send_Data_Frame ( next_frame_to_send , frame_expected ) ;
        Go_On ( next_frame_to_send ) ;
    }
    // 收到一个数据帧
    void Recieve_Data () {
        // 先进行校验
        int len = recv_frame ( (unsigned char *)&One , sizeof One ) ;
        if ( len < 5 || crc32 ( (unsigned char *)&One , len ) ) {
            dbg_frame ( "Recv Bad packet\n" ) ;
            return ;
        }
        // 如果的确是接收窗口当前的序号
        if ( One.seq == frame_expected ) {
            dbg_frame ( "Recv DATA %d %d , ID %d\n" , One.seq , One.ack , *(short *)One.data ) ; 
            put_packet ( One.data , len - 7 ) ; // 减去七位非数据位
            Go_On ( frame_expected ) ;
        }
        // 看是否可以腾出发送窗口的左边
        while ( between ( ack_expected , One.ack , next_frame_to_send ) ) {
            --nbuffered ;
            stop_timer ( ack_expected ) ;
            Go_On ( ack_expected ) ;
        }
    }
    // 协议初始化
    void Init_Protocol ( int argc , char **argv ) {
        protocol_init ( argc , argv ) ;
        lprintf ( "Fluence_YHL : " __DATE__"  "__TIME__"\n" ) ;
        disable_network_layer () ;
    }
    // 如果 ack 超时了
    void Data_Time_Out () {
        dbg_event ( "---- DATA %d timeout\n" , arg ) ;  
        // 要传的下一帧是 ack_expected, 也就是左边界     
        next_frame_to_send = ack_expected ;
        for ( int i = 1 ; i <= nbuffered ; ++i ) {
            Send_Data_Frame ( next_frame_to_send , frame_expected ) ;
            Go_On ( next_frame_to_send ) ;
        }
    }
    // 控制网络层开闭
    void Enable_Net_Layer () {
        if ( nbuffered < MAX_SEQ && phl_ready )
            enable_network_layer() ;
        else
            disable_network_layer() ;
    }
    // 获取一个事件
    int Get_event () {
        return wait_for_event ( &arg ) ;
    }
}

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 ;
            // 
            default : break ;
        }
        // 控制网络层流量
        YHL::Enable_Net_Layer () ;
    }
    return 0 ;
}

 

tcp的复杂机制

阅读数 2110

没有更多推荐了,返回首页