TCP报文格式

source
:发送TCP数据的源端口
dest
:接受TCP数据的目的端口
seq
:标识该TCP所包含的数据字节的开始序列号
ack_seq
:确认序列号,表示接受方下一次接受的数据序列号。
doff
:数据首部长度。和IP协议同样,以4字节为单位。通常的时候为5
urg
:若是设置紧急数据指针,则该位为1
ack
:若是确认号正确,那么为1
psh
:若是设置为1,那么接收方收到数据后,当即交给上一层程序
rst
:为1的时候,表示请求从新链接
syn
:为1的时候,表示请求创建链接
fin
:为1的时候,表示请求关闭链接window窗口,告诉接收者能够接收的大小check对TCP数据进行较核
urg_ptr
:若是urg=1,那么指出紧急数据对于历史数据开始的序列号的偏移值
TCP链接创建三次握手

- 第一次握手:创建链接时,客户端发送syn包(seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;
- 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时本身也发送一个SYN包(seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
- 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
- 完成三次握手,客户端与服务器开始传送数据,
TCP优缺点
优势程序员
- TCP提供以承认的方式显式地建立和终止链接。
- TCP保证可靠的、顺序的(数据包以发送的顺序接收)以及不会重复的数据传输。
- TCP经过保持连续并将数据块分红更小的分片来处理大数据块。无需程序员知道
缺点编程
- TCP在传递数据时必须建立(并保持)一个链接。这个链接给通讯进程增长了开销,让它比UDP速度要慢。TCP 链接的资源消耗,其中包括:数据包信息、条件状态、序列号等。
- TCP链接存在安全隐患:经过故意不完成创建链接所须要的三次握手过程,形成链接一方的资源耗尽
- 序列号的可预测性,目标主机应答链接请求时返回的SYN/ACK 的序列号是可预测的 TCP 会话劫持和SYN FLOOD(同步洪流)就是根据TCP的这个弱点出现的一种网络攻击方式
TCP 数据结构
在TCP链接创建的过程当中,会用到一些数据结构安全
- 半链接队列:在三次握手协议中,服务器维护一个未链接队列,该队列为每一个客户端的SYN包(syn=j)开设一个条目,该条目代表服务器已收到SYN 包,并向客户发出确认,正在等待客户的确认包。这些条目所标识的链接在服务器处于Syn_RECV状态,当服务器收到客户的确认包时,删除该条目,服务器进入ESTABLISHED状态。
- Backlog参数:表示未链接队列的最大容纳数目。
- SYN-ACK 重传次数:服务器发送完SYN-ACK包,若是未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,若是重传次数超过系统规定的最大重传次数,系统将该链接信息从半链接队列中删除。注意,每次重传等待的时间不必定相同。
- 半链接存活时间:是指半链接队列的条目存活的最长时间,也即服务从收到SYN包到确认这个报文无效的最长时间,该时间值是全部重传请求包的最长等待时间总和。有时咱们也称半链接存活时间为Timeout时间、SYN_RECV存活时间
TCP 标志位
应该就是code bit那个字段的位的意义服务器
- SYN(同步标志):该标志置上的时候,同步序列编号(Synchronize Sequence Numbers)栏有效。该标志仅在三次握手创建TCP链接时有效。它提示TCP链接的服务端检查序列编号,该序列编号为TCP链接初始端(通常是客户端)的初始序列编号。在这里,能够把TCP序列编号看做是一个范围从0到4,294,967,295的32位计数器。经过TCP链接交换的数据中每个字节都通过序列编号。在TCP报头中的序列编号栏包括了TCP分段中第一个字节的序列编号。
- ACK(确认标志):该标志置上的时候,确认编号(Acknowledgement Number)栏有效。大多数状况下该标志位是置位的。TCP报头内的确认编号栏内包含的确认编号(w+1,Figure-1)为下一个预期的序列编号,同时提示远端系统已经成功接收全部数据。
- RST(复位标志):该标志置上的时候,用于复位相应的TCP链接。
- URG(紧急标志):该标志置上的时候,表示紧急(The urgent pointer) 标志有效。
- PSH(推标志):该标志置位时,接收端不将该数据进行队列处理,而是尽量快将数据转由应用处理。在处理 telnet 或 rlogin 等交互模式的链接时,该标志老是置位的。
- FIN(结束标志):带有该标志置位的数据包用来结束一个TCP回话,但对应端口仍处于开放状态,准备接收后续数据。
TCP链接过程的中间状态
- SYN_SENT:客户端发送syn数据包向服务器端申请创建TCP链接,此时客户端的状态为SYN_SENT
- SYN_RCVD:接收方收到请求,给发起方发送一个设置了SYN与ACK标志位的TCP数据包作为应答,另外设置一个比客户机发送来的ISN大1个单位的ISN值,这常被称为SYN_ACK数据包或SYN_ACK报文这时链接的状态称作SYN_RCVD
- ESTABLISHED:发起方而后发送一个带有ACK应答和增1后的ISN标志来确认SYN_ACK至此,完成了三次握手,此时的链接状态为连结成功: ESTABLISHED
TCP链接终止协议(四次挥手)

因为TCP链接是全双工的,所以每一个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的链接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP链接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另外一方执行被动关闭。
TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送(报文段4)。
服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN同样,一个FIN将占用一个序号。
服务器关闭客户端的链接,发送一个FIN给客户端(报文段6)。
客户段发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。网络
关闭链接等待两倍最大生存时间
主动关闭链接方发送ack响应后,为何须要等待两倍最大生存时间后再关闭链接?数据结构
由于主动方发送的ACK消息可能丢失,并致使被动方再次发送FIN报文,TIME_WAIT为链接中”离群的段”提供从网络中消失的时间。考虑一下,若是延迟或者重传段在链接关闭后到达时会发生什么呢?一般状况下,由于TCP仅仅丢弃该数据并响应RST消息,因此这不会形成任何问题。当RST消息到达发出延时段的主机时,由于该主机也没有记录链接的任何信息,因此它也丢弃该段。然而,若是两个相同主机之间又创建了一个具备相同端口号的新链接,那么离群的段就可能被当作是新链接的,若是离群的段中数据的任何序列号偏偏在新链接的当前接收窗口中,数据就会被从新接收,其结果就是破坏新链接并发
- 简单点说:就是为了将以前的TCP链接的端口号给占住,不让新的TCP链接使用,避免以前TCP链接上发出的包(由于某些缘由比较晚才到达目标主机)被新的TCP链接给收到和处理。
TCP关闭链接时状态
- CLOSED: 初始状态。
- LISTEN: 服务器端的某个SOCKET处于监听状态,能够接受链接了
- FIN_WAIT_1:FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态其实是当SOCKET在ESTABLISHED状态时,它想主动关闭链接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,固然在实际的正常状况下,不管对方何种状况下,都应该立刻回应ACK报文,因此FIN_WAIT_1状态通常是比较难见到的,而FIN_WAIT_2状态还有时经常能够用netstat看到。
- FIN_WAIT_2:FIN_WAIT_2状态下的SOCKET,表示半链接,也即有一方要求close链接,但另外还告诉对方,我暂时还有点数据须要传送给你,稍后再关闭链接。
- TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL(2倍最大生存时间)后便可回到CLOSED可用状态了。若是FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,能够直接进入到TIME_WAIT状态,而无须通过FIN_WAIT_2状态。
- CLOSING: 正常状况下,当你发送FIN报文后,按理来讲是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。可是CLOSING状态表示你发送FIN报文后,并无收到对方的ACK报文,反而却也收到了对方的FIN报文。什么状况下会出现此种状况呢?其实细想一下,也不可贵出结论:那就是若是双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的状况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET链接。
- CLOSE_WAIT: 在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给本身,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正须要考虑的事情是察看你是否还有数据发送给对方,若是没有的话,那么你也就能够close这个SOCKET,发送FIN报文给对方,也即关闭链接。因此你在CLOSE_WAIT状态下,须要完成的事情是等待你去关闭链接。
- LAST_ACK: 它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也便可以进入到CLOSED可用状态了。
三次和四次
为何创建链接协议是三次握手,而关闭链接倒是四次握手呢?socket
这是由于服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它能够把ACK和SYN(ACK起应答做用,而SYN起同步做用)放在一个报文里来发送。但关闭链接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你全部的数据都所有发送给对方了,因此你能够未必会立刻会关闭SOCKET,也即你可能还须要发送一些数据给对方以后,再发送FIN报文给对方来表示你赞成如今能够关闭链接了,因此它这里的ACK报文和FIN报文多数状况下都是分开发送的。函数
TCP Socket 编程流程图

UDP socket 编程流程图

UDP和TCP区别
- UDP没有三次握手过程。
- UDP处理的细节比TCP少。UDP不能保证消息被传送到(它也报告消息没有传送到)目的地。
- UDP也不保证数据包的传送顺序。UDP把数据发出去后只能但愿它可以抵达目的地。
UDP优缺点:
- UDP不要求保持一个链接
- UDP没有因接收方承认收到数据包(或者当数据包没有正确抵达而自动重传)而带来的开销。
- 设计UDP的目的是用于短应用和控制消息
- 在一个数据包链接一个数据包的基础上,UDP要求的网络带宽比TDP更小。
Socket概念
- 网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符
- Socket也具备一个相似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的链接创建、数据传输等操做都是经过该Socket实现的。
Socket类型
- 流式Socket(SOCK_STREAM):流式是一种面向链接的Socket,针对于面向链接的TCP服务应用
- 数据报式Socket(SOCK_DGRAM):数据报式Socket是一种无链接的Socket,对应于无链接的UDP服务应用
socket调用库函数主要有:
下面这几个接口都会建立一个socket大数据
Socket(af,type,protocol)
:建立套接字
bind(sockid, local addr, addrlen)
:创建地址和套接字的联系
listen( Sockid ,quenlen)
:服务器端侦听客户端的请求
创建服务器/客户端的链接 (面向链接TCP)
Connect(sockid, destaddr, addrlen)
:客户端请求链接
newsockid=accept(Sockid,Clientaddr, paddrlen)
:服务器端等待从编号为Sockid的Socket上接收客户链接请求
发送/接收数据
send(sockid, buff, bufflen)
:面向链接的发送数据
recv( )
:面向链接的接收数据
sendto(sockid,buff,…,addrlen)
面向无链接发送数据
recvfrom( )
面向无链接的接收数据
释放套接字