网络

#1.网络分层

  • 应用层
  • 表示层
  • 会话层
  • 传输层
  • 网络层
  • 数据链路层
  • 物理层

#2.术语

2.1.TCP

  • 传输控制协议:传输层协议之一;
  • 面向连接:传输数据前需要三次握手建立连接;
  • 稳定可靠:传输数据时有响应、重发、拥堵控制机制;
  • 时效性低:握手、响应、重发等机制会消耗大量时间,占用大量系统资源。

主要用在需要可靠传输数据的地方,如文件传输协议:HTTP、HTTPS、FTP;邮件传输协议:POP、SMTP。

2.2.UDP

  • 用户数据报协议:也是传输层协议之一;
  • 无连接:传输数据前不需事先建立连接,直接向目标主机发送报文;
  • 不可靠:不保证数据能收到或完整收到,只做报文完整性校验,不完整则丢弃;
  • 速度快:没有TCP那么复杂的机制,简单高效速度快;

主要用在追求通信速度但对通信质量要求不高的地方,如语音视频、游戏画面和语音。

2.3.HTTP

超文本传输协议,属于应用层协议,基于TCP协议和请求/响应模型,用于在web服务器与客户端浏览器之间封装和传输数据。客户端发送请求后需要服务器响应,请求结束后会主动释放连接,因此它属于短连接。

2.4.SOCKET

SOCKET位于应用层传输层之间,不是协议而是对TCP/IP协议的抽象与封装,隐藏了TCP与IP的所有细节,并对外提供接口以供 HTTP 开发者方便地使用TCP/IP协议。

SOCKET 通信需要两个端:客户端和服务端。

  • 服务端:监听网络状态,等待来自客户端的连接;
  • 客户端:指定 ip 与端口,向服务器请求连接;
  • 服务器:响应客户端的连接请求,建立一个新线程,把服务端套接字的描述发给客户端,客户端确认此描述后双方正式建立连接。

理论上 SOCKET 是一种长连接,即客户端与服务端的连接建立之后,一般不会主动断掉。如果长时间没有通信则防火墙可能会断开此连接以释放资源,所以一般 SOCKET 在没有数据传输时需要发送心跳包以保持连接。

2.5.IP协议

网络层协议,解决网络路由和寻址问题。

2.6.TCP/IP

传输控制协议/网际协议,指的是一系列协议。

#3.三次握手

TCP请求在发送数据之前,会先进行三次握手,以正式建立连接:

握手

第1次主机A 发送SYN包主机B,并进入SYN_SEND状态,等待 主机B 确认;

第2次主机B 收到SYN包,必须确认 主机ASYN,同时自己也发送一个SYN包,即SYN+ACK包,此时 主机B 进入SYN_RECV状态

第3次主机A 收到 主机BSYN+ACK包,向 主机B 发送确认包ACK

第三个包发送完毕后 主机A主机B 进入ESTABLISHED状态,完成三次握手。

#4.四次挥手

TCP连接在断开时需要四个步骤:

挥手

第1次主机A 发送完数据且知道 主机B 已接收完,想要关闭发送数据口,发 FIN主机B

第2次主机B 收到 主机A 发送的FIN,表示收到了,就会发送 ACK 回复;

第3次:这时 主机B 可能还在发送数据,不想关闭数据口,在发完ACK后继续把数据发送完了再发送FIN主机A

第4次主机A 收到 主机B 发来的FIN,知道 主机B 的数据也发送完了,回复ACK。主机A 等待 2MSL(2倍报文最长存活时间)后没有收到 主机B 传来的任何消息,知道 主机B 已经收到自己的ACK了,主机A 就关闭连接,主机B 也关闭连接。

问:A为什么等待2MSL?

