传输层
TCP协议
报头与有效载荷如何分离?如何将有效载荷交付给上层?
固定长度+自描述字段(4位首部长度)
根据目的端口号交付给相应的上层协议或应用程序。
TCP协议格式

4位首部长度:头部长度,单位4字节,范围就是[0,60],如果有选项,头部长度-20字节就是选项大小

TCP三次握手和四次挥手
三次握手建立连接
为什么是三次握手?
1、三次握手可靠验证了全双工
2、奇数次握手,把失败成本嫁接给了客户端
client在第三次ACK之后,就认为连接已经建立完成了,所以资源都准备就绪了,失败成本就会在client端
细节:
1、三次握手和上层accept没有关系,都是操作系统自动完成
2、上层listen函数第二个参数backlog,backlog+1表示已经建立好连接的全连接队列最大长度
3、server端,不会长时间维护SYN_RECVD,被建立连接的一方,会把SYN_RECVD放入半连接队列,该队列中节点不会长时间维护
4、主动断开连接的一方,在四次挥手之后,会进入TIME_WAIT状态,等待若干时长后自动释放
TIME_WAIT等待多少时间?为什么?
1)一般是60~120秒
2)让双方历史通信数据消散
3)让双方在四次挥手时,有更好的容错性

出现bind错误的原因是什么???
连接没有彻底断开,ip和端口号还在继续使用
解决办法:


注:
逻辑上两台主机之间在传输层之间直接进行三次握手和四次挥手
但是实际上是需要网络层和数据链路层的参与
TCP可靠性
1、校验和
发送端填充, CRC校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含TCP首部, 也 包含TCP数据部分
2、序列号
保证数据在放送时,接收方接收到的时的正确顺序
3、确认应答
ACK,保证对方主机收到我发出去的数据,收到ACK之后再发下一个数据段
4、超时重传
再特定时间间隔内,发出去的数据没有收到ACK,就会重新发
5、连接管理
三次握手和四次挥手
6、流量控制
如果发送缓冲区数据发送过快,立刻把对方的接收缓冲区打满,如果再继续发送,就可能会导致丢包问题
滑动窗口
一般使用滑动窗口来实现流量控制
窗口大小是由对方接收缓冲区决定的
怎么知道对方的接收缓冲区大小的?
在三次握手之后,双方交换了报文,已经具有协商沟通的能力
双指针来控制窗口大小
确认序号:确认序号xxx,表示xxx之前的都接收到了(允许少量ACK丢失)


7、拥塞控制
如果在网络情况拥堵的的情况下,一开始就发送大量数据,可能会导致网络直接崩掉
拥塞控制也就是**"慢启动"**,先发少量数据,之后指数增长数据量

TCP提高性能机制
1、滑动窗口
2、快重传
如下图所示为快重传,当收到三次重复的确认应答,主机A就会直接重发1---1000数据段的内容

3、延迟应答
一次传输的数据越大效率越高
窗口越大,传出数据越大
怎样让窗口越大?
可以让对方read和recv尽快把缓冲区中的数据读走
4、捎带应答
把数据和ACK应答一起发送,提高效率
面向字节流
创建TCP的socket时,创建了一个接收缓冲区和一个发送缓冲区
一个连接既可以写又可以读,这种被称为全双工
接收方读缓冲区直接冲对方写缓冲区中读,序列号确定了读的顺序,所以确定了TCP是面向字节流的
用户对报文一个个处理,将字节流变成一个个请求
但是这里就会出现一个问题,怎么保证拿到的就是一个完整的报文???
粘包问题
当从缓存区拿到的不是一个完整的报文,就会出现粘包问题
解决办法:定协议(Decode 和 Encode)
明确报文与报文之间的边界
1、使用定长报文
2、使用特殊字符
3、定长报头+自描述字段
4、定长报头+特殊字符
TCP异常情况
1、进程终止:连接正常断开
2、重启:关闭所有进程,连接断开
3、机械断电:正常四次 挥手,保活机制
网络层
IP协议
如何将报头与有效载荷分离?
固定长度+自描述字段
如何将有效载荷交付给上层?
8位协议

4位版本号(version): 指定IP协议的版本, 对于IPv4来说, 就是4.
4位头部长度(header length): IP头部的长度是多少个32bit, 也就是 length * 4 的字节数. 4bit表示最大 的数字是15, 因此IP头部最大长度是60字节.
8位服务类型(Type Of Service): 3位优先权字段(已经弃用), 4位TOS字段, 和1位保留字段(必须置为0). 4位 TOS分别表示: 最小延时, 最大吞吐量, 最高可靠性, 最小成本. 这四者相互冲突, 只能选择一个. 对于 ssh/telnet这样的应用程序, 最小延时比较重要; 对于ftp这样的程序, 最大吞吐量比较重要
IP分片
在数据链路层,要求上层不能发过大的报文,所以会产生IP分片(TCP流量控制也是为了不发过大的报文到下层)

16位标识(id): 唯一的标识主机发送的报文. 如果IP报文在数据链路层被分片了, 那么每一个片里面的这个 id都是相同的.
3位标志字段: 第一位保留(保留的意思是现在不用, 但是还没想好说不定以后要用到). 第二位置为1表示禁 止分片, 这时候如果报文长度超过MTU, IP模块就会丢弃报文. 第三位表示"更多分片", 如果分片了的话, 最后一个分片置为1, 其他是0. 类似于一个结束标记.
13位分片偏移(framegament offset): 是分片相对于原始IP报文开始处的偏移. 其实就是在表示当前分片 在原报文中处在哪个位置. 实际偏移的字节数是这个值 * 8 得到的. 因此, 除了最后一个报文之外, 其他报 文的长度必须是8的整数倍(否则报文就不连续了).

如上图所示,IP分片之后,每个分片都要有报头
细节问题:
如何检查是否有片丢失?
1)前面的片都可以用片偏移来判断是否丢失
2)最后一个可以通过三位标志字段最后一位来判断,因为只有最后一个片是0
如何组装分片?
片偏移排序
为什么不建议分片?
因为任何一个片丢失,都需要重新发送,增加了丢包的概率
IP协议的本质就是提供一种能力,将数据从A主机跨网络传到B主机
通过路由器进行下一跳到另一个路由器,直到到达目的主机所在的路由器网络
网络中那么多路由器,怎么直到要怎么下一个路由器的??
每个路由器节点都维护一张路由表,查表就知道目标IP地址该怎么走
路由器:不仅可以进行ip地址转发,还可以构建子网
特殊IP地址
主机IP地址全设为0,表示的就是该局域网
主机IP地址全设为1,表示广播,向该局域网内所有主机发送数据
数据链路层
IP协议找到目的主机所在的局域网,这里就需要在局域网找具体的物理地址
为什么IP协议已经找了局域网,为什么不直接找目的IP地址??
因为IP地址是可以重复使用的
MAC地址
表示唯一的地址
arp协议
在一个局域网中,主机A要给主机B发送消息,就要知道主机B的MAC地址
1、主机A以广播方式向所有主机发送arp请求(如果arp表中没有主机B的MAC地址就会广播)
2、所有主机接受请求后舍弃,只有主机B才会接受,并且应答,应答中就带有自己的MAC地址
因为在A主机广播时就带有自己的MAC地址,所以B主机就能够直接给主机A发送arp应答
arp协议属于数据链路层,但是是在mac地址之上的