tcp是网络七层模型当中传输层的协议,由IETF的RFC 793定义,是面向链接的、可靠的、基于字节流的通讯协议。而传输层位于七层模型的中间,下面是网络层,上面的话有应用层,承上启下,地位仍是很重要的。在传输层中还有一种协议udp(无链接、不保证可靠性)。相比来讲tcp有如下特色html
- 传输可靠,数据丢失有重传机制
- 数据分段打包传输,对每一个数据编号,控制顺序
- 流量控制,避免拥塞,由于TCP链接双方有固定大小缓冲空间。TCP的接收端只容许另外一端发送接收端缓冲区所能接纳的数据。
针对上面图中的结构划分,下面进行下解释node
source port 和 destination port 都是16位,计算机端口识别访问那个服务, 其中source port 是随机的,而destination port决定接受方由那个程序来接受而且由于是16位,因此说程序的最大端口号65535编程
sequence Number 是发送数据包中的第一个字节的序列号,假设当前的序列号为 s,发送数据长度为 l,则下次发送数据时的序列号为 s + l。在创建链接时一般由计算机生成一个随机数做为序列号的初始值api
Acknowledgment Number 它等于下一次应该接收到的数据的序列号。能够认为这个位置之前全部的数据都已被正常接收。
header length TCP 首部的长度,单位为 4 字节。若是没有可选字段,那么这里的值就是 5。表示 TCP 首部的长度为 20 字节(除掉data和option,恰好20字节)。
reserved浏览器
- URG表示Urgent Pointer字段有意义
- ACK表示Acknowledgment Number字段有意义
- PSH表示有 DATA数据传输
- RST表示复位TCP链接
- SYN表示SYN报文(在创建TCP链接的时候使用)
- FIN表示没有数据须要发送了(在关闭TCP链接的时候使用)
Windows 表示接收缓冲区的空闲空间,16位,用来告诉TCP链接另外一端本身可以接收的最大数据长度,流量控制的机制就基于此。
Checksum 差错控制,TCP校验和的计算包括TCP首部、数据和其它填充字节。在发送TCP数据段时,由发送端计算校验和,当到达目的地时又进行一次检验和计算。若是两次校验和一致说明数据是正确的,不然将认为数据被破坏,接收端将丢弃该数据。
Urgent 是紧急指针,16位,只有URG标志位被设置时该字段才有意义,表示紧急数据相对序列号(Sequence Number字段的值)的偏移。服务器
说明 上面是一个我写的测试demo,是一个普通的http请求,下面咱们抓包分析一下tcp三次握手的细节网络
说明 第一次握手client经过发送一个SYN标识位和Sequence Numbers(同步序列号)的数据段给server请求链接,经过该数据段告诉server但愿创建链接
说明 第二次握手是server用一个确认应答ACK标志位和Acknowledgment Number告诉client收到了数据段,同时本身也发送一个syn包(syn标志位和Sequence Numbers)。
说明 第三次客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK,此包发送完毕,客户端和服务器进入ESTABLISHED(TCP链接成功)状态,完成三次握手。
说明 三次握手完毕,连接通道创建成功,下面开始正式数据传输
针对上面整个过程下面再来一幅图详细总结说明下socket
- 客户端经过向服务器端发送一个SYN来代表但愿创建链接,做为三次握手的一部分。客户端把这段链接的序号设定为随机数c。
- 服务器端应当为一个合法的SYN回送一个SYN/ACK。ACK的确认码应为c+1,SYN/ACK包自己又有一个随机产生的序号s。
- 最后,客户端再发送一个ACK。当服务端收到这个ACK的时候,就完成了三次握手,并进入了链接建立状态。此时包的序号被设定为收到的确认号c+1,而响应号则为s+1。
下面描述下整个过程,过程和三次握手机制同样,也是用一些标志位来实现断开的过程,详细步骤过程不在图形化,由于须要四幅步骤图,太占篇幅了,下面根据上面的流程图大体解释说明一下。tcp
- client发送FIN标志位,表示出要断开链接的请求的含义
- server进行响应,发送ack标识,表示确认收到断开链接请求
- server 发送FIN标志位,提出反方向的关闭要求
- client 发送ack标志位,标识确认收到的主机B的关闭链接请求
适合对传输数据要求比较可靠的地方,例如常见的ftp,http,https,smtp等等这些应用层的协议都是基于tcp的封装;还有实战中常见套接字编程,能够用来开发浏览器通讯模块,以及p2p的下载工具等等,这些底层都是都是基于tcp协议。工具
协议只是一个规范,实现形式有多种,具体而言在node当中使用的话以下形式
let net = require('net'); let path = require('path'); let ws = require('fs').createWriteStream(path.join(__dirname, 'msg.txt')); let server = net.createServer(function (socket) { socket.pipe(ws, { end: false }); }); server.listen(8080); 建立一个tcp服务器监听8080端口,并将接受的数据存储到msg.txt文件中,上面的socket是一个双工流,既可写又能够读,下面是测试的输出结果
说明 上面只是一个简单的实例,更多用法,能够参考node当中net模块
参考连接
https://zh.wikipedia.org/wiki...
http://nodejs.cn/api/
http://www.freebuf.com/column...