TCP协议是网络多层协议中运输层的最重要的协议之一,运输层是两台主机的进程之间的通信。除了TCP还有一个是UDP协议(用户数据包协议)

TCP全称是Transmission Control Protocol,意思是传输控制协议

一、TCP简介

1.TCP协议两个对等运输实体之间进行传送的数据单位是:TCP报文段

2.TCP提供的是面向连接的服务,在传送数据之前必须建立连接,数据传送完成之后需要关闭连接,TCP只可点对点,不可广播或多播,TCP连接是可靠的运输服务。

3.TCP的工作方式类似于打电话,打电话之前需要先拨号(号码就是连接的IP+端口号)连接,通话结束之后关闭连接

4.TCP提供可靠交付,即TCP传输的数据无差错、不丢失、不重复且有序

5.TCP支持全双工通信,即通信双方可随时发送数据,发送方发送完数据会先放到发送缓存中,发送方发送完毕就可以干别的事去了,TCP会在合适的时机将数据发送给接受方,接收方接收到数据会先把数据放到接收缓存中,应用程序会在合适的时机在缓存中获取数据。

6.TCP是面向字节流的,流入到进程或从进程中流出的是字节序列。而发送时和接收时除了传输的业务数据,可能还会额外加一些字节数据,用于发送方和接收方处理。比如在微信聊天中需要提醒接收方会添加@XXX,而接收方只需要接收有用信息,@信息是和业务无关的。

7.TCP连接的双方不是两个主机、不是两个IP地址、不是两个应用程序、而是两个套接字,每个套接字socket=(IP地址:端口号),每一个TCP连接必须有唯一的两个套接字,即TCP连接={套接字1,套接字2}={(IP1,port1),(IP2,port2)}

二、TCP三次握手和四次挥手

TCP是面向连接的协议,所以协议的基础就是需要有连接,而发起连接的一方可以称为客户端,等待连接的一方可以称为服务端。而TCP建立连接的过程称为握手,每次握手客户端和服务器之前需要交换三个报文段,因此也叫做“三次握手”。

在RFC973(TCP标准文档)中使用的名称是three way handshake,这里的handshake没有用复数,所以三次握手不太准确,应该叫三次报文握手,因为人与人之间握手的意思就是已经连接上了,手上摇晃了三次之后才最终握上,所以准确点说应该是握手成功了一次。但是三次握手的说法比较普遍,所以本文也叫做三次握手。在理解TCP连接之前,先来了解一些常量的含义

SYN:发起一个连接,同步位

FIN:关闭一个连接

ACK:确认连接有效

RST:重置连接

seq:序号,每次发送一次数据,seq=上一个seq+1

ack:应答序号

上图是TCP连接三次握手示意图

第一次握手:A向B发送连接请求报文,同步完syn=1,初始化序号seq=X,TCP协议规定syn=1的报文不允许携带数据,所以SYN=1即表示发起连接请求,当A发送第一次握手之后,A就进入了SYN-SENT状态,表示同步已发送

第二次握手:B接收到A发送的请求报文,如果同意连接,则向A发送确认。发送同步报文段SYN=1,seq=y,确认报文段ACK=1,确认序号ack=x+1。此时服务端进入SYN-RCVD状态,表示同步已接收

第三次握手:A接收到B的确认报文,再向B发起确认,设置ACK=1,确认序号seq=x+1,ack=y+1,此时TCP连接完成,双方都进入ESTAB-LISHED状态,表示连接以建立。

那么为什么需要三次,而不是两次就行,还需要最后再发送一次确认呢?或者说如果没有最后一次确认会发送什么?看看下面这种情况:

A发出连接请求,但是在网络中长时间滞留了而没有发送到B,此时由于A久久没有接收到B发送过来的确认请求,所以A就将连接释放了,在A释放了连接之后B又接收到了A发送过来迟到的连接请求,由于B不知道此时A已经释放了连接了,所以B认为是有效的连接,

