【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

时间:2021-10-17 01:10:51
  1. netstat命令

  • -n.拒绝显示别名,能显示数字的全部转化成数字(IP+PORT)

  • -l 仅列出有在 Listen (监听) 的服务的状态

  • -p 显示建立相关链接的程序名(pid)

  • -t 仅显示tcp相关选项

  • -u 仅显示udp相关选项

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

2.UDP协议

2.1.全双工和半双工的区别

全双工:可以双方同时传输数据,UDP协议和TCP都是全双工
半双工:一次只能一方传输数据;

2.2.UDP的特点

1.无连接:知道对端的IP和端口号就直接进行传输, 不需要建立连接 ;
2.不可靠:没有应答机制和重传机制;
3.面向数据报:不能够灵活的控制读写数据的次数和数量 ;
1.必须接受一个完整的报文,不能分两次接受半个报文在拼接;
2.UDP一次只能发送2^16个字节大小的数据,如果超过只能在应用层拆分,再在对端的应用 层合并;

2.3.UDP协议格式

16位源端口号:发送端端口号
16位目的端口号:接受端端口号
16位UDP长度:UDP首部(UDP报头)+UDP数据(UDP有效载荷);整个数据报的总长度
16位UDP检验和:如果校验和出错, 就会直接丢弃;
【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

2.4.UDP的缓冲区

过程:调用系统接口read把缓冲区的数据拷贝到应用层,write直接向内核交付数据

UDP协议只有接受缓冲区:因为没有重传机制和应答机制;

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.TCP协议

3.1.tcp协议格式

16位源端口号:发送端端口号
16位目的端口号:接受端端口号
【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.2.首部长度和序号

TCP的报头标长是20字节;

4位首部长度:4个比特位可以表示0-15;报头长度=首部长度*4;所以最大的报头为4*最大首 部长度(15)=60;报头长度在20-60可以被4整除的数;

序号:每个报文都会被设置一个序号;一个报文在发送缓冲区最大那一个下标,下面这个报文的序号是1000;

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

确定序号:表示确定序号之前的序号对应的报文被对端接受了;例:确定序号101,表示101序号以前的序号对应的报文都被接受了,下次使用101序号传输;

3.3.确认应答机制

  • 收到确定报文表示确认序号以前的序号已经被接收;并且确定报文中16位窗口大小被设置表示接收端的接受缓冲区还有多少空间,

  • 如果没收到确定报文,发送端默认对端没有收到将重传;

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.4.TCP协议的缓冲区

TCP协议有两个缓冲区:发送缓冲区和接受缓冲区

过程:调用read实际就是把数据拷贝到发送缓冲区,write把数据从接受缓冲区拷贝到应用层
特点:
1. 效率提高 ,因为应用层把数据拷贝到发送缓冲区就结束了就返回;
2. 应用层和传输层的解耦 ,因为应用层把数据拷贝到发送缓冲区,数据就不用应用层管理
【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.5.六位标志位

标志位的概念:用于区分不同的报文,确定报文、连接报文等等;

  • 一个标志是3个英文字母总共3字节,有6位的标志位有6字节,所以一次最多设置2个标志,也可以一个都不设置;

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

6个标志:

前4个标志在3次握手4次挥手讲

ACK: 设置与否表示确认序号是否有效
SYN: 请求建立连接; 我们把携带SYN标识的称为 同步报文段 FIN: 通知对方, 本端要关闭了, 我们称携带FIN标识的为 结束报文段 RST: 对方要求重新建立连接; 我们把携带RST标识的称为 复位报文段
URG: 紧急指针是否有效 PSH: 接收端的接收缓冲区快满了发送端没法传输数据了,提示接收端应用程序立刻从TCP缓冲区把数据读走;

URG(不是很重要):优先先读URG报文不用按序到达,只会读被紧急指针下标的那个字节

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.6.超时重传机制

TCP协议会统计正常通信的时间;来设置一个超时重传的时间

3.7.TCP3次握手,为什么是3次

3次握手过程

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.7.1.第一个原因:3次握手是最小次数,可证明全双工的双端的网络通信信道是正常

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.7.1第二个原因:防止SYN洪水;

1/2握手server端会先于client端建立连接

  • 那么client端可以无消耗让server建立一个与client的连接并管理起来(消耗server资源);

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.8.TCP的4次挥手及TIME_WAIT的解释

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.8.1.TIME_WAIT为什么要有这个状态

  • 不能直接CLOSED因为还有给对端发送ACK;

