代码改变世界

Tcp协议介绍

2019-08-06 15:23  Tony、  阅读(687)  评论(1编辑  收藏  举报

前情提要:根据域名建立tcp链接之前要做两件事情,1 根据arp协议找到网管mac地址 2 通过dns服务器解析出域名的Ip地址,解析出域名的Ip地址之后就可以建立tcp链接了。

tcp协议三个特点:1 实现可高传输 2 实现流量控制 3 避免网络拥塞

tcp首部:

 

 

 序号:表示传输数据第一个字节 是整个数据中的第几个字节

 确认号:表示下一个链接过来的传输数据的第一个字节 是整个数据中的第几个字节

 URG:值为1时表示数据不用进入TCP缓存池排队,直接发送给接收端

 ACK:表示确认号码是否有效,0无效 1有效 

 SYN:值为1时表示发起会话请求的标识,其他为0后者不传(一般用于tcp握手阶段)

 PSH:值为1时表示接收端要提前提交给应用程序,不要进入TCP缓存池

 RST: 值为1时表示终端链接

 RST:值为1时表示释放链接

TCP三次握手

为什么要进行三次握手?

  理论上2次握手已经可以判断网络是通畅的,但是为什么还要进行第三次呢?主要是为了解决当第一握手时,如果出现网络延迟时,客户端一段时间没有收到服务器的响应 就会再发一次握手信息,此时服务器会给客户端一个响应。后面客户端第一次发送的握手信息,又传送到服务器,此时服务器会在给客户端一个响应,此时客户端就不会在处理这个响应,如果没有第三次握手,服务器还在等待着客户端传输数据,会很浪费服务器资源。

  第一次客户端发给服务端,服务端接收到则可以认为服务端接收没问题,然后服务端第二次给客户端发,客户端收到则可以断定客户端发送没问题接收也没问题,这个时候服务端还不知道自己发送有没有问题,第三次客户端给服务端,服务端接收就可以判断服务端的发送功能没问题。这样客户端和服务端的发送和接收都没问题了,就说明tcp通道是OK的了。

TCP四次挥手

tcp 链接图

 四次挥手还是三次挥手?

当客户端关闭的时候 此时服务器如果还有未处理完成的任务,会产生4次挥手,如果服务端没有任务处理直接关闭与客户端的链接此时就是三次挥手。

SocketChannel client = (SocketChannel) key.channel();
        ByteBuffer buffer = (ByteBuffer) key.attachment();
        buffer.clear();
        int read = 0;
        try {
            while (true) {
                read = client.read(buffer);
                if (read > 0) {
                    buffer.flip();
                    while (buffer.hasRemaining()) {
                        client.write(buffer);
                    }
                    buffer.clear();
                } else if (read == 0) {
                    break;
                } else {
                    try {
                        Thread.sleep(5*1000);//如果此时不将程序休眠就是三次挥手,服务端会少一次ack
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    client.close();
                    System.out.println( "...close");
                    break;
                }
            }
        } catch (IOException e) {
            //e.printStackTrace();

        }

 

为什么要四次分手?

TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

为什么要等待2MSL?

MSL:报文段最大生存时间,它是任何报文段被丢弃前在网络内的最长时间。原因有二:

  • 保证TCP协议的全双工连接能够可靠关闭

  • 保证这次连接的重复数据段从网络中消失

第一点:如果主机1直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致主机2没有收到主机1最后回复的ACK。那么主机2就会在超时之后继续发送FIN,此时由于主机1已经CLOSED了,就找不到与重发的FIN对应的连接。所以,主机1不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。

第二点:如果主机1直接CLOSED,然后又再向主机2发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达主机2,由于新连接和老连接的端口号是一样的,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。