提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
7.延迟应答
8.捎带应答
9.面向字节流
10.tcp中的异常处理
程序崩溃了
正常关机
主机掉电
接收方掉电
发送方掉电
网线断开
二、总结tcp和udp的对比
三.网络层
ip协议报文格式
这篇文章是基于上文《tcp》机制的补充部分并介绍了ip协议相关知识
提示:以下是本篇文章正文内容,下面案例可供参考
提高传输效率的机制,又是基于流量控制,来引入的提高效率的机制
还是水池的例子:
当接受1kb的数据时,此时水位上涨1kb,剩余空间9kb,如果立即返回ack,此时窗口大小就是9kb
但是当我们稍等一会再返回ack(过了个几十ms)很可能在这几十ms之内,应用程序从缓冲区取走了一大波的数据,取走5kb,此时剩下的水位就是6kb了
通过把应答的时间稍微拖后一点,趁着这个时间,应用层赶紧处理系统缓冲区数据,这样就能保证后续应答时候欠的债少了
但实际上tcp的延时时间,不一定是非用时间来衡量的,也可以是传输轮次衡量如图:
基于延时应答又引入一个机制
网络通信中,典型通信模型是一发一收
前面讲过tcp将数据传输过去,对方收到后,就会立刻由内核返回一个ack报文,响应数据则要稍等一会,由应用程序调用socket负责传输
由于时机不同,正常情况下不能合并,但是由于延迟应答,本来ack立即返回,现在等一下,在这个时间,正好业务上也要返回这个响应,此时就可以把俩个报文合二为一了(应用程序调用socket的write方法将数据最终交给内核,内核进行封装,进行发送)
注意这俩操作能否合并成一个,不是100%的,主要还是看应用程序啥时候返回响应
在面向字节流中,有一个典型的问题:粘包问题
举个例子,某一天a向女神发了一串消息(做我女朋友好不好?)对方回复好个p,由于粘包问题,你可能收到的是好,好个,好个p,意思就变了
实际上tcp(或者其他面向字节流传输的方式),也是如此,都是有一个接收缓冲区的,a的应用程序从接收缓冲区读取收到的数据
由于是面向字节流,a是无法确定从哪到哪,是完整的应用层数据报
a就可能把好,好个甚至好个p当成完整的响应
事实上udp数据包,不存在上述问题,因为一个udp数据包就是一个应用层报文,tcp自身是对应用层数据报无法区分的
解决方式:
从应用层协议区分:在定义应用层数据协议的时候,明确包和包的边界就可以了
典型的俩种:
1.通过分割符,比如约定使用;作为包的结束标记
2.通过指定包的长度,比如在数据包的开头位置声明长度
前面讲过自定义应用层协议的几个典型实现方式:
连接异常了怎么办?
有如下几种情况:
这种情况也就是程序异常退出,操作系统会回收进程的资源,包括释放文件描述符表,这样的释放操作,就相当于调用了对应的socket的close执行close就会触发fin报文,进一步的开始四次挥手
这种情况其实和普通的四次挥手没什么区别
也就是通过开始菜单关机
类似上述进程崩溃,关机时先强制结束所有用户进程,系统内核,会进行文件描述符表的释放操作,进一步的进行四次挥手
这种情况是猝不及防的,很有可能损失硬盘
发送方不知道对方挂了,继续发数据
此时发的数据,没有ack了,发送方会触发超时重传,重传几次,仍然无应答,尝试重新连接(复位报文),连接失败,只能放弃连接了
此时接受方就等着(也不是干等)
等了一阵,发一个心跳包,周期触发,是一个不携带任何业务数据的包存在的意义就是确认一下对方是否存在
如果对方不返回心跳包,说明心跳遗失,对方挂了,此时也会放弃连接
类似于我们打电话,无法确认对方掉线会问一句在嘛,是和电话内容没关的,只是想确任是否连接终端,如果对方回复在,返回心跳包,说明连接正常
情况同主机掉电,只不过通信双方主机都好着呢,两端各自按上述执行
公司突然没网了,但是电脑却没关机,重新建立连接
各自应用场景不同
tcp对可靠性要求比较高,用到tcp非常广泛
udp对可靠性要求不高,对传输效率要求很高
例如机房内部内网传输,压力小,不容易丢包,传输效率也比较高,用到udp
如何使用udp实现可靠传输,其实考查的是tcp,基于udp在应用层实现确认应答,超时重传,引入序号.....
上述是传输层部分,接下来介绍网络层部分
网络层要做的工作,就是在两点之间规划处一个合理的路径,同时对主机所在的位置进行定义
这里网络层做的工作
1.地址管理
2.路由选择
首先认识一下
4位版本号实际上只有2个版本(4bit)
这里介绍一下,想要计算tcp的报文长度,tcp协议是不能解决的,需要在ip协议里由ip总长度-ip报头长度就是tcp报文长度
8位服务类型,实际上就是状态的不同,可以自由切换
16位总长度算下来是64kb,但是由于ip协议自带分包操作可以传输更多数据:
下面是16位总长度报文包含的:
例如一堆东西,一辆车拉不下,用多辆,每辆车拉其中一部分
车都是我找的,在一个包下,16位标识符相同,先找的车,片位移小,后找的大,最后一辆车特殊标记一下
8位生存时间TTl:
ttl的单位是次数,是一个整数,一般是32/64/128这样的整数,数据包经过传输时,每经过一个路由器转发,ttl就-1,如果-到0了,就要丢弃包(不要继续转发了),预期正常情况下,数据包可以在很短的次数内就能插损胡到世界上的任何一台主机上
例如我们通过ping向百度发一个特殊的请求
经过64-53=11次交换完成
8位协议
32位源ip,目的ip地址
ip地址最多能表示的范围是不到43亿,那么如何够全世界网络使用
1.动态分配ip地址
设备上网的时候才分配ip地址,不上网,回收ip给别人用
2.nat机制(主流机制)
局域网内部ip不重复
外允许
举个例子:
运营商路由器还连接着千家万户的设备,这样一个外网,就可以代替多个设备了,这样用一个ip地址代替很多设备,自然就节省了ip地址的个数