3.8.2.TIME_WAIT需要等多久呢?为什么?

等待时间:需要等2倍MSL时间;

  • MSL(maximum segment lifetime)时间:MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同, 在Centos7上默认配置的值是60s,并且TCP协议也有自己的一套方法,统计多个正常一次通信的时间,取最大的一个做MSL;

为什么是2MSL

  • 一个来回是2MSL,ACK没被接受就会重发FIN,刚好一个来回的时间2MSL;

  • 2MSL保证历史发的数据在网络中消散如果server不等待2MSL直接断开,对面没有收到ACK,将会重发FIN,server立马重连收到重发的FIN又会断开不符合我的要求

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.8.3.CLOSE_WAIT

如果服务器端,在客户端请求关闭连接,服务器端accept的文件描述符不关闭,会在保持CLOSE_WAIT状态(文件描述符泄漏)

服务器端:只能accept的文件描述符但是不处理

int main()
{
    int listen_sock=socket(AF_INET,SOCK_STREAM,0);
    //bind服务器
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port=htons(PORT);
    local.sin_addr.s_addr=INADDR_ANY;
    bind(listen_sock,(struct sockaddr*)&local,sizeof(local))

    listen(listen_sock,5);

    struct sockaddr_in tmp;
    socklen_t tlen=sizeof(tmp);
    //建立连接
    int fd=accept(listen_sock,(struct sockaddr*)&tmp,&tlen);
}
【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.9.滑动窗口

滑动窗口的作用:发送报文不用立即ACK可以继续发送一些报文

滑动窗口的大小:

  1. 跟接收端的窗口大小(接收缓冲区)有关;

  1. 在3次握手就设置好了滑动窗口的大小;

  1. 滑动窗口大小不是一直不变的;window_start+=ACK(不一定是一个报文可能是多个),window_end+=接收端的16位窗口大小;

三部分依次:1.以确认的报文;2.已发送/可以发送但是没有收到ACK的报文;3.还不能发送的报文

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.9.1.流量控制

因此TCP支持根据接收端的处理能力(窗口大小), 来决定发送端的发送速度. 这个机制就叫做流量控制(Flow Control);

  • 在3次握手就设置好了滑动窗口的大小就是依靠流量控制;

  • 如果接收端的窗口满了就会返回的窗口大小为0;发送端定期发送一个窗口探测报文(标志位设为PSH并且不携带数据);

3.9.2.快重传

连续收到3个及以上的确认序号的ACK,那么会重发下一个,这种机制被称为 "高速重发控制"(也叫 "快重传");

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.10.拥塞控制

再开始通信时,并不知道网络情况怎么样,是否拥塞;所有不能通信一开始就发送大量的数据,免得已经拥塞的网络,更加拥塞;

过程(慢启动:前面慢后面快):拥塞窗口初始化时为1;先按指数增长,碰见网络拥塞时,把拥塞窗口的一半做为阈值;

再把阻塞窗口置为1,先按指数增长达到阈值,再按线性增长,再次碰见网络阻塞;(循环这一步)

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

滑动窗口大小=min(阻塞窗口,接受端的窗口大小);

3.11.延迟应答和捎带应答

3.11.1延迟应答

原因:如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小(接受端的应用层也在read数据);

  • 窗口越大, 网络吞吐量就越大, 传输效率就越高. 保证网络不拥塞的情况下尽量提高传输 效率;

也是有限制的,一般数量(多少个报文就返回一个ACK)限制:2,时间限制:最大延迟时间:200ms;不同的操作系统可能不同;

3.11.2.捎带应答

携带数据的报文并设置ACK标志位,大多数的报文都是这样的;

3.12.粘包问题

tcp的接受缓冲区是一串连续的字节数据,没有区分的边界,如何把一个个数据包分离出来:

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

从应用层来解决:

  1. 特殊字符

  1. 自描述字段

  1. 固定长度

http就是使用特殊字符+自描述字段来处理粘包问题的;

  • 空行分离报文和有效载荷

  • 如果存在Content-length自描述字段,那么就有有效载荷并且Content-longth的数值表示有效载荷的字节数;

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等

3.12.1.UDP有粘包问题吗?

A:没有;

表示报头中包含一个16位UDP长度表示UDP报文有多少字节数,并且UDP报头是固长8字节的,UDP长度- 8=一个数据包;UDP的接受缓冲区一次只会交付给应用层一个数据包;

【Linux 网络编程4】网络层--UDP/TCP协议,3次握手4次挥手、粘包问题等