此时B向A发送确认,同意建立连接(如果只要两次握手,那么此时B就已经进入了ESTAB-EISHED状态),此时A已经释放了连接,所以接收到B的确认请求也不会理睬,但是B还是认为连接有效而一直等待着A发送数据,就会导致B持有无效的连接而浪费资源。

而如果采用三次握手,那么B在发送完确认之后,只会进入到SYN-RCVD状态,并不会建立连接的等待数据的发送,除非A再次发送了确认请求。

TCP连接是双向的,所以TCP连接的释放是双方都可以发起的,以A为例发起释放连接,需要经过四次挥手,过程如下图示:

在连接释放之前,A和B都是出于ESTAB-LISHED状态,且可以数据传输,此时A开始进行关闭

第一次挥手:A向B发送关闭连接请求,FIN=1,seq=u(u的值等于数据传输的最后一个请求的序号+1),此时A进入FIN-WAIT-1状态,等待B确认。TCP规定FIN报文不可携带数据

第二次挥手:B接收到A的关闭连接请求,并发出关闭确认,ACK=1,seq=v(v的值等于B传送的最后一个字节的序号+1),ack=u+1,然后B进入CLOSE-WAIT(等待关闭)状态,且需要通知应用进程A需要关闭连接,不再发送数据过来了。

此时TCP连接进入半关闭状态,也就是A-B的连接已经关闭,B-A的连接还没有关闭,但A接收到B的关闭确认之后进入FIN-WAIT-2状态,等待B发送关闭连接报文

第三次挥手:若B没有数据再发送给A,则向A发送关闭连接报文,FIN=1,ACK=1,seq=w(w的值等于B传送的最后一个字节的序号+1),ack=u+1,并且B进入LAST-ACK(最后确认)状态,等待A的确认

第四次挥手:A收到B的关闭连接报文之后,再向B发送一次确认报文,ACK=1,seq=u+1,ack=w+1,并且进入到TIME-WAIT(时间等待)状态,需要等待2MSL时间之后才会进入到CLOSED状态,而B接收到关闭确认报文之后就直接进入CLOSED(关闭)状态。

这里有两个问题,一是为什么需要有四次握手,而不是两次或三次?二是A在发送关闭确认请求之后,为什么还需要等待2MSL长时间才进入CLOSED状态?(MSL一般是2分钟,2MSL就是4分钟)

回答一:和三次握手一样,挥手只用两次肯定是不够用的,那三次为什么也不够呢,因为第一次关闭连接是A向B发起的,表示A不会发送数据给B了,但是此时可能B还有数据需要传送给A,如果B在数据还没有传输完成就通知A,则数据就会丢失;如果B在数据传输完成之后再通知A,那么此时可能已经超时了,导致A以为发起的关闭连接失效了就会重新发送多次的关闭连接。而四次挥手比三次握手多的一次报文是B向A发送的关闭连接请求,表示B也已经不会发送数据给A了,这样就确保了双方都没有数据发送了,且都对对方的关闭连接做了关闭确认。

回答二:设置TIME-WAIT状态等待2MSL主要有两个原因:

原因1:防止第四次挥手丢失,如果A在发送第四次挥手报文之后马上进入CLOSED状态,而B有可能没有接收到这个确认报文,就会一直处于LAST-ACK状态,在超时之后B就会重发关闭连接报文,而此时A已经进入CLOSED状态了,就会导致B无法进入CLOSED状态。

而设置了TIME-WAIT状态之后,A会等待2MSL时间,如果B重发了FIN+ACK报文,A还是可以接收到并且发出关闭确认报文,直到B进入CLOSED状态。

原因2:确保A最后发送的报文在网络中消失,MSL表示报文的最长寿命,达到时间报文就会失效,所以A等到2MSL时间之后,报文无论是否被B接收到肯定是会失效,这样就确保了此报文不会影响到下一个新的连接。而如果没有TIME-WAIT状态,而是A直接进入CLOSED状态,然后A又再次和B通过三次握手建立了连接,此时A最后发送的关闭确认报文可能还在网络中传输,就会出现旧的报文段出现的新的连接中。

