1、简单理解几个接口函数:sendto,recvfrom,read,write,send,recv等等
这些函数并不是直把数据发送到网络中,而是将数据拷贝到缓冲区中,tcp到发送缓存区,udp直接到内核缓冲区,或者直接将内核缓冲区的数据拷贝到用户
至于什么时候发,发多少,丢包了呢,等等,皆由传输层协议搞定:tcp/udp
2、简单理解为啥要有协议:线太长,数据容易丢掉,需要tcp保证可靠性,ip定位设备
一、udp协议
报头格式:位段
任何协议都需要解决两个问题
1、将自己的报头和有效载荷进行分离
2、任何协议都需要解决,要将有效载荷交予上层的哪一个协议
udp为了将自己的报头和和有效载荷进行分离,采用了16位udp长度,即通过此处即可得到报头的总长度。通过16位目的端口号可将有效载荷交予上层应用。
udp的特点
1、无连接:有对方的ip和端口号就可进行传输,不需要链接
2、不可靠:没有确认机制和重传机制,只要发了就默认成功。
3、面向数据报:不能够灵活的控制读写数据的次数和数量。发送端一次sendto传来多少数据,udp直接一次recvfrom对应的数据。当然发送端如果数据太长(大于64k),则需要分包发送。
udp的缓冲区:
没有发送缓冲区,应用层直接sendto发送给内核,内核将数据传给网络层协议进行后续操作
有接受缓冲区:但是不能够保证发送方的udp顺序和接收方的一致。不同报文在网络中选择的路径不一样,到达顺序不一样,所以可能会导致双方顺序不一致。
udp也是全双工,因为udp的socket能读也能写。
二、TCP协议
报头格式:
TCP的特点
1、传输层协议,负责制定网络传输策略
2、面向链接的:进行网络收发数据前,必须建立链接成功。
3、可靠性:提供了确认应答机制、超时重传机制、流量控制机制、拥塞控制机制等等
4、面向字节流。将数据按照字节发送和接受
5、全双工:可同时发送和接收
tcp相比于udp的可靠性体现在:例如确认应答机制
tcp和udp的优缺点:
tcp可靠,但是机制复杂
udp,不可靠,但是简单,对于直播、打游戏等等之前的数据意义比较小,所以少量丢包不影响。
TCP报头的解释:
1、4位首部长度:1111代表15,最大字节为4*15 = 60,最小一般为0101,5*4 = 20
报头长度为 20 字节 到 60字节之间
2、
tcp是全双工的,双发发送的同时也是对对方的请求和应答。
使用两个序号,32位序号用来告知我发了多少,确认序号告知你应该从哪里发
使用序号保证了报文的顺序,解决了由于报文发送时选择路径不一致,导致收到的报文乱序,但是由于有序号,所以可以重新按照顺序排列好。是一种按序到达机制。
3、16位窗口大小
host1通过write、send等函数将应用层数据拷到tcp发送缓冲区,通过网络转移到 host2的接受缓冲区,接着通过recv、read等拷贝到应用层。
因为要多次收发,如果发送的数据已经超过了缓冲区的容量那该咋办呢?
通过报文中的16位窗口大小,表明自己的接受能力(自己的接受缓冲区中剩余空间的大小)。通过相互通报自己的接受能力给对方,tcp报文中的16位窗口大小,以达到两个方向上的传输速率的控制,这就叫做流量控制。
4、TCP的六个标志位
1、SYN标识该报文是一个链接建立请求的报文
2、ACK:设置为1表明是确认报文
3、RST:重置异常链接
4、PSH:对方接受缓冲区快要满了,但是应用层不读或者很慢,PSH告知对方尽快将缓冲区数据向上交付
5、URG:设置URG表明该报文有紧急数据,需要优先处理,16位紧急指针存放数据在报文中的地址
6、FIN:请求断开链接
SYN、ACK、FIN
SYN:为什么一定要有SYN,服务器在收到TCP报文的时候,一定会在一个时间段内收到多种报文,接收方需要知道哪些是断开链接,哪些是建立链接,哪些是正常通信的。
PSH:
主机B的窗口大小为0时,并且过了重发超时的时间后还没有收到窗口更新的通知,发送端发送一个窗口探测的包,接受端也会发送窗口更新通知
如果探测多次,对方依旧不读,依旧缓冲区满的,故发送携带PSH的报文,让对方赶紧读取
URG:紧急读取一个字节的数据
tcp是按时到达的,所以如果我想让后续的数据被优先读取并处理,是不可能的。
但是,tcp提供了优先处理数据的能力,设置紧急标志位
RST:重置异常链接
假设host1的ack,host2没有收到,但host1只要发送后,其就认为对方已经收到了。
这时host1向host2发送数据,host2则发送一个含有RST=1的报文,请求重新建立链接
5、确认应答、链接管理、流量控制、按序到达(具有去重功能)皆已经介绍
超时重传:
当我长时间没有收到你的应答,我认为数据丢失了,要进行超时重传。如果是我的数据在网络中丢包了,里说应当重传。但如果是你的应答丢包了(我的数据传到了咋办?),有32为序号和确认序号保证TCP层的去重功能
三、三次握手
connect:套接字编程时的客户端connect就是发起链接请求(SYN),只要其返回值大于0,客户端就认为链接成功了。
accept:返回的本质在于:服务器认为握手成功,然后可以返回链接。
为什么要三次握手?不是4次,5次呢?
首先,可以最小次数验证全双工
其次,如果最后一次ack链接失败,那么维护链接的成本在客户端(奇数次)
这是由于链接需要管理,需要先描述在组织,是有成本的,建立链接不一定能成功,所以要以最大的概率,最小的成本建立链接成功。由于服务端要链接大量客户端,所以不能承受这种成本。
四、四次挥手
为啥建立链接是三次,而断开链接是四次?
因为建立链接是奇数次时,最后一次丢包成本由客户端承受,所以要保证奇数次,其次由于捎带应答机制将ACK和SYN在一个报文中发送,所以是三次
对于断开链接而言,双端断开链接的时间是不相同的,所以需要逐一进行发送,如果想要同时断开链接也可以三次挥手,所以断开链接的本质是双方达成断开的共识,四次是双方协商断开链接的最小次数。双方各两次。
1、 理解CLOSED_WAIT状态
当client端首先发起请求FIN后,server端处于CLOSED_WAIT状态
客户端收到ACK后处于FINAL_WAIT2,最终客户端进入TIME_WAIT状态,接着CLOSED
注意:如果服务不停下来,一旦有链接是close_wait状态,可能会维持比较长的时间,如果我们发现我们的服务器上有大量的close_wait状态,一定要注意是否你的服务器有bug,导致没有正确的关闭sock。
服务器接着会进入LAST_ACK(如果关服务器会立刻进入),由于客户端已经关了,所以,其最终进入CLOSED状态。
2、理解TIME_WAIT状态
主动断开链接的一方,最终要进入一个状态叫做TIME_WAIT
注意:由于主动断开链接的一方处于TIME_WAIT状态,所以服务器(主动)一旦断开,再起来的时候一直起不来,注意使用setsockopt函数
为什么要进行TIME_WAIT:
1、为了保证历史数据在网络中消散
2、四次挥手依旧担心最后一个ACK丢失:
由于TCP协议规定主动断开链接的一方要处于TIME_WAIT状态,等待两个MSL(maximum segment lifetime)的时间后才能回到CLOSED状态。所以,当最后一个ACK对方没有接受到时,可能再次发送FIN给你,你可以再次发送ACK给对方,最大概率的保证链接是正确四次挥手的
五、滑动窗口
背景:1、发送方发送数据的时候,把数据放入网络中,并不一定完成发送过程,在我们没收到ACK时,刚刚发送的数据需要保存起来
2、发送方发送数据不一定是一个发送,一个应答。可以一次发送多个报文,只要最后一个报文都有ACK即可。
窗口大小是无需等待确认应答,而可以继续发送数据的最大值
8.1 滑动窗口的两层理解
1、滑动窗口只能整体右移吗?能缩小,能扩大吗?
在链接阶段,双方就已经告知对方自己的接受缓冲区大小。故接收方缓冲区变大,窗口可以变大,缓冲区变小窗口就变小,不变就整体右移。
2、如何理解滑动窗口?我们如何设计
可以让发送方一次发送大量的数据,保证效率。配合对端的接收能力,完成流量控制。
可设计成环形数组,这样不会移出我们的发送缓冲区。
8.2 丢包情况理解
1、接收方的报文全都收到了,但是给发送方的应答有两个丢掉了,只要发送方收到应答中的最大值大于丢失的值,就按最大值考虑。
2、确实丢包了,会在次发送给接收方(通常是3次的请求报文)
六、拥塞控制:
网络很庞大,状态不稳,加上滑动窗口可以大量发送数据。有可能造成网络拥塞。
拥塞避免机制:
快恢复机制
七、延迟应答和捎带应答
八、TCP面向字节流
12、粘包问题
九、int listen(int sock_fd,int backlog)