网络TCP解析
目录
1.从宏观看
2.TCP详解
3.TCP三次握手四次挥手
4.socket编程
1.从宏观看
网络通信不过是因为远距离传输而进行创造的网络通信。
也就是进程间通信,从上到下分别是应用层,传输层,网络层,数据链路层。
由于远程通信出现的问题是分层的,所以给出的解决方案也是分层的,我们平常做一件事情,就会把事情分层,比如高一高二高三,在哪个阶段干哪个事情。
网络通信一般是TCP/IP协议,为什么,因为这两个协议是核心,我们先来认识一下传输层的TCP和UDP
先总体看,TCP就是保证可靠的网络传输,UDP就是不可靠的网络传输。
那么TCP是如何保证可靠网络传输呢?
2.TCP详解
TCP为了保证可靠性,那么它是如何保证可靠呢?答案是超时重传,快速重传,滑动窗口,拥塞窗口。
TCP报头里面有2个核心的东西来保证超时重传的,序号和确认序号
序号是因为TCP是面向字节流进行传输的,但是发出的顺序并不一定是报文到达的顺序,所以序号就是保证顺序到达的。
然后还有确认序号,确认序号的是为了保证可靠性而出现的,该序号以前的报文全部送达了。
3.TCP三次握手四次挥手
从宏观上来看,我们要知道TCP是工作在传输层的,负责数据发送可靠性的
TCP的特性是面向连接进行数据传输,字节流传输,可靠!
如何确定唯一一个TCP连接呢?目的IP目的端口,源IP源端口来保证。
如果你想保证数据的可靠性,你就用TCP,如果你想保证速度的话,就用UDP。
TCP和UDP可以使用同一个端口,因为它们根本不工作在一起,彼此是分离的。
TCP在进行通信前,需要进行三次握手,关闭通信的时候,需要四次挥手。
三次握手可以帮助我们同步双方的初始序列号,也可以验证双方的通信意愿和网络环境,保证全双工通信。即一个套接字文件内核帮助我们维护两个缓冲区,接受缓冲区和发送缓冲区,实现全双双工通信。最后也可以互相知道对方的缓冲区大小,便于了解发送的量。如果对方的缓冲区小,你就发少点,如果对方的缓冲区大,你就发多点,同时这也要取决于拥塞窗口的大小,这个我们后面再介绍。
三次握手,客户端向服务端发送SYN,请求建立连接。
服务端回ACK+SYN,响应并且也发出建立连接的请求。
客户端发出ACK,告诉服务端,OK我知道了,然后双方就可以进行通信了。
我们可以看这个过程,我们确定了双方的通信意愿,也确定了双方是可以接受和发送的,全双工。
然后我们要细细探讨,如果第一次报文丢了呢?
那么就是SYN客户端第一次发送就丢了,这个就会进行超时重传的机制,当客户端发送STYN之后,发现服务端长时间没有响应,就会进行超时重传,开始比如是1ms,然后第二次是2ms,第三次就是4ms,第四次是8ms,最后一次是16ms,进行一定的次数后,客户端就不强求了,说,既然我发这么多次你都没有响应,那就算了,客户端就关掉了这个连接。
那么如果第二次的SYN+ACK丢包了呢?
那么客户端也不会收到响应,客户端会进行重发SYN,然后服务端也会进行重发ACK+SYN。和第一次类似,超时一定的时间进行重发,但是重发多次后,如果你还是丢包,直接关闭连接。
第三次丢包了呢?
这里要说明的是当客户端回复最后一次的ack后,它就认为连接已经建立了,ACK如果没有发过去,那么服务端就会发ACK+SYN,客户端就会知道ACK丢包,然后进行重发。
但是重发多次还是丢包,那么有意思的就来了,客户端单方面连接建立了,但是服务端的连接没建立起来,这个时候客户端向服务端发信息就是非法的,服务端会返回RST报文,进行连接重置。
TCP三次握手可以达到验证双方通信能力,通信的意愿,即双方是否愿意进行通信,还可以初始双方的序列号,进行缓冲区大小的确认,为滑动窗口发送数据提供基础。
根据网上的资料,说三次握手首要原因是避免历史连接,因为序列号的存在,可以对历史连接进行确认
多一次资源浪费,少一次无法验证以上的能力。
TCP在进行传输的过程中是需要分包的,不能大块的数据一起传过去,这是因为在底层如果你的字节超过MTU1500字节,就会对报文进行切分,我们一般不希望对报文进行切分,这个会导致报文的丢包概率增大。所以在TCP面向字节流传输我们就会让整个数据报小于某个值。MSS
你想如果我们对报文进行切分,IP并不保证数据传输的可靠性,IP只要丢包一次,就会全部重发。所以自然不希望底层对报文进行切分!
下面看一下TCP的四次挥手
首先主动关闭连接的一方发送FIN,然后对端回ACK,然后对端再回FIN,这边再回ACK。
这样我们可以保证双方都要断开连接。就好比我们谈恋爱的时候,我们分手要进行双方的同意。
四次挥手其实是可以变成三次的,这是因为如果服务端没有数据要发送,它发ACK的时候就会顺便发FIN带上。这样就少了一次发送。但是一般情况下,客户端主动关闭连接,服务端一般还要发送完当前的数据,所以一般情况下是四次挥手,非常灵活。
还是一样的,如果客户端发的FIN丢失了,它等待一段时间后发现没有ACK来,他就会进行超时重传,超过一定的次数就会直接断开连接,然后每次重传的时间是在前一次的间隔上乘以2.
第二次丢失也就是ACK丢失,也是一样的,由于客户端就没有收到ACK,所以它会继续重传FIN,直到收到ACK。这和我们发消息类似,你想我们发出去一条消息,怎么保证对面读到了,那就是对面进行回复,说我看到了,你就知道你的消息对方收到了,报文就是采用这种机制啊。确认机制。
第三次服务端的FIN丢失,它收不到应答就是进行超时重传。
第四次ACK丢失,服务端就是重发FIN,因为他不确定自己的FIN是否丢失,它收不到应答就会重发FIN。和上面类似,如果一直收不到,重发一定次数直接关掉连接。
这里我们要知道一个TIME_WAIT状态,主动关闭连接的一方在发送完最后一次ACK后,就会进入这个状态,这个状态的时长是2MSL。一个MSL的意思就是一个报文在网络中生存的最大的时间。
2个MSL可以保证这个连接历史的报文全部丢失。也可以保证当ACK丢包的时候,可以进行重传。
我们可以手动关闭这个状态,但是一般情况我们不要关闭,因为这个TIME_WAIT我们要去理解,而不是关闭。
4.socket编程
服务端需要创建监听套接字,bind,listen,accept。
客户端需要创建套接字,系统帮助默认绑定,connect.
accept和connect返回的都是建立连接的套接字下标。
我们这里要知道connect是什么时候返回的,就是当客户端发送完最后一次ACK后客户端认为连接建立完毕,返回文件下标,服务端的ACCEPT什么时候返回呢?当然是收到ACK之后就认为连接建立完毕,返回文件下标,然后这个socket里面有发送缓冲区和接收缓冲区,我们就可以进行全双工的通信了,我们把数据交给内核,内核决定数据的接收与发送。
关闭连接的过程如下图,客户端close,对方读完毕之后会读到EOF,服务端就知道对方要关闭连接了,所以回复ACK,之后它把数据发送完之后,也调用close,发送FIN报文,对方收到发送ACK响应报文,进入TIME_WAIT,服务端收到ACK报文,连接关闭,丢包了就会重发FIN,然后客户端就会再次回ACK。宏观与具体的代码结合,让我们更清楚的了解TCP的三次握手,四次挥手,以及每一次丢包了会怎么办!@!
下一篇博客,我们说一下TCP重传,滑动窗口,流量控制,拥塞控制的具体。
立个flag,下一篇在10.3号之前写出来吧。