三、TCP可靠传输

tcp一大特性就是可靠传输,而网络传输过程中,很容易就会出现丢失、重复、错误及延迟的问题,那么TCP能保证数据的传输过程不会丢失、不会重复、不会乱序,是如何达到的呢?主要有以下四点:

3.1、确认和重传机制(ack机制)

TCP连接的双方发送报文之后,必须等待接收方的ACK,否则就认为这个报文丢失了而重传报文,比如发送方发送了报文seq为x,则接收方会返回一个ack=x+1。另外发送方发出报文之后会启动一个计时器(RTO),计时时间到了还没有收到ack就会重新发送。另外接收方还会对接收到的报文进行校验,如果校验不通过会再ack上返回异常的报文seq,这样发送方就会重传这个seq。(ack可以优化成多个报文合并ack一次,只需要ack最后一条报文即可,可以减少ack次数)

3.2、数据排序机制(seq机制)

每条报文都包含一个seq序列号,这个序列号会从初始的seq值上进行递增,如果发送方发送seq=x,则接收方的ack=x+1,然后发送方下一次的报文seq就等于x+1。而如果seq=x+n的报文丢失了,发送方就很清楚是哪一个报文丢失了,从而可以重传。而接收方可以根据seq来对报文进行排序,并且可以丢弃掉重复的报文。

3.3、流量控制(滑动窗口机制)

发送方维持一个滑动窗口来控制发送方报文发送,防止发送方报文发送太快而导致接收方无法及时处理,所以将报文分成四类:

1.发送完成且已经确认的

2.发送完等待确认的

3.等待发送且允许发送的

4.窗口被占满暂时不允许发送的

窗口的左边在1-2类之间,右边在3-4类之间,通过滑动窗口来进行流量控制有三种方法,分别如下:

1.停等协议:窗口大小为1,即每次只可发送一个报文,等确认之后才可发送下一个报文

2.后退N步协议:窗口大小大于1,每次可以发送多个报文,当接收方连续发送三次连续的同一个序号的ack,则表示这个序号的报文丢失了,则发送方从这个序号开始到后面的所有报文都重发一次。比如丢失的是7,那么7后面的8,9,10...都会再重发一次

3.选择重传协议:选择重传是后退N步都优化版,即只重发丢失的报文

3.4、拥塞控制(慢启动、拥塞避免、快速重传、快速恢复)

当网络出现拥塞情况,这时发送方和接收方就会频繁的发生丢包报文以及重发的报文,这样就会使得本来就堵塞的网络变得更加的堵,如果不加控制就可能导致网络崩溃了。所以tcp添加来拥塞控制,通过控制拥塞窗口(cwnd)的大小和拥塞阈值(ssthreshold)的大小来进行拥塞控制

a、慢启动

此时一般是(记住是一般情况)cwnd<ssthreshold,此时cwnd呈指数形式增长,1、2、4、8、16、32...这种增长趋势

b、拥塞避免

此时一般cwnd>ssthreshold,此时cwnd呈线性增长,32、33、34、35...这种增长趋势

c、拥塞解决

此时一般是遇到了网络拥塞的状况,解决方法是拥塞阈值乘性减即ssthreshold=cwnd/2,cwnd=1,或者ssthreshold=cwnd/2,cwnd=ssthreshold,这两种情况在后面说明

d、快速恢复

一般是启用拥塞结局策略之后,根据不同的情况,进入慢启动或者拥塞避免阶段。

