这一节正式踏入LWIP协议TCP部分的大门。先来看看它是怎样来描述一个TCP连接的。这个结构灰常的复杂,这里的简单描述,也并不全面,并不能清晰说明各个字段的作用,在后续的TCP相关内容中,会对每个用到的字段详加讲解。结构体tcp_pcb的源代码如下:

struct tcp_pcb {

IP_PCB; //这是一个宏,描述了连接的IP相关信息,包括双方IP地址,TTL等信息

struct tcp_pcb *next;

//用于连接各个TCP控制块的链表指针

enum tcp_state state;

//TCP连接的状态,即为状态图中描述的那些状态

u8_t

prio; //该控制块的优先级

void *callback_arg;//

u16_t local_port; //本地端口

u16_t remote_port; //远程端口

u8_t flags;// 附加状态信息,如连接是快速恢复、一个被延迟的

ACK是否被发送等

#define TF_ACK_DELAY

(u8_t)0x01U //这些宏定义是为flags字段

#define

TF_ACK_NOW (u8_t)0x02U //定义的掩码

#define

TF_INFR (u8_t)0x04U

#define

TF_RESET (u8_t)0x08U

#define

TF_CLOSED (u8_t)0x10U

#define

TF_GOT_FIN (u8_t)0x20U

#define

TF_NODELAY (u8_t)0x40U

// 接收相关字段

u32_t

rcv_nxt; //期望接收的下一个字节,即它向发送端ACK的序号

u16_t

rcv_wnd; //接收窗口

u16_t rcv_ann_wnd;

//通告窗口大小,较低版本中无该字段

u32_t

tmr; // 该字段记录该PCB被创建的时刻

u8_t polltmr, pollinterval; //

三个定时器,后续讲解

u16_t

rtime; //重传定时,该值随时间增加,当大于rto的值时则重传发生

u16_t

mss; //最大数据段大小

//RTT估计相关的参数

u32_t rttest;

//估计得到的500ms滴答数

u32_t rtseq;

//用于测试RTT的包的序号

s16_t sa, sv;

//RTT估计出的平均值及其时间差

u16_t

rto; //

重发超时时间,利用前面的几个值计算出来

u8_t

nrtx; //

重发的次数,该字段在数据包多次超时时被使用到,与设置rto的值相关

// 快速重传/恢复相关的参数

u32_t lastack; // 最大的确认序号,该字段不解

u8_t dupacks; // 上面这个序号被重传的次数

// 阻塞控制相关参数

u16_t cwnd; //连接的当前阻塞窗口

u16_t ssthresh;  //

慢速启动阈值

// 发送相关字段

u32_t

snd_nxt, // 下一个将要发送的字节序号

snd_max, // 最高的发送字节序号

snd_wnd, // 发送窗口

snd_wl1, snd_wl2,  //

上次窗口更新时的数据序号和确认序号

snd_lbb; // 发送队列中最后一个字节的序号

u16_t acked; //

u16_t

snd_buf; // 可用的发送缓冲字节数

u8_t snd_queuelen; // 可用的发送包数

struct tcp_seg

*unsent; // 未发送的数据段队列

struct tcp_seg

*unacked; // 发送了未收到确认的数据队列

struct tcp_seg

*ooseq; //

接收到序列以外的数据包队列

#if

LWIP_CALLBACK_API //

回调函数,部分函数在较低版本没定义

err_t (* sent)(void *arg, struct

tcp_pcb *pcb, u16_t space);

err_t (* recv)(void *arg, struct

tcp_pcb *pcb, struct pbuf *p, err_t err); // 数据包接收回调函数

err_t (* connected)(void *arg, struct

tcp_pcb *pcb, err_t err);

err_t (* accept)(void *arg, struct

tcp_pcb *newpcb, err_t err);

err_t (* poll)(void *arg, struct

tcp_pcb *pcb);

void (* errf)(void *arg, err_t

err);

#endif

// 剩下的所有字段在较低版本中均未定义,用到时再讲解

u32_t keep_idle;

#if LWIP_TCP_KEEPALIVE

u32_t

keep_intvl; //

保活定时器,用于检测空闲连接的另一端是否崩溃

u32_t keep_cnt;

#endif

u32_t

persist_cnt; // 这两个字段可以使窗口大小信息保持不断流动

u8_t persist_backoff;

u8_t keep_cnt_sent;

};

