TCP/IP常见问题总结(二)

本文总结了TCP/IP中的滑动窗口协议,包括停等协议、GoBackN和选择性重发。接着探讨了HTTP报文结构,详细解析了状态码的含义,并列举了HTTP请求的多种方法。此外,还对比了HTTP 1.0与1.1的区别,如连接复用和Host头域。
摘要由CSDN通过智能技术生成

上一篇的传送门:TCP/IP常见问题总结(一)


6. TCP滑动窗口与回退N帧协议

TCP作为一个提供可靠服务的传输层协议,对于数据的发送必须拥有一套良好的反馈机制,让发送方得知接收方接收到了数据,而TCP下的反馈机制大部分借鉴与数据链路层的反馈机制,因此在此我们分析一下数据链路层的反馈机制。

1.停等协议

停等协议是一种非常简单的协议,发送方在发送完一帧数据后就一直等待接收方的确认信号(ACK),要是超时就重传数据,只到收到ACK信号后才发送下一帧数据。停等协议效率较低(如此低效数据链路层都不适用,TCP协议当然也不用了),其示意图如下:
停等协议

2.滑动窗口协议之GoBackN

由于发完一帧数据后发送方就挂起等待的行为非常低效,因此滑动窗口协议诞生了。滑动窗口的意思其实就是一个缓冲区(发送方为发送窗口,接收方为接收窗口),缓冲区的内容会随着数据的发送而移动,因此称为滑动窗口。
我们先来讲讲滑动窗口协议中的GoBackN协议。滑动窗口协议允许发送方连发数帧,每发一帧都对应 一个计时器timeout,而GoBackN协议要求发送方把丢失帧及其之后的帧全部重传(因为光凭一个ACK并不能确定哪些帧出现了丢失,ACK的含义是:期待接收序号为N的帧,之前所有的帧都已经成功收到并依此交给了上层)。其示意图如下:
GoBackN协议
上图由于Data2丢失,导致了Data2~Data5的重发(窗口大小为4)

3.滑动窗口协议之选择性重发

由于GoBackN中重发已经发送过的数据有点多余,因此选择性重发协议诞生了。选择性重发协议在ACK上引入了NAK的概念(否定性确认帧),表示小于N的帧已经全部收到并交给了上层,而第N帧丢失了,要求重发第N帧。当发送方接到NAK后,只要重发NAK表示的那一帧即可。其示意图如下:
选择性重发
上图中发送方发送的Data2丢失了,因此收到了接收方的NAK2,然后发送方只需重新发送Data2即可。
在TCP协议中使用的也是选择性重发协议。

7. Http的报文结构

Http协议(Hypertext
模仿数据链路层的gobackn协议 /*该协议是搭载ack的回退n步协议*/ #include #include "protocol.h" #define max_seq 7 #define flag 126 #define ESC 100 #define wait_time 2700 //发送计时器等待的时间 #define ack_wait_time 280 static int phl_ready = 0; unsigned char buf[max_seq+1][270]; unsigned char ack[8]; //发送空的ack帧 unsigned char in_buf[600], last_buf[520];//接收时的缓冲区;去掉冗余之后的缓冲区,为防备因误码两帧合并为一帧而定义了很大一个数组 int nbuffered=0; //发送的帧数 int buf_size[max_seq+1]; //记下以发送各帧的帧长 int next_frame_to_send=0; int frame_in_phl=0; //用于成帧 int frame_expected=0; int ack_expected=0; int between(int a,int b,int c) { if( ((a<=b)&&(b<c)) || ((c<a)&&(a<=b)) || ((b<c)&&(c<a)) ) return 1; else return 0; } //判断帧尾,防止出现误判esc esc flag为数据的情况 int end_flag(int in_len) { int count=0; int i; if(in_len=0;i--)//记录flag前的esc数目 count++; return count%2; //若flag前的esc为偶数,则为帧尾 }//成帧函数--数据帧 void send_frame(char *my_buf,int len) { int n; buf[frame_in_phl][0]=(frame_expected+max_seq)%(max_seq+1); //ack buf[frame_in_phl][1]=frame_in_phl; //发送帧的帧号 for(n=0;n<len;n++) buf[frame_in_phl][n+2]=my_buf[n]; //将处理过的新帧赋值到缓冲区中 len=len+2; *(unsigned int *)(buf[frame_in_phl]+len) = crc32(buf[frame_in_phl],len); //在原始帧的基础上加检验和 buf_size[frame_in_phl]=len+4; //记录当前帧的长度,包括3个帧头,4个检验和 nbuffered=nbuffered+1; //缓冲区占用数加一 frame_in_phl=(frame_in_phl+1)%(max_seq+1); } //成帧函数--ack帧 void send_ack() //ack帧的处理 { ack[0]=(frame_expected+max_seq)%(max_seq+1); ack[1]=max_seq+10; //ack帧的序号位,使ack[1]==frame_expected恒不成立 *(unsigned int *)(ack+2) = crc32(ack,2); //在原始帧的基础上加检验和 } //主函数 int main(int argc, char **argv) { int event, arg, n , m , i , j , len = 0 ,in_len = 0; unsigned char my_buf[260]; int phl_wait=0; //在物理层中还没有被发送的帧 protocol_init(argc, argv); enable_network_layer(); for (;;) { event = wait_for_event(&arg); switch (event) { case NETWORK_LAYER_READY:
(1)初始化。开网络层允许;ack_expected = 0(此时处于发送窗口的下沿);next_frame_to_send = 0,frame_expected = 0(初始化正在发送的帧和期待的帧序号);nbuffered = 0(进行发送窗口大小初始化);(2)等待事件发生(网络层准备好,帧到达,收到坏帧,超时)。(3)如果事件为网络层准备好,则执行以下步骤。从网络层接收一个分组,放入相应的缓冲区;发送窗口大小加1;使用缓冲区中的数据分组、next_frame_to_send和frame_expected构造帧,继续发送;next_frame_to_send加1;跳转(7);(4)如果事件为帧到达,则从物理层接收一个帧,则执行以下步骤。首先检查帧的seq域,若正是期待接收的帧(seq = frame_expected),将帧中携带的分组交给网络层,frame_expected加1;然后检查帧的ack域,若ack落于发送窗口内,表明该序号及其之前所有序号的帧均已正确收到,因此终止这些帧的计时器,修改发送窗口大小及发送窗口下沿值将这些帧去掉,继续执行步骤(7);(5)如果事件是收到坏帧,继续执行步骤(7)。(6)如果事件是超时,即:next_frame_to_send = ack_expected,从发生超时的帧开始重发发送窗口内的所有帧,然后继续执行步骤(7)。(7)若发送窗口大小小于所允许的最大值(MAX-SEQ),则可继续向网络层发送,否则则暂停继续向网络层发送,同时返回互步骤(2)等待。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值