浅探网络1---tcp协议详解(三次握手和四次挥手)的更多相关文章

  1. python网络编程-TCP协议中的三次握手和四次挥手(图解)

    建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的. 首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资 ...

  2. TCP协议中的三次握手和四次挥手(图解)【转】

    建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的. [更新于2017.01.04 ]该部分内容配图有误,请大家见谅,正确的配图如下,错误配图也不删 ...

  3. 真的懂了:TCP协议中的三次握手和四次挥手(关闭连接时, 当收到对方的FIN报文时, 仅仅表示对方不在发送数据了, 但是还能接收数据, 己方也未必全部数据都发送对方了。相当于一开始还没接上话不要紧,后来接上话以后得让人把话讲完)

    一.TCP报文格式 下面是TCP报文格式图: (1) 序号, Seq(Sequence number), 占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记. (2) 确 ...

  4. python TCP协议详解 三次握手四次挥手和11种状态

    11种状态解析 LISTEN  --------------------  等待从任何远端TCP 和端口的连接请求. SYN_SENT  ---------------  发送完一个连接请求后等待一个 ...

  5. 网络编程简介(OSI七层协议,TCP协议原理,三次握手与四次挥手)

    目录 网络编程 软件开发架构 C/S架构 B/S架构 网络编程的发展史 互联网协议 1.物理连接层 2.数据链路层 3.网络层 4.传输层 5.应用层 三次握手四次挥手 三次握手建链接 数据传输 四次 ...

  6. TCP协议中的三次握手和四次挥手(图解)

    建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的. 首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资 ...

  7. [转]TCP协议中的三次握手和四次挥手(图解)

    本文转自:http://blog.csdn.net/whuslei/article/details/6667471 建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来 ...

  8. 【转】 TCP协议中的三次握手和四次挥手(图解)

    建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的. 首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资 ...

  9. TCP协议中的三次握手和四次挥手(图解)(转载http://blog.csdn.net/whuslei/article/details/6667471)

    建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的 首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资源 ...

  10. TCP协议中的三次握手和四次挥手(图解) 转载

    建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的. 首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资 ...

随机推荐

  1. VS2017 调试 Unity3D 脚本

    1. 安装Unity3D最新版本.   https://unity3d.com/cn/get-unity/download 2. 安装Visual Studio Community 2017. htt ...

  2. 关于Kafka java consumer管理TCP连接的讨论

    本篇是<关于Kafka producer管理TCP连接的讨论>的续篇,主要讨论Kafka java consumer是如何管理TCP连接.实际上,这两篇大部分的内容是相同的,即consum ...

  3. Golang 笔记 4 defer、error、panic

    一.defer语句 defer语句仅能被放置在函数或方法中.它由关键字defer和一个调用表达式组成.这里的表达式所表示的既不能是对Go语言内建函数的调用也不能是对Go语言标准库代码包unsafe中的 ...

  4. LeetCode - 868. Binary Gap

    Given a positive integer N, find and return the longest distance between two consecutive 1's in the ...

  5. 【CF613D】Kingdom and its Cities 虚树+树形DP

    [CF613D]Kingdom and its Cities 题意:给你一棵树,每次询问给出k个关键点,问做多干掉多少个非关键点才能使得所有关键点两两不连通. $n,\sum k\le 10^5$ 题 ...

  6. CTF的一道安卓逆向

    前几天打CTF时遇到的一道安卓逆向,这里简单的写一下思路 首先用jadx打开apk文件,找到simplecheck处(文件名是simplecheck),可以看到基本逻辑就是通过函数a对输入的内容进行判 ...

  7. Spring-Boot构建多模块项目

    Spring-Boot构建多模块项目 功能模块单独项目开发,可以将一个庞大的项目分解成多个小项目,便于细分开发 Maven多模块项目不能独立存在,必须有一个介质来包含. 1.创建一个Maven 项目, ...

  8. python学习之旅(五)

    Python基础知识(4):基础数据类型之字符串(Ⅰ) 字符串是 Python 中最常用的数据类型.可以使用引号“ ”来创建字符串,只要为变量分配一个值即可.例如: name=“Alice” 注:字符 ...

  9. Java 读取某文件下的所有文件的大小 并将所有文件的文件名,以及对应大小输出在xls表格里

    import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.In ...

  10. JAVA SE ------------------- 项目的菜单输入

    //写一个工具类,进行输入选项数值的获取public class InputUtil { static Scanner sc=new Scanner(System.in); public static ...