先说说和接收数据相关的字段rcv_nxt, rcv_wnd,

rcv_ann_wnd和数据发送的相关字段snd_nxt,snd_max,snd_wnd,acked。这些字段都和TCP中有名的滑动窗口协议有密切关系。如下图所示,连接的双方都维持一个窗口用于数据的发送。滑动窗口把整个序列分成三部分:左边的是发送了并且被确认的分组,窗口右边是还没发送的分组,窗口内部是待确认的分组,窗口内部又分成已经发送待确认的,和未发送但将立即发送。TCP是通过正面确认和重传技术来保证可靠性的,滑动窗口可以使发送方在收到前一个分组的确认信息前发送下一个分组,这样提高了网络的带宽利用率。

除了发送窗口外,TCP连接的双方还各自维护了一个接收窗口,如下图,接收方的接收窗口和发送方的发送窗口对比起来看看数据包的交互过程。

在接收方,rev_wnd表示了自己接收窗口的大小,它可以在给发送方的ACK包中通告自己的窗口大小值,发送方接收到该值后,就以此设子自己的发送窗口大小值snd_wnd。发送方的发送窗口内包含的数据发送序列是与ACK序号密切相关的,即它将ACK序号以后的snd_wnd个字节序号包括在窗口内。发送方的acked字段就表示已经接收到的最高的ACK序号,snd_nxt表示发送方即将发送数据的序号,acked与snd_nxt之间的数据表示已经被发送但还未接收到ACK,发送方也必须将他们包括在滑动窗内,以方便超时重发,snd_nxt到发送窗口末端表示还未发送的数据。snd_max表示不解,MARKKKKK一下,后面再来看看。在接收方,接收处于滑动窗内编号的数据,当某个序号以前的所有序号都已经接收到后,则接收方可以ACK该序号,并将接收窗口向后滑动。发送方也接收到该ACK后,也将自己的发送窗口向后滑动。在接收方,re_nxt表示希望接收到的下个字节序号,rev_ann_wnd表示对方通告的窗口大小,这里也表示不解。凌乱,凌乱。。。

与发送相关的还有cwnd字段,这就涉及到慢启动的概念了。当发送方接收到接收方的窗口通告后,并不会一下子把窗口内允许的数据全部发送出去,因为这样做的话可能由于中间路由器转发拥塞等原因,造成网络吞吐量不稳定,带宽利用率低等不良现象。发送端的做法是用cwnd字段保存一个拥塞窗口,发送方取拥塞窗口与通告窗口中的最小值作为发送上限,拥塞窗口初始值一般取1,并在每次收到接收方的一个ACK后加上一个值。关于慢启动还会在后续内容中讲解。

lwip路由实现_TCP控制块《LwIP协议栈源码详解——TCP/IP协议的实现》相关推荐

  1. lwip路由实现_TCP超时与重传《LwIP协议栈源码详解——TCP/IP协议的实现》

    在TCP两端交互过程中,数据和确认都有可能丢失.TCP通过在发送时设置一个定时器来解决这种问题.如果当定时器溢出时还没有收到确认,它就重传该数据.对任何TCP协议实现而言,怎样决定超时间隔和如何确定重 ...

  2. OpenstackSDK 源码详解

    OpenstackSDK 源码详解 openstacksdk是基于当前最新版openstacksdk-0.17.2版本,可从 GitHub:OpenstackSDK 获取到最新的源码.openstac ...

  3. OkHttp3源码详解

    前言:为什么有些人宁愿吃生活的苦也不愿吃学习的苦,大概是因为懒惰吧,学习的苦是需要自己主动去吃的,而生活的苦,你躺着不动它就会来找你了. 一.概述 OKHttp是一个非常优秀的网络请求框架,已经被谷歌 ...

  4. 【Live555】live555源码详解(九):ServerMediaSession、ServerMediaSubsession、live555MediaServer

    [Live555]live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的三个类所在的位置: ServerMediaSession.ServerMediaSubsession.Dy ...

  5. 【Live555】live555源码详解系列笔记

    [Live555]liveMedia下载.配置.编译.安装.基本概念 [Live555]live555源码详解(一):BasicUsageEnvironment.UsageEnvironment [L ...

  6. 【Live555】live555源码详解(八):testRTSPClient

    [Live555]live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的testRTSPClient实现的三个类所在的位置: ourRTSPClient.StreamClient ...

  7. 【Live555】live555源码详解(七):GenericMediaServer、RTSPServer、RTSPClient

    [Live555]live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的三个类所在的位置: GenericMediaServer.RTSPServer.RTSPClient 14 ...

  8. 【Live555】live555源码详解(六):FramedSource、RTPSource、RTPSink

    [Live555]live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的三个类所在的位置: FramedSource.RTPSource.RTPSink 11.FramedSou ...

  9. 【Live555】live555源码详解(五):MediaSource、MediaSink、MediaSession、MediaSubsession

    [Live555]live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的四个类所在的位置: MediaSource.MediaSink.MediaSession.MediaSub ...

  10. 【Live555】live555源码详解(四):Medium媒体基础类

    [Live555]live555源码详解系列笔记 7.Media Medai所依赖关系图 依赖Medai关系图 Media和UsageEnvironment关联图

最新文章

  1. 可持久化线段树(主席树)【舰娘系列】【自编题】
  2. RightScale发布2017年度云调查报告
  3. java web分层的思想
  4. getdc 与getwindowDc的区别,loadbitmap 与loadimage的区别
  5. 【opencv系列05】OpenCV4.X鼠标回调函数
  6. java 微信 回复_微信java 开发2 发送文本消息并回复
  7. 倒计时按钮_办公小技巧:轻松玩转PPT秒针倒计时
  8. 拳王虚拟项目公社:利用减肥健身类虚拟资源项目,如何打造一套赚钱系统?
  9. ce修改服务器的数据库,数据库服务器的调优步骤
  10. LeetCode 207. 课程表(广度优先遍历)
  11. linux 系统启动级别,LINUX系统启动级别介绍与解释
  12. VS C++ 从字符串中查找字符最后一次出现的位置 strrchr
  13. PDF Expert for Mac(PDF阅读器) 2.4.29最新中文激活版
  14. ucserver admin.php,Discuz!X3.2 升级后ucenter、uc_server正确密码却无法登录后台的解决方法...
  15. 32-【算法与数据结构】伪代码与流程图
  16. 未充分说明劳务采购价格公允性、供应商合作合理性,电旗股份IPO被否.
  17. Oracle 转 PG- ERROR: recursive query “t“ column 2 has type character varying(150) in non-recursive t
  18. u盘中的隐藏文件该怎样恢复
  19. AUTOSAR MCAL PWM
  20. H3C设备的基本配置

热门文章

  1. 机械工程专业英语复习
  2. .NET-C#超文本编辑器FreeTextBox使用
  3. 方正字库中、英文、PS名称对照表
  4. java常用省份合集
  5. [读书笔记]小决心还是大决心
  6. un-app网易云歌词滚动功能
  7. [已解决]罗技鼠标驱动打不开问题
  8. Matlab 2016a 安装包及破解教程
  9. Java排序算法——冒泡排序(Bubble Sort)
  10. Java JSch 远程执行 Shell 命令