A发送出最后的 ACK 回复后,该 ACK 可能丢失。B如果没有收到 ACK,将不断重发 FIN。所以A不能立即关闭,必须确认B收到了该 ACK。A会在发送出 ACK 后进入TIME_WAIT状态并设置一个计时器,等待 2MSL 的时间。如果在该时间内再次收到 FIN,那么A会重发 ACK 并再次等待 2MSL。如果直到 2MSLA都没有再次收到 FIN,那么A推断 B已经成功接收自己的 ACK,则结束 TCP 连接。

#5.无状态

HTTP协议是无状态的,指的是协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。也就是说,打开一个服务器上的网页和你之前打开这个服务器上的网页之间没有任何联系。

#6.短/长连接

HTTP 是应用层协议,基于 TCP 这一传输层协议。TCP 连接在 IP层上安全、面向连接地传递数据包。在HTTP/1.0中,HTTP 默认使用的是短连接。浏览器和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。如果客户端浏览器访问的某个HTML页面中包含有其他的Web资源,如Js、图像、CSS文件等,那么浏览器每遇到一个Web资源就会建立一次会话。从 HTTP/1.1 起,浏览器开始默认使用长连接,用以保持连接特性。使用长连接时会在响应头加入这行代码:

1
Connection:keep-alive

使用长连接时,当一个网页打开完成后,客户端和服务器之间的 TCP 连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用已经建立的连接。Keep-Alive 不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接要客户端和服务端都支持长连接,现在各个浏览器的高版本基本都是支持长连接。

优点和缺点

短连接:对于服务器来说管理较为简单,存在的连接都是有用的连接,不需要额外的控制手段。但如果客户请求频繁,将在TCP的建立和关闭操作上浪费时间和带宽。

长连接:可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间。对于频繁请求资源的客户来说,较适用长连接。但连接一直不关闭的话,会存在一个问题,随着客户端连接越来越多,服务端可能会扛不住。

数据发送完成?

短连接模式下,服务器通常在发送回所请求的数据之后就关闭连接。这样客户端读数据时会返回EOF(-1),就知道数据已经接收完全了。但是长连接模式发送完数据后服务器不会自动断开连接,所以不能再使用返回EOF(-1)来判断。

  • Conent-Length

客户端向服务器请求一个资源时,服务器可以很清楚的知道内容大小,它通过消息首部中的Content-length字段告诉客户端总共需要接收多少数据,客户端可以根据这个值和已接收的值来判断数据是否接收完成。

  • Transfer-Encoding

对于边产生数据边发给客户端的动态页面,服务器需使用Transfer-Encoding:chunked的方式来代替Content-Length

chunk编码将数据分成一块一块的发送,以一个标明长度为0的chunk标示结束。每个chunk分为头部和正文两部分,头部内容指定正文的字符总数和数量单位,正文部分就是指定长度的实际内容,两部分之间用回车换行(CRLF)隔开。在最后一个长度为0的Chunk中的内容是称为footer的内容,是一些附加的Header信息(通常可以直接忽略)。

Chunk编码的格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Chunked-Body = *chunk
"0" CRLF
footer
CRLF
chunk = chunk-size [ chunk-ext ] CRLF
chunk-data CRLF

hex-no-zero = <HEX excluding "0">

chunk-size = hex-no-zero *HEX
chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-value ] )
chunk-ext-name = token
chunk-ext-val = token | quoted-string
chunk-data = chunk-size(OCTET)

footer = *entity-header

消息长度的总结:

  1. 为了兼容HTTP/1.0应用程序,HTTP/1.1的请求消息体中须包含Content-Length字段;
  2. content-length字段对应的值须和消息体里面的长度完全匹配;
  3. 同时存在Transfer-EncodingContent-Length字段,忽略Content-Length字段;
  4. 如果采用短连接,则可以直接通过服务器关闭连接来确定消息的传输长度。

#7.HTTP头部

HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求,请求头包含:请求的方法、URI、协议版本、以及包含请求修饰符、客户信息和内容的类似于MIME的消息结构。服务器以一个状态行作为响应,响应的内容包括:消息协议的版本,成功或者错误编码加上包含服务器信息、实体元信息以及可能的实体内容。

通常HTTP消息包括客户端向服务器的请求消息和服务器向客户端的响应消息。这两种类型的消息由一个起始行,一个或者多个头域,一个只是头域结束的空行和可选的消息体组成。HTTP的头域包括通用头,请求头,响应头和实体头四个部分。每个头域由一个域名,冒号(:)和域值三部分组成。域名是大小写无关的,域值前可以添加任何数量的空格符,头域可以被扩展为多行,在每行开始处,使用至少一个空格或制表符。

请求消息头

1
2
3
4
5
6
7
8
9
10
11
12
13
Host:rss.sina.com.cn
User-Agent:Mozilla/50 (Windows; U; Windows NT 51; zh-CN;
rv:18114) Gecko/20080404 Firefox/20014
Accept:text/xml,application/xml,application/xhtml+xml,text/html;
q=09,text/plain;q=08,image/png,*/*;q=05
Accept-Language:zh-cn,zh;q=05
Accept-Encoding:gzip,deflate
Accept-Charset:gb2312,utf-8;q=07,*;q=07
Keep-Alive:300
Connection:keep-alive
Cookie:userId=C5bYpXrimdmsiQmsBPnE1Vn8ZQmdWSm3WRlEB3vRwTnRtW &lt;-- Cookie
If-Modified-Since:Sun, 01 Jun 2008 12:05:30 GMT
Cache-Control:max-age=0

响应消息头

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Status:OK - 200 &lt;-- 响应状态码,表示 web 服务器处理的结果。
Date:Sun, 01 Jun 2008 12:35:47 GMT
Server:Apache/2061 (Unix)
Last-Modified:Sun, 01 Jun 2008 12:35:30 GMT
Accept-Ranges:bytes
Content-Length:18616
Cache-Control:max-age=120
Expires:Sun, 01 Jun 2008 12:37:47 GMT
Content-Type:application/xml
Age:2
X-Cache:HIT from 236-41、D07071951、sina、com、cn &lt;
-- 反向代理服务器使用的 HTTP 头部
Via:1.0 236-41.D07071951.sina.com.cn:80 (squid/2.6.STABLE13)
Connectionclose

Content-Type

用于指定请求和响应的HTTP内容的类型。如果未指定默认为text/html。

1
2
3
4
类型格式:type/subtype(;parameter)? type
type,主类型,任意的字符串,如text,*代表所有;
subtype,子类型,任意的字符串,如html,*代表所有;
parameter,可选,一些参数,如Accept请求头的q参数, Content-Type的 charset参数。

常见的媒体格式类型如下:

  • text/html : HTML格式
  • text/plain :纯文本格式
  • text/xml : XML格式
  • image/gif :gif图片格式
  • image/jpeg :jpg图片格式
  • image/png:png图片格式

以application开头的媒体格式类型:

  • application/xhtml+xml :XHTML格式
  • application/xml : XML数据格式
  • application/atom+xml :Atom XML聚合格式
  • application/json : JSON数据格式
  • application/pdf :pdf格式
  • application/msword : Word文档格式
  • application/x-www-form-urlencoded :表单默认的提交数据的格式(表单键值对)
  • application/octet-stream :上传二进制数据(只能提交一个文件)
  • multipart/form-data :既可以上传表单键值对,也可以上传二进制数据(可传多个文件)

#8.GET 与 POST

Http定义了与服务器交互的不同方法,最基本的方法有4种:

  • GET:查询资源的信息;
  • POST:向服务器提交数据,通常是以表单的形式;
  • PUT:向服务器写入文档;
  • DELETE:删除资源。

最常用的是 GET 和 POST:

用途:

  • GET一般用于查询资源信息,POST一般用于提交数据、更新资源信息。

参数

  • GET 请求的数据会附在 URL 之后,以?分割 URL 和传输数据;
  • POST 请求的数据被放在 HTTP 包的 body 中;
  • GET 比 POST 更不安全,因为参数直接暴露在 URL 上,不能用来传递敏感信息;
  • GET 请求的URL可以设置成书签,POST不可以;
  • GET 请求的参数会被完整的保留在浏览历史记录中,POST 请求不会;
  • GET 请求 URL 中的参数有长度限制,POST 没有;

数据包

  • GET 请求只产生一个 TCP 数据包,浏览器会把 Header 和 data 一并发送出去,服务器响应200;
  • POST 请求产生两个 TCP 数据包,浏览器先发送 Header,服务器响应 100 continue;浏览器再发送data,服务器响应 200。

注: 从本质上来说,GET 与 POST 都是 Http 协议中发送请求的方法,底层都是基于 TCP 的链接。技术上来讲如果你想,你可以给 GET 请求加上 request body,也可以给 POST 请求的URL加上参数。但一般我们不会这样做,因为上面所说的这些都是 Http 协议已经约定俗成的规则。

#9.Http 与 Https

Http的缺点:

  • 通信不加密,使用明文,内容可能会被窃听;
  • 不验证通信方的身份,有可能遭遇伪装;
  • 无法证明报文的完整性,所以有可能已遭篡改;

Http的优点:

  • 传输速度快

Https并非是应用层的一种新协议,它只是Http通信接口部分用SSLTLS代替而已,即添加了加密及认证机制。

1
Https = Http + 加密 + 认证 + 完整性保护

SSL

全称 Secure Socket Layer,即安全套接层,是网景公司开发的一种安全协议,用以为网络通信提供安全数据完整性。当前版本为3.0,被广泛地用于Web浏览器与服务器之间的身份认证加密数据传输。SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。

TLS

全称 Transport Layer Security,即安全传输层协议,是 SSL 的继任者,它是 IETF 将 SSL 进行标准化的成果。从技术上讲,TLS 1.0与 SSL 3.0的差异非常微小,具体内容可参考 这里~

密钥加密

密钥加密使用一对非对称的密钥:私钥和公钥。私钥不能让其他任何人知道,而公钥则可以随意发布,任何人都可以获得。使用公钥加密方式时,发送密文的一方使用对方的公钥进行加密处理,对方收到被加密的信息后,再使用自己的私钥进行解密。这种方式相对比较安全,因为不需要发送用来解密的私钥,也不必担心密钥被攻击者窃听而盗走。

Https请求流程

  1. DNS Lookup;
  2. TCP Handshake;
  3. TLS或SSL Handshake;
  4. TCP/HTTP Request/Response;

Https 在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行 SSL 握手,握手过程中将确立双方加密传输数据的密码信息,过程描述如下:

1.浏览器将自己支持的一套加密规则发送给服务端。

2.服务端从中选出一组加密算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址、加密公钥、证书颁发机构等信息。

3.获得服务端证书之后浏览器要做以下工作:

  • 验证证书的合法性(证书的颁发机构是否合法,网站地址是否与正在访问的地址一致等),如果证书受信任,则浏览器栏里面会显示一个小锁头,否则会给出证书不受信的提示;
  • 如果证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码,并用证书中提供的公钥加密;
  • 使用约定好的HASH计算握手消息,并使用生成的随机数对消息进行加密,最后将之前生成的所有信息发送给服务端;

4.服务端接收浏览器发来的数据之后要做以下的操作:

  • 使用自己的私钥将信息解密取出密码,使用密码解密浏览器发来的握手消息,并验证HASH是否与浏览器发来的一致;
  • 使用密码加密一段握手消息,发送给浏览器;

5.浏览器解密并计算握手消息的HASH,如果与服务端发来的HASH一致,此时握手过程结束,之后所有的通信数据将由之前浏览器生成的随机密码并利用对称加密算法进行加密。

#10.网络优化

10.1.网络检测

检测用户所处的网络环境,2G/3G/4G/Wi-Fi以及当前网速,动态应对:

  1. 动态调整网络请求的并发数

网络差时将任务的并发数置为更小值,或者串行;注意并发数不宜过大或者过小,并发数过大在网络差时会造成更大的拥堵和整体延时;并发数过小在网络差时会造成急切请求等普通请求的情况。

控制并发数可以从两个层面入手,一个是在发起时控制请求的执行数量;一个是设置网络连接本身的最大并发数;

  • 控制任务请求的并发数

基于信号量、NSOperation或者GCD,控制任务的并发数量,比如AFN早期版本中的AFHTTPRequestOperation

  • HTTPMaximumConnectionsPerHost

The maximum number of simultaneous connections to make to a given host.

This property determines the maximum number of simultaneous connections made to each host by tasks within sessions based on this configuration. This limit is per session, so if you use multiple sessions, your app as a whole may exceed this limit. Additionally, depending on your connection to the Internet, a session may use a lower limit than the one you specify. The default value is 6 in macOS, or 4 in iOS.

这是NSURLSessionConfiguration的一个属性,表示同一个服务器同时接受的最大连接并发数,默认情况下iOS支持最多4个并发;每个session对应着一个设置,如果配置N个session则主机同时可接受的最大并发数可能会超过你给单个session设置的限制。

  1. 动态设置超时时间

网络差时,将请求的超时时间置为更短,节省后面请求的等待时间;

  1. 减少数据传输量

将待传输的数据进行分割,分批或者压缩再传输;同时配合AFN库中提供的 throttle 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
Throttles request bandwidth by limiting the packet size
and adding a delay for each chunk read from the upload stream.

When uploading over a 3G or EDGE connection, requests may fail with "request body stream exhausted".
Setting a maximum packet size and delay according to the recommended values (`kAFUploadStream3GSuggestedPacketSize`
and `kAFUploadStream3GSuggestedDelay`) lowers the risk of the input stream exceeding its allocated bandwidth.
Unfortunately, there is no definite way to distinguish between a 3G, EDGE, or LTE connection over `NSURLConnection`.
As such, it is not recommended that you throttle bandwidth based solely on network reachability.
Instead, you should consider checking for the "request body stream exhausted" in a failure block,
and then retrying the request with throttled bandwidth.

@param numberOfBytes Maximum packet size, in number of bytes. The default packet size for an input stream is 16kb.
@param delay Duration of delay each time a packet is read. By default, no delay is set.
*/
- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes
delay:(NSTimeInterval)delay;
  1. 提供重发机制

遭遇请求失败或超时等错误时,可自动尝试指定次数的重发。

  1. 使用HTTP缓存

结合实际情况,合理设置NSURLRequestCachePolicy缓存策略。

10.2.DNS解析

应用内置服务器的IP列表,该列表可以在应用启动服务中下发更新。

10.3.HTTP版本

使用HTTP1.1及以上版本,自动开启Connection: Keep-Alive,省去TCP频繁三次握手的时间;

最近看到一篇 文章,里面讲到了 HTTP 2.0,而且 iOS 9 开始已经支持 HTTP 2.0,只是目前主流的还是 HTTP 1.1;另外,最近在 Github 上看到微信有一个网络基础组件开源库 Mars,这两个点后面抽时间再继续研究一下~


相关参考:

#©Yfling-HTTPS加密原理

#©软件iOS开发-iOS网络层详解和优化

#©偷师饿了么:怎样用HTTP/2优化iOS APP网络层次架构

#©网络TCP建立连接为什么需要三次握手而结束要四次

#©51cto-GET与POST的区别

#©Socket和Http之间的区别和概述


网络
https://davidlii.cn/2017/12/20/http.html
作者
Davidli
发布于
2017年12月20日
许可协议