平时上网冲浪逛淘宝,或者给微信好友发送一条消息时,这条消息(或者叫数据更为准确)会在网络上进行传输,但在实际网络这条数据是怎么安全被接收者接收的,今天我们就来聊一聊。
在纽约的我想给一位成都的小姐姐发送一条消息(后面都叫数据),那么这条消息由数字信号转换成模拟信号在网络上进行传输(通过网线或者光纤),但这条数据将会面临许多复杂的传输环境,比如模拟信号受到磁场影响或极端天气影响出现衰减,传输过程中丢包等,如下图:
数据在上面的网络中传输显得极为复杂,为了简化网络的复杂度,网络通信的不同方面被分解为多层次结构,使得每个层次分工明确,并且每一层只与紧挨着的上一层或者下一层进行交互,.各层之间相互独立,即不需要知道低层的结构,只要知道是通过层间接口所提供的服务,这样大大提高了灵活性,只要接口不变就不会因层的变化(甚至是取消该层)而变化,各层采用最合适的技术实现而不影响其他层。这也有利于促进标准化。
OSI七层协议: Open System Interconnect的缩写,意为开放式系统互联。开放式系统互联模型是一个参考标准,解释协议相互之间应该如何相互作用,OSI是制定的适用于全世界计算机网络的统一标准,是一种理想状态。
TCP/IP协议: 是美国国防部发明的,是让互联网成为了目前这个样子的标准之一。
IOS七层参考模型 | TCP/IP协议 | 对应的网络协议 | 对应的网络设备 |
---|---|---|---|
应用层 | 应用层 | DNS,HTTP,FTP,TFTP,SSH,SMTP,SNMP,Telnet | / |
表示层 | / | / | |
会话层 | / | / | |
传输层 | 传输层 | TCP,UDP | 四层交换机、四层路由器 |
网络层 | 网际层 | IP,ICMP,ARP,RARP,AKP,UUCP | 路由器、三层交换机 |
数据链路层 | 网络接口层 | FDDI,Ethernet,Arpanet,PPP,SLIP,PDN | 网桥、以太网交换机、网卡 |
物理层 | IEEE802.1A,IEEE802.2 ~ IEEE802.11 | 中继器、集线器、双绞线 |
物理层是参考模型中的最底层,主要定义了系统的电气、机械、过程和功能标准。 如:电压、物理数据速率、最大传输距离、物理联接器和其他的类似特性。物理层的主要功能是利用传输介质为数据链路层提供物理联接,负责数据流的物理传输工作。物理层传输的基本单位是比特流(bit),即0和1,也就是最基本的电信号或光信号,是最基本的物理传输特征。
在物理层提供比特流服务的基础上,建立相邻结点之间的数据链路,通过差错控制提供数据帧(Frame)在信道上无差错的传输,并进行各电路上的动作系列。数据链路层在不可靠的物理介质上提供可靠的传输。该层的作用包括:物理地址寻址、数据的成帧、流量控制、数据的检错、重发等。 在这一层,数据的单位称为帧(frame)。数据链路层协议的代表包括:SDLC、HDLC、PPP、STP、帧中继等。
在 计算机网络中进行通信的两个计算机之间可能会经过很多个数据链路,也可能还要经过很多通信子网。网络层的任务就是选择合适的网间路由和交换结点, 确保数据及时传送。网络层将数据链路层提供的帧组成数据包,包中封装有网络层包头,其中含有逻辑地址信息——源站点和目的站点地址的网络地址。如果你在谈论一个IP地址,那么你是在处理第3层的问题,这是“数据包”问题,而不是第2层的“帧”。IP是第3层问题的一部分,此外还有一些路由协议和地 址解析协议(ARP)。有关路由的一切事情都在这第3层处理。地址解析和路由是3层的重要目的。网络层还可以实现拥塞控制、网际互连等功能。在这一层,数据的单位称为数据包(packet)。网络层协议的代表包括:IP、IPX、RIP、OSPF等。
第4层的数据单元也称作数据包(packets)。但是,当你谈论TCP等具体的协议时又有特殊的叫法,TCP的数据单元称为数据段 (segments)而UDP协议的数据单元称为“数据报(datagrams)”。这个层负责获取全部信息,因此,它必须跟踪数据单元碎片、乱序到达的 数据包和其它在传输过程中可能发生的危险。第4层为上层提供端到端(最终用户到最终用户)的透明的、可靠的数据传输服务。所为透明的传输是指在通信过程中 传输层对上层屏蔽了通信传输系统的具体细节。 传输层协议的代表包括:TCP、UDP、SPX等。
在会话层及以上的高层次中,数据传送的单位不再另外命名,而是统称为报文。会话层不参与具体的传输,主要功能是负责维护两个节点之间的传输联接,确保点到点传输不中断,以及管理数据交换等功能。会话层在应用进程中建立、管理和终止会话。会话层还可以通过对话控制来决定使用何种通信方式,全双工通信或半双工通信。会话层通过自身协议对请求与应答进行协调。
表示层为在应用过程之间传送的信息提供表示方法的服务。表示层以下各层主要完成的是从源端到目的端可靠地的数据传送,而表示层更关心的是所传送数据的语法和语义。 表示层的主要功能是处理在两个通信系统中交换信息的表示方式,主要包括数据格式变化、数据加密与解密、数据压缩与解压等。在网络带宽一定的前提下数据压缩的越小其传输速率就越快,所以表示层的数据压缩与解压被视为掌握网络传输速率的关键因素。表示层提供的数据加密服务是重要的网络安全要素,其确保了数据的安全传输,也是各种安全服务最为重视的关键。表示层为应用层所提供的服务包括:语法转换、语法选择和联接管理。
应用层为操作系统或网络应用程序提供访问网络服务的接口。应用层中包含了若干独立的用户通用服务协议模块,为网络用户之间的通信提供专用的程序服务。需要注意的是应用层并不是应用程序,而是为应用程序提供服务。应用层协议的代表包括:Telnet、FTP、HTTP、SNMP等。
相同点:
OSI和TCP/IP的相同点是二者均采用层次结构,而且都是按功能分层。都是负责为用户提供真正的端对端的通信服务,也对高层屏蔽了底层网络的实现细节。
不同点:
OSI分七层,自下而上分为物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,而TCP/IP分四层:网络接口层、网际层、传输层和应用层。
OSI层次间存在严格的调用关系,两个(N)层实体的通信必须通过下一层(N-1)层实体,不能越级,而TCP/IP可以越过紧邻的下一层直接使用更低层次所提供的服务,因而减少了一些不必要的开销,提高了协议的效率。
OSI先有模型,再有协议,比较适合理论上探讨。TCP/IP先有协议,再有模型,已得到广泛的实际应用。
http是一个简单的请求-响应协议,一种无状态的,以请求/应答方式运行的协议,请求和响应消息的头以ASCII码形式给出;而消息内容则具有一个类似MIME的格式,它使用可扩展的语义和自描述消息格式。
无状态是指Web浏览器与Web服务器之间不需要建立持久的连接,这意味着当一个客户端向服务器端发出请求,然后Web服务器返回响应,连接就被关闭了,在服务器端不保留连接的有关信息。也就是说,HTTP请求只能由客户端发起,而服务器不能主动向客户端发送数据。HTTP协议是一种典型的无状态协议。
有状态指的是,客户端或者服务端需要维护一个状态。TCP协议实际上是双方都维护了一个状态,双方都变成已连接的状态,才可以开始传输数据,任何一个人掉线都不能发送消息;双方都变成连接关闭状态时,这时候双方都释放需要维护这个状态的资源。
HTTP协议的请求报文由三大部分组成:
请求行:描述请求的基本信息,包含了请求方法(METHOD),请求资源的URI,HTTP版本号。
头部字段集合: 使用 key-value 形式更详细地说明报文,包含了请求头,通用信息头,实体头
报文主体:实际传输的数据,它不一定是纯文本,可以是图片、视频 等二进制数据。
序号 | 方法 | 描述 |
---|---|---|
1 | GET | 请求指定的页面信息,并返回实体主体。 |
2 | HEAD | 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头。 |
3 | POST | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 |
4 | PUT | 从客户端向服务器传送的数据取代指定的文档的内容。 |
5 | DELETE | 请求服务器删除指定的页面。 |
6 | CONNECT | HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。 |
7 | OPTIONS | 允许客户端查看服务器的性能。 |
8 | TRACE | 回显服务器收到的请求,主要用于测试或诊断。 |
9 | PATCH | 实体中包含一个表,表中说明与该URI所表示的原内容的区别。 |
10 | MOVE | 请求服务器将指定的页面移至另一个网络地址。 |
11 | COPY | 请求服务器将指定的页面拷贝至另一个网络地址。 |
12 | LINK | 请求服务器建立链接关系。 |
13 | UNLINK | 断开链接关系。 |
14 | WRAPPED | 允许客户端发送经过封装的请求。 |
15 | Extension-mothed | 在不改动协议的前提下,可增加另外的方法。 |
Header | 解释 | 示例 |
---|---|---|
Accept | 指定客户端能够接收的内容类型 | Accept: text/plain, text/html |
Accept-Charset | 浏览器可以接受的字符编码集。 | Accept-Charset: iso-8859-5 |
Accept-Encoding | 指定浏览器可以支持的web服务器返回内容压缩编码类型。 | Accept-Encoding: compress, gzip |
Accept-Language | 浏览器可接受的语言 | Accept-Language: en,zh |
Accept-Ranges | 可以请求网页实体的一个或者多个子范围字段 | Accept-Ranges: bytes |
Authorization | HTTP授权的授权证书 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Cache-Control | 指定请求和响应遵循的缓存机制 | Cache-Control: no-cache |
Connection | 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) | Connection: close |
Cookie | HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 | Cookie: $Version=1; Skin=new; |
Content-Length | 请求的内容长度 | Content-Length: 348 |
Content-Type | 请求的与实体对应的MIME信息 | Content-Type: application/x-www-form-urlencoded |
Date | 请求发送的日期和时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
Expect | 请求的特定的服务器行为 | Expect: 100-continue |
From | 发出请求的用户的Email | From: [email protected] |
Host | 指定请求的服务器的域名和端口号 | Host: www.zcmhi.com |
If-Match | 只有请求内容与实体相匹配才有效 | If-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Modified-Since | 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 | If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
If-None-Match | 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 | If-None-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Range | 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag | If-Range: “737060cd8c284d8af7ad3082f209582d” |
If-Unmodified-Since | 只在实体在指定时间之后未被修改才请求成功 | If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
Max-Forwards | 限制信息通过代理和网关传送的时间 | Max-Forwards: 10 |
Pragma | 用来包含实现特定的指令 | Pragma: no-cache |
Proxy-Authorization | 连接到代理的授权证书 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Range | 只请求实体的一部分,指定范围 | Range: bytes=500-999 |
Referer | 先前网页的地址,当前请求网页紧随其后,即来路 | Referer: http://www.zcmhi.com/archives/71.html |
TE | 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 | TE: trailers,deflate;q=0.5 |
Upgrade | 向服务器指定某种传输协议以便服务器进行转换(如果支持) | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
User-Agent | User-Agent的内容包含发出请求的用户信息 | User-Agent: Mozilla/5.0 (Linux; X11) |
Via | 通知中间网关或代理服务器地址,通信协议 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 关于消息实体的警告信息 | Warn: 199 Miscellaneous warning |
响应行:描述响应的基本信息包含HTTP版本号,状态码(STATUS CODE),原因(REASON)。
头部字段集合: 使用 key-value 形式更详细地说明报文,包含了响应头,通用信息头,实体头
报文主体:实际传输的数据,它不一定是纯文本,可以是图片、视频 等二进制数据。
HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型:
状态码 | 状态码英文名称 | 描述 |
---|---|---|
1开头的状态码 | ||
100 | Continue | 继续。客户端应继续其请求 |
101 | Switching Protocols | 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议 |
2开头的状态码 | ||
200 | OK | 请求成功。一般用于GET与POST请求 |
201 | Created | 已创建。成功请求并创建了新的资源 |
202 | Accepted | 已接受。已经接受请求,但未处理完成 |
203 | Non-Authoritative Information | 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本 |
204 | No Content | 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 |
205 | Reset Content | 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 |
206 | Partial Content | 部分内容。服务器成功处理了部分GET请求 |
3开头的状态码 | ||
300 | Multiple Choices | 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 |
301 | Moved Permanently | 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 |
302 | Found | 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI |
303 | See Other | 查看其它地址。与301类似。使用GET和POST请求查看 |
304 | Not Modified | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 |
305 | Use Proxy | 使用代理。所请求的资源必须通过代理访问 |
306 | Unused | 已经被废弃的HTTP状态码 |
307 | Temporary Redirect | 临时重定向。与302类似。使用GET请求重定向 |
4开头的状态码 | ||
400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
401 | Unauthorized | 请求要求用户的身份认证 |
402 | Payment Required | 保留,将来使用 |
403 | Forbidden | 服务器理解请求客户端的请求,但是拒绝执行此请求 |
404 | Not Found | 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面 |
405 | Method Not Allowed | 客户端请求中的方法被禁止 |
406 | Not Acceptable | 服务器无法根据客户端请求的内容特性完成请求 |
407 | Proxy Authentication Required | 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权 |
408 | Request Time-out | 服务器等待客户端发送的请求时间过长,超时 |
409 | Conflict | 服务器完成客户端的PUT请求是可能返回此代码,服务器处理请求时发生了冲突 |
410 | Gone | 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置 |
411 | Length Required | 服务器无法处理客户端发送的不带Content-Length的请求信息 |
412 | Precondition Failed | 客户端请求信息的先决条件错误 |
413 | Request Entity Too Large | 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 |
414 | Request-URI Too Large | 请求的URI过长(URI通常为网址),服务器无法处理 |
415 | Unsupported Media Type | 服务器无法处理请求附带的媒体格式 |
416 | Requested range not satisfiable | 客户端请求的范围无效 |
417 | Expectation Failed | 服务器无法满足Expect的请求头信息 |
5开头的状态码 | ||
500 | Internal Server Error | 服务器内部错误,无法完成请求 |
501 | Not Implemented | 服务器不支持请求的功能,无法完成请求 |
502 | Bad Gateway | 充当网关或代理的服务器,从远端服务器接收到了一个无效的请求 |
503 | Service Unavailable | 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 |
504 | Gateway Time-out | 充当网关或代理的服务器,未及时从远端服务器获取请求 |
505 | HTTP Version not supported | 服务器不支持请求的HTTP协议的版本,无法完成处理 |
Header | 解释 | 示例 |
---|---|---|
Accept-Ranges | 表明服务器是否支持指定范围请求及哪种类型的分段请求 | Accept-Ranges: bytes |
Age | 从原始服务器到代理缓存形成的估算时间(以秒计,非负) | Age: 12 |
Allow | 对某网络资源的有效的请求行为,不允许则返回405 | Allow: GET, HEAD |
Cache-Control | 告诉所有的缓存机制是否可以缓存及哪种类型 | Cache-Control: no-cache |
Content-Encoding | web服务器支持的返回内容压缩编码类型。 | Content-Encoding: gzip |
Content-Language | 响应体的语言 | Content-Language: en,zh |
Content-Length | 响应体的长度 | Content-Length: 348 |
Content-Location | 请求资源可替代的备用的另一地址 | Content-Location: /index.html |
Content-MD5 | 返回资源的MD5校验值 | Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ== |
Content-Range | 在整个返回体中本部分的字节位置 | Content-Range: bytes 21010-47021/47022 |
Content-Type | 返回内容的MIME类型 | Content-Type: text/html; charset=utf-8 |
Date | 原始服务器消息发出的时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
ETag | 请求变量的实体标签的当前值 | ETag: “737060cd8c284d8af7ad3082f209582d” |
Expires | 响应过期的日期和时间 | Expires: Thu, 01 Dec 2010 16:00:00 GMT |
Last-Modified | 请求资源的最后修改时间 | Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT |
Location | 用来重定向接收方到非请求URL的位置来完成请求或标识新的资源 | Location: http://www.zcmhi.com/archives/94.html |
Pragma | 包括实现特定的指令,它可应用到响应链上的任何接收方 | Pragma: no-cache |
Proxy-Authenticate | 它指出认证方案和可应用到代理的该URL上的参数 | Proxy-Authenticate: Basic |
refresh | 应用于重定向或一个新的资源被创造,在5秒之后重定向(由网景提出,被大部分浏览器支持) | Refresh: 5; url=http://www.zcmhi.com/archives/94.html |
Retry-After | 如果实体暂时不可取,通知客户端在指定时间之后再次尝试 | Retry-After: 120 |
Server | web服务器软件名称 | Server: Apache/1.3.27 (Unix) (Red-Hat/Linux) |
Set-Cookie | 设置Http Cookie | Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1 |
Trailer | 指出头域在分块传输编码的尾部存在 | Trailer: Max-Forwards |
Transfer-Encoding | 文件传输编码 | Transfer-Encoding:chunked |
Vary | 告诉下游代理是使用缓存响应还是从原始服务器请求 | Vary: * |
Via | 告知代理客户端响应是通过哪里发送的 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 警告实体可能存在的问题 | Warning: 199 Miscellaneous warning |
WWW-Authenticate | 表明客户端请求实体应该使用的授权方案 | WWW-Authenticate: Basic |
当用户在浏览器输入www.taobao.com
网址回车之后,网络协议都做了哪些工作呢?
chrome://net‐internals/#events
查看), 如果没有则从本机域名解析文件hosts(C:\Windows\System32\drivers\etc\hosts
)中查看,还没有则从本地域名服务器、权威域名服务器、顶级域名服务器、根域名服务器(Root DNS Servers)层层解析。在浏览器中输入地址:http://localhost:8080/user/userLoginValidate?userName=admin&passWord=321
向我的tomcat服务器发送一个GET请求,其请求报文内容大致如下(注:GET请求的报文主体包含在URL中了):
实际上,黑客就可以通过对请求行的请求方法和URL进行伪造(篡改),又或者对头部字段集合中的部分字段(如:Referer、User-Agent、Cookie
)的Value进行伪造,达到欺骗服务器进而窃取数据的目的,诸如我在大学期间就通过伪造Cookie欺骗的投票系统的服务器,进而进行无限刷取票数。
刚刚请求的响应报文内容如下:
上图只看到响应头的内容,没有响应体,这是由于火狐浏览器响应体需要在其他地方看:
需要注意的地方,我一开始输入的密码是错误的,响应行的状态为200只能说明我这次的GET请求正常请求并返回响应结果了,不能说明密码正确。
UDP定义:Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。
TCP定义:传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
详细说明各个字段含义:
16位源端口号:16位的源端口中包含初始化通信的端口。源端口和源IP地址的作用是标识报文的返回地址。
16位目的端口号:16位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。
32位序号:32位的序列号由接收端计算机使用,重新分段的报文成最初形式。当SYN出现,序列码实际上是初始序列码(Initial Sequence Number,ISN),而第一个数据字节是ISN+1。这个序列号(序列码)可用来补偿传输中的不一致。
32位确认序号:32位的序列号由接收端计算机使用,重组分段的报文成最初形式。如果设置了ACK控制位,这个值表示一个准备接收的包的序列码。
4位首部长度:4位包括TCP头大小,指示何处数据开始。
保留(6位):6位值域,这些位必须是0。为了将来定义新的用途而保留。
标志:6位标志域。表示为:紧急标志、有意义的应答标志、推、重置连接标志、同步序列号标志、完成发送数据标志。按照顺序排列是:URG、ACK、PSH、RST、SYN、FIN。
16位窗口大小:用来表示想收到的每个TCP数据段的大小。TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。窗口大小是一个16字节字段,因而窗口大小最大为65535字节。
16位校验和:16位TCP头。源机器基于数据内容计算一个数值,收信息机要与源机器数值 结果完全一样,从而证明数据的有效性。检验和覆盖了整个的TCP报文段:这是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证的。
16位紧急指针:指向后面是优先数据的字节,在URG标志设置了时才有效。如果URG标志没有被设置,紧急域作为填充。加快处理标示为紧急的数据段。
选项:长度不定,但长度必须为1个字节。如果没有选项就表示这个1字节的域等于0。
数据:该TCP协议包负载的数据。
在上述字段中,6位标志域的各个选项功能如下:
注意:ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号。
握手之前客户端主动结束CLOSED阶段
,被动打开的服务器端也结束CLOSED阶段
,并进入LISTEN阶段
。接下来开始"三次握手":
(1)第一次握手:客户端向服务端发送一段TCP报文,包含以下内容:
随后客户端进入SYN-SENT阶段
。
(2)第二次握手:服务器端接收到来自客户端的TCP报文后,结束LISTEN阶段
,并返回一段TCP报文,包含以下内容:
随后服务器端进入SYN-RCVD阶段
。
(3)第三次握手:客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段
。并返回最后一段TCP报文。包含以下内容:
随后客户端进入ESTABLISHED阶段
。
服务器端收到来自客户端的“确认收到服务器数据”的TCP报文之后,明确了从服务器端到客户端的数据传输是正常的。便结束SYN-RCVD阶段
,也进入ESTABLISHED阶段
。之后客户端和服务端就可以进行数据传输了,三次握手结束。
需要注意:从整个三次握手的过程来看,双方的确认号ack和序号seq的值,都是在前一次握手的基础上进行了计算,假如某一方发送的TCP报文出现了丢失就无法通过验证继续握手,这就保证了TCP报文传输的连续性。
接下来我们深挖一下服务端的Linux内核大致是如何处理TCP连接的:
图中部分参数说明:
SYN队列
中(该SYN队列由操作系统内核进行维护,进入SYN队列
的报文状态会被设置为SYN_RCVD
);带有SYN和ACK响应的报文
给到客户端,随后进行等待;SYN队列
对应的请求报文
出队,之后再入队到ACCEPT队列
,这就表示三次握手结束,连接建立成功;ACCEPT队列
进行监听,阻塞等待,当ACCEPT队列
中有可用的连接后,就可以通过API
拿到连接进行双向的数据通信
。更多关于tcp_max_syn_backlog
和somaxconn
细节请查阅linux内核调优tcp_max_syn_backlog和somaxconn的区别
想要测试三次握手的过程我们需要用到抓包工具,我这里就用netcat工具做演示:
首先我们通过网址:https://eternallybored.org/misc/netcat/下载netcat。
再将该文件复制粘贴到C盘 users/当前登录用户目录下即可,这样我们就可以通过cmd进入windows的命令界面使用nc命令了(简单粗暴的方式,也可以自己配置环境变量)。
在自己的测试服务器(我的是centos7)中打开一个测试端口,我这里使用的是8080,然后通过以下命令对服务器指定的端口号接收TCP报文情况进行监听:
tcpdump -i eth0 -S -c 3 port 8080
// tcpdum -i 网卡号 -S[将相对序列号转化为绝对序列号] -c 抓报文次数 port 监听端口号
在自己的windows电脑上通过cmd进入命令化界面,输入如下命令发送TCP请求(注意你通过nc命令发送TCP请求的端口号应该是你监听的端口号):
nc 你服务器的IP地址 8080
然后在服务器中就会打印如下内容:
其中:183.128.158.142.34718是客户端,cggeeker.webcache表示服务端。
第一次握手是:183.128.158.142.34718 > cggeeker.webcache;
第二次握手是:cggeeker.webcache > 183.128.158.142.34718;
第三次握手是:183.128.158.142.34718 > cggeeker.webcache。
至此三次握手实践分析结束。
SYN-ACK
之后,收到Client的ACK之前的TCP连接称为半连接(half-openSYN_RCVD状态
,当收到ACK
后,Server转入ESTABLISHED状态
。IP地址
,并向Server不断地发送SYN包
,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包
将产时间占用未连接队列,导致正常的SYN请求
因为队列满而被丢弃
,从而引起网络堵塞
甚至系统瘫痪
。SYN攻击时一种典型的dos攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了,使用如下命令可以让之现行:
netstat -nap | grep SYN_RECV
挥手之前主动释放连接的客户端结束ESTABLISHED阶段
。随后开始“四次挥手“:
(1)第一次挥手: 客户端想要释放连接,向服务器端发送一段TCP报文,包含以下内容:
随后客户端进入FIN-WAIT-1阶段
,即半关闭阶段。并且停止客户端到服务器端方向上发送数据(报文数据),但是客户端仍然能接收从服务器端传输过来的数据。
(2)第二次挥手: 服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段
,进入CLOSE-WAIT阶段
(半关闭状态)并返回一段TCP报文,包含以下内容:
随后服务器端开始准备释放服务器端到客户端方向上的连接,但是这个过程中服务器端仍然可以向客户端发送未发送完的数据;客户端收到从服务器端发出的TCP报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1阶段
,进入FIN-WAIT-2阶段
(3)第三次挥手: 服务器端自发出ACK确认报文后,经过了CLOSED-WAIT阶段
,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文,包含以下内容:
随后服务器端结束CLOSE-WAIT阶段
,进入LAST-ACK阶段
,并且停止服务器端到客户端的方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据(因为此刻两端都还没有完全关闭连接)。
(4)第四次挥手: 客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段
,进入TIME-WAIT阶段
,并向服务器端发送一段报文,包含以下内容:
随后客户端开始在TIME-WAIT阶段
等待2MSL
,服务器端收到从客户端发出的TCP报文之后结束LAST-ACK阶段
,进入CLOSED阶段
。由此正式确认关闭服务器端到客户端方向上的连接;
客户端等待完2MSL之后
,结束TIME-WAIT阶段
,进入CLOSED阶段
,由此完成“四次挥手”。
需要注意:在客户端与服务器端传输的TCP报文中,双方的确认号ack和序号seq的值,都是在彼此ack和seq值的基础上进行计算的,这样做保证了TCP报文传输的连续性,一旦出现某一方发出的TCP报文丢失,便无法继续"挥手",以此确保了"四次挥手"的顺利完成
原因如下:
IP地址+端口号
,于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME-WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。流协议
(stream protocol)。这就意味着数据是以字节流的形式传递给接收者的,没有固有的”报文”或”报文边界”的概念。从这方面来说,读取TCP数据就像从串行端口读取数据一样–无法预先得知在一次指定的读调用中会返回多少字节(也就是说能知道总共要读多少,但是不知道具体某一次读多少)。一连串
的无结构的字节流
,TCP并不知道字节流的含义,TCP并不关心应用程序一次将多大的报文发送到TCP的缓存中,而是根据对方给出的发送窗口值
、当前网络拥堵的程度
、路径上的最大传输单元
和连接的输出队列中有多少数据
来决定一个报文段应该包含多少个字节。概念补充:
TCP最大段大小:Max Segment Size(MSS), TCP一次传输发送的最大数据段长度,默认536byte实际数据。
拆包和粘包问题是处于网络比较底层的问题,在数据链路层、网络层以及传输层都有可能发生。
讨论TCP拆包和粘包问题前,我们不妨先来看看UDP是否会出现类似问题,我们可以从本文UDP报文整体布局那幅图中看出,在UDP首部采用了16bit来指示UDP数据报文的长度,因此在应用层能很好的将不同的数据报文区分开,从而避免粘包和拆包的问题。而TCP是基于字节流的,虽然应用层和TCP传输层之间的数据交互是大小不等的数据块,但是TCP把这些数据块仅仅看成一连串无结构的字节流,没有边界;同时从本文前面的TCP报文整体布局图也可以看出,在TCP的首部没有表示数据长度的字段,基于上面两点,在使用TCP传输数据时,才有粘包或者拆包现象发生的可能。
场景举例:客户端和服务端建立连接后,客户端连续给服务端发送两条数据后,客户端关闭与服务端的连接。
我们将可能出现的情况分类讨论如下:
常见原因如下:
通过上述分析可以知道解决粘包或拆包问题的关键在于指定数据的边界或者指定数据的长度,通常会有以下一些常见的解决办法: