客户端建立连接的步骤一般是socket、bind、listen、accept、recv、send、close等,文章将按照这个顺序介绍每个api的功能。
socket:
创建服务器的文件描述符(将列表中对应位置的fd置为1,默认从3开始),同时分配tcp控制块。
bind:
绑定fd和IP端口
listen:
listen被调用时将对应的fd中的tcp状态设置为监听状态,使其能够被访问。
listen连接队列的迭代:
listen即监听函数经过三次变化,最初只存储syn,这种方式在第一次握手就会占用内存,无法应对ddos攻击,后来衍生了存储syn和accept的方式,同时存储半连接和全连接,能监控半连接的比例从而一定程度上防御ddos,后来由于堡垒机的普及,不再需要个人做ddos防御,故发展为当代的存储accept的形式,只存放全连接。
accept:
进行三次握手并开始与客户端建立tcp连接。
三次握手的理解:
第一次握手:
客户端调用connect向服务器发送一次tcp报文,包含syn和ins,即协议中的syn位置为1,表示请求连接,ins为随机数,表示客户端序列号,用于记录信息发送的起始位,然后进入syn_send状态
第二次握手:
服务端收到第一次握手信息后向客户端返回一个tcp报文,包含ack、syn、确认号(客户端序列号+1)、服务端随机序列号,并进入syn_resave状态
第三次握手:
客户端返回ack以及确认号(服务端序列号+1)并进入establish状态,服务端收到ack后也进入establish状态,自此双端连接建立。
三次握手的调用时机:
当accept被调用时会触发三次握手,此时会发生两件事:客户端fd的分配以及建立fd:tcp的映射。
触发方式:
通常适合水平触发(FT),如果要用边沿触发(ET)建议用死循环运行accept,直到返回fd为-1,以满足同时多个用户访问的场景。
特殊情况:
通常连接由客户端单方面发起,但在P2P中连接请求会由双方发起,走两遍三次挥手
send:
send的作用是将数据加载到系统内核,由系统决定数据发送的时机,当数据发送后客户端的协议栈开始接收,并在接收完成后程序主动调用recv函数。
每次send的数据最大大小为固定值,可以通过ifconfig查询mtu:
apt-get install net-tools
ifconfig
mtu建议修改为1400,以防止被有些路由器拦截,将eth0修改为你的网卡号:
sudo ifconfig eth0 mtu 1400
数据分片:在数据发送之前对数据做分片处理,接受数据的时候对数据按顺序进行重组。
到达确认:接收端接收到分片数据时,根据分片数据序号向发送端发送一个确认。
超时重发:发送方在发送分片时启动超时定时器,如果在定时器超时之后没有收到相应的确认,重发分片。
滑动窗口:防止过载和拥塞的手段,做法为动态地维护一个滑动窗口的大小,使数据的收发控制在服务器和用户可承载的范围。
拥塞检测:当发生拥塞时会产生丢包,客户端会发送重复的数据,接收方收到后也会返回重复的确认,当发送方收到重复信号时判断为网络拥塞,将减缓慢启动速度。
慢增长:连接刚刚建立时只会建立一个较小的拥塞窗口(cwnd),代表数据传输速率,并以指数速度增长,当检测到拥塞时会减小cwnd的增长速率以平衡网络中不同设备的性能。
校验和:将所有数据分块,每块16位,累加并取反,在数据发送时同时发送这个数字和,接收方用相同的方式计算数字和,如果两个值不相等表示数据错误,需要重传,这个数字也叫校验和。
close:
调用close时会触发四次挥手,过程如下:
1.主动方发送一个带有fin(finish)的tcp报文,并进入fin_wait_1状态
2.被动方收到来信后返回带有ack的报文,进入close_wait状态,主动方收到ack后进入fin_wait_2状态
3.被动方发送完数据后返回带有fin的报文,并进入last_ack状态,主动方收到fin报文后进入time_wait状态
4.主动方发送带有ack的报文,被动方收到后关闭连接
特殊情况:
1.如果被动方的fin先于ack到达,则被动方会先收到ack并进入closed状态,收到fin后主动方进入timewait状态。
2.如果两端同时调用close, 则会在收到对方的fin信号后进入close_wait状态,并发送确认信号,收到确认信号后进入time_wait
tcp协议主要通过连接控制、确认和重传、超时重传、校验和、拥塞控制、流量控制、顺序控制等机制保障数据的可靠传输。
个人对拥塞控制和流量控制的对比理解:两者都是通过控制调整发送方的发送速率达到减少丢包的目的,区别是流量控制通过查看接收方的缓存区剩余空间来把控发送数据的量,以保证非网络问题下数据不丢失,拥塞控制是考虑流量控制没考虑到的网络传输问题,解决满足流量控制的条件下数据丢失在网络传输过程的情况。