英语:Transmission Control Protocal,缩写为TCP [træns'mɪʃən]n. 传动装置,[机] 变速器;传递;传送;播送数组
TCP是传输控制协议;是一种面向链接的 可靠的 基于字节流的传输层通讯协议,有IETF的RFC 793定义。bash
与UDP同样完成第四层传输层所指定的功能与职责。服务器
三次握手,四次挥手。网络
具备校验机制、可靠、数据传输稳定。校验机制保证了数据传输的可靠性以及数据传输的稳定性,那么数据传输的可靠性呢,在于咱们的客户端往服务器端发送数据的时候,数据会通过层层的校验,以便后面的数据是否肯定能够进行发送,固然服务器端给客户端回送消息的时候也会通过这样的一个校验机制,因此说能够保证咋们的数据可靠性。异步
那么数据传输的稳定性呢,这在于咱们数据传输的一个速率的窗口大小的随机调整。原理大概是:客户端给服务器端发送数据的时候,因为受限于咱们客户端或者服务器端的带宽压力,或者是客户端和服务器端处理能力的压力,那么当客户端有100个字节发送到服务器端的时候,若是发现服务器端的数据接收过于缓慢,那么服务器端会在接收过程中按期的回送他本身的一个状态给客户端,那么客户端也会根据这样的状态进行本身的一个速度调整,以便本身客户端的速度适应服务器端的一个接收速度,从而知足咋们的一个数据传输稳定性。socket
首先客户端的链接通过了3次握手链接到服务器端,而后服务器端在通过这3次握手链接成功以后,才会进入到咱们后续的一个传输的创建,后面的传输创建后就好发送一系列的数据过去同时又回送数据,这是客户端和服务器端简单交互的流程介绍。TCP当中会有一些额外的数据进行发送,例如校验数据,若是你发送的数据为100K,那么可能发送完成以后,你的数据字节会大于100K,这是正常的,由于在整个过程中TCP和服务器端会不断的进行一个数据的校验,以及咋们的一个链接创建,这些都是须要消耗额外的一些流量,这样咋们额外的一些数据的消耗。函数
聊天消息传输、推送。性能
单人语言、视频聊天等。这个点若是用UDP来作的话会更加优秀一点,他在传输上的一些限制会更小,固然若是你想要保证单人之间传输的一个优越性、数据的一个健壮性、以及保证视频数据的一个精准送达,那么能够用TCP来作。ui
几乎UDP能作的都能作,但须要考虑复杂性、性能问题。spa
限制:没法进行广播,多播等操做。这是UDP所独有的。也没法作搜索,搜索只能由UDP来作。
socket(): 建立一个Socket。在于建立一个客户端的Socket链接,客户端本身new Socket的时候,其实他经过构造函数建立一个无链接的无绑定
的一个客户端Socket的空状态。通常而言是建立一个空状态的Socket,后面在调用方法设置参数创建链接。
bind(): 绑定一个Socket到一个本地地址和端口上。对于客户端而言就在于绑定到你本身客户端的端口上。而对于服务器端而言bind这个方法呢
在于绑定在本身服务器端的一个接口上以后,那么他还监听这个地址和端口上所到来的其余的客户端的一些套接字。
connect(): 客户端链接到远程套接字。
accept(): 接受一个新的链接。这是服务器端的一个ServerSocket所独有的一个方法。这是一个阻塞方法,等待客户端链接。但是设置超时时间。
阻塞状态直到有一个新的客户端链接到达,才会进入到后面的Socket建立。那么服务器端的一个简单流程就是一个ServerSocket绑定到一个
本身的端口以后,会进入到一个accept的等待状态,若是此时有新的客户端的Socket到达,那么这个时候服务器会建立一个对应的相匹配的
Socket,进入到后续的一个发送和接受的流程。那么服务器端还能够本身选择是否再去accept下一个Socket或者是直接关闭掉,再也不进行
后续的一个套接字的等待。
write(): 把数据写入到Socket输出流。
read(): 从Socket输入流读取数据。
复制代码
建立Socket-->bind本地套接字(占用一个本地端口)-->connect远程套接字-->若是链接成功,客户端就能够和远程套接字服务器进行数据收发。
建立ServerSocket-->bind本地套接字-->accept客户端套接字-->若是此时客户端的链接到达了,那么远程套接字服务器就能够和客户端之间 进行数据的收发。
默认的每个进程均可以建立一个Socket链接,甚至你的一个进程能够建立多个Socket链接。能够借助于Socket来进行进程之间的数据交互。
TCP的buffer以及TCP底层的变量实际上是由操做系统所维护的,那么TCP在进行这些变量以及buffer的一些维护获得信息以后,他会信息抛给上层的进程这一层,因此咋们进程这一层实际上是没法管理咋们TCP底层的一些东西的,好比咋们前面说的TCP三次握手,四次挥手,以及TCP的数据校验机制这些东西,是由TCP系统所完成的,系统实际上是实现了TCP的协议的,这些东西无序咱们进程去关心,咱们进程仅仅只是使用TCP,从而实现了进程之间的一个交互。固然进程之间的交互并不只仅只是你本身电脑上的进程交互,实际上是你电脑的某个进程和别人电脑上的某个进程之间的一个交互,这也是属于进程之间的一个交互。
三次握手: 首先客户端TCP会发送一条叫作SYN命令(这是一个链接请求命令),这个命令会携带一个参数,暂且叫x=rand()随机值,随机值在发送给服务器以后,服务器这个时候尚未进行一个链接的创建,仅仅只是受到了这样一次命令,收到这个命令以后他会作一个操做,校验收到的这个SYN命令,若是这个命令是完整的,那么他会开始回送一条命令,回送的命令叫SYNACK,这么命令当中携带了两个指令,一个是SYN指令,一个是ACK指令,ACK指令是对客户端发送过来的SYN指令的一次回送,这个回送表明着服务器端本身已经收到了客户端的一个信息,同理他在回送这个命令的时候也会携带一条命令SYN命令过去到客户端,在这个过程中首先他会作一件事情,在回送咋们的ACK命令的时候他会携带咱们客户端所带过来的这个x,客户端在发送SYN命令的时候会把x发送到服务器端,那么服务器端在回送这条ACK命令的时候,其实他会回送这个x回去,那x这个时候会作一个操做,把这个x+1表明着他已经收到而且通过了一次处理,因此他把x+1,而后回送到客户端,固然同时在回送的时候,他会本身携带一条他本身的SYN命令,这条命令会携带第二个参数y=rand()随机值,生成方式和客户端发送过来的x生成方式如出一辙,这个时候回去的有两个命令,一块儿到达客户端,在客户端收到的时候,他会先进行一次校验,若是说认为本身发送的SYN这个命令,收到的这个ACK命令呢是等于x+1的,那么就认为这一次已经收到服务器的一个回送消息,同时他会给服务器回送一次说我已经收到了,那么他给服务器回送消息的时候,他会把y+1同时包括刚刚收到的x值发送给服务器端,服务器端在收到这个ACK命令以后,确保这个链接已经彻底的创建,以后就能够进行咋们数据发送上的一些准备和操做。那么在这里要说一下为何要有这样的一个3次命令?首先客户端跟服务器说我要链接你,服务器端给客户端说你能够来链接我,固然服务器也给客户端同时说我也要链接你,那么这个时候客户端给服务器回送说,你能够链接我。这个地方能够肯定两个事情,客户端能够链接服务器,那么服务器也能够链接客户端。其中的随机数是用于肯定对应的客户端的,由于服务器端是要接受无数的客户端链接。
四次挥手: 客户端也能够是服务器端,这里在于这里是发送方,对面是接受方,其实不管是客户端仍是服务器端均可以进行这样的一个流程,均可以提出本身想要关闭的一个操做。首先他们会从一个已链接的状态先发送一个FIN命令FIN=1(1也是随机值),seq=u(随机值)。当接受方收到这条消息的时候,他会回送你一条ACK命令,ACK命令都是一个回送命令,ACK=1,seq=v,ack=u+1,当发送方一旦收到这个ack=u+1的时候,那么你其实就已经能够把你本身的链接断开了。这个时候服务器端有可能还有一些数据没有给你彻底送达,这个时间以内,服务器端会把他没有彻底送达的消息一一给你送达,知道他送达 完成以后,他才给你发送一个FIN=1,ACK=1,seq=w,ack=u+1命令过来讲他想要关闭了,就是服务器端跟你说他想要关闭这个链接,他一旦给你发送了这个消息以后,你收到这个消息以后,你会给他回一个ACK=1,seq=u+1,ack=w+1命令,一旦这个ACK命令你确保他已经收到了,那么以后就能够进行一个链接断开了,但这里其实就只有一个来回来回,你怎么肯定一个数据被他收到了呢,实际上是这样的,当咋们的服务器端他发送FIN命令以后,他会进行一个等待状态,在这个等待状态当中,他会持续的发送FIN命令,间隔一段时间以后会发送一次FIN命令,这个间隔时间呢通常是一次数据片所送达的完整的一个送达时间 这个简称叫SML,在于说一次数据片所可以达到对面的一次最长时间,那默认这个时间定义为2分钟,固然在Linux系统当中已经把这个值改成了30秒,30秒认为已是一个如今网络很是可靠的一个时间,若是说30秒以内对方没有收到你的消息,那么就能够认为这条消息可能被网络断开丢掉了,如今的网络当中基本上能够保证在30秒以内把一个数据片送到对方。他发送一个FIN命令以后他会进行一个等待状态,在等待状态当中若是超过30秒,他会没有收到ACK命令,那还会继续发FIN命令给你,持续的发送,直到说你给他回送一次ACK命令,固然在这个过程中有可能遇到说我网络出问题异常断开了,那么也是有可能会出现IO异常,这也是容许的,在这个过程中,他给你发送,你给他回送的ACk命令以后,也是同样的,若是说这个链接尚未进行一个完整的断开,那么你会不断的收到FIN命令,由于对方在没有收到ACK命令的状况下,他间隔一段时间又会给你发送一个FIN命令,若是说你持续的收到FIN命令,你就要持续的向对方发送ACK表示你已经收到这个命令了,直到对方已经真实的收到了ACK命令以后,对方就把链接断开,你也把链接断开。四次挥手为何要有四次挥手,四次挥手实际上是保证了前面咱们所说的全双工链接的一个断开,什么是全双工?就是说你能够向对面发送一条消息也能够接受来之对面的消息,对面能够接受你的消息,也能够向你发送消息。全双工在于大家之间断开链接,首先你向对面说能够关闭链接吗,对面一旦向你回复了能够容许断开链接,那么这个时候你就已经断开了你的一个输出流,你的输出流若是还在进行一个输出的话,那么会直接触发一个链接异常。固然这个时候你的输入仍是保留的,由于你还能够接受一个来之服务器端的数据,服务器端这个时候还在向你发送数据,那么这个时候你本身实际上是处于一个半双工的状态,你仅仅只可以接受消息了,不能再发送消息。那么服务器端也是同样,他把本身的消息发送完成以后,他向你回送了一条消息说,他的消息发送完了他也想要关闭链接,那么这个时候一旦你回送了一条消息确认,那么它也会把本身的一条链接断开,以前大家已经断开了一次你的发送信息的一个流,以后他断开了他向你发送信息的流,那么你不向说话了,他也不向你说话了,大家二者之间就能够肯定已经断开了,因此这就是四次挥手所具有的一个功能。
左边是接收方,右边是发送方,发送方缓冲区有1 2 3 4 5,5个数据片。
首先他会给接受方发送第1个数据包{序列号=1,数据:1460byte},当接受方接受到的时候,他会回送一条{序列号=1,确认号=1461,数据:0byte},这时候缓冲区的指针会移动到2。
发送第2个数据包{序列号=1461,数据:1460byte}给接受方,发送过去以后,这个时候若是说发送方没有收到接收方的回送,那么这个回送被中断了,这个时候,发送方缓冲区的指针移动到了3位置,而后他把第3个数据包{序列号=2921,数据:1460byte}发送给接收方,这个时候发送失败,接受 方没有收到第3个数据包,发送方这时候缓冲区的指针会移动到4。
给接受方发送第4个数据包{序列号=4381,数据:1460byte},发送过去以后,这个时候若是说发送方没有收到接收方的回送,那么这个回送被中断了,这时候缓冲区的指针会移动到5。
首先他会给接受方发送第5个数据包{序列号=5841,数据:1460byte},当接受方接受到的时候,他会回送一条{序列号=1,确认号=2921,数据:0byte}而后接收方1 2 4 5都接受到了,但这个时候有一点是丢掉了一条数据,那么你丢掉的这条数据,若是说在发送方认为时间Timeout了,尚未收到你的回送,就认为这条数据真的是被丢掉了,那么他会把第三条数据从新发送。
发送方给接受方重发第3个数据包{序列号=2921,数据:1460byte},当接受方接受到的时候,他会回送一条{序列号=1,确认号=7301,数据:0byte}。
一条Socket链接视为一个通道。
byte(8bit)、char(8big)、short(16bit)
char和byte是能够直接复用的,short要转换成2个byte数组。
boolean(8bit)、int(32bit)、long(64bit)
float(32bit)、double(64bit)、string(可变的) 中文转换成byte是3个byte。
UDP辅助TCP实现点对点传输案例: 若是说你知道你的服务器地址以及端口,那么每每你能够直接用TCP跟你的服务器进行一个链接。可是假如说在一个局域网当中,不知道你服务器 的一个IP地址,你仅仅知道的是你服务器公共的UDP的端口,那么在这样的状况下,你如何实现TCP的一个链接呢? TCP链接必需要知道IP地址和端口,那么要怎么要知道IP地址和端口呢?咱们能够经过UDP的一个搜索,当咱们的服务器与咱们的全部的客户端之间 约定了搜索的一个格式以后,咱们能够在客户端发起一个UDP广播,在广播的一个接受者,也就是服务器收到这个广播以后,而后判断一下咱们的 这个收到的广播是不是须要处理的,若是说是,那么服务器会回送这个广播对应的端口和IP地址上面去,当这个回送的时候,客户端就能收到咋们 服务器回送过来的这个UDP的包,当收到UDP包的时候,UDP的包就包含了IP地址和端口号,固然还能够在服务器回送信息的时候携带一些信息,因此 我就能够经过UDP的一个搜索获得咱们TCP须要的点对点的IP地址和端口,而后再根据这些信息创建TCP链接。
构建基础的口令消息。若是说咱们没有这个口令的一个头字节的话,那别人发的任何消息只要到达咋们的端口,咋们就会去回送,这是会暴露咋们本身的信息,好比最基本的信息IP地址和端口号。 局域网广播口令消息(指定端口)。
接受指定端口回送消息(获得客户端IP、port)。UDP没有标准的客户端和服务端,这里客户端指的就是对面的这一端就是server端。
异步线程接受回送消息。
异步线程等待完成(定时)。
关闭等待-终止线程等待。 一旦超时等待到达,咱们就要进行一个线程的关闭,而且终止线程等待。