有关即时通讯的基本概念

刚接触开发IM时,几个基本的概念把我搞得晕头转向,比如:

  1. Socket 和 WebSocket 有哪些区别和联系?
  2. WebSocket 和 HTTP 有什么关系?
  3. WebSocket 和 HTML5 是什么关系?
  4. 什么是 长连接/短连接、长轮询/短轮询?
  5. WebSocket在哪些场景下使用?
  6. 如果想做IOS的即时通讯,是使用Socket还是WebSocket?

通过google查找了大量资料,觉得有必要把相关内容做一个整理,上面几个问题也会在叙述中逐渐清晰。

1. Socket 和 WebSocket 有哪些区别和联系?

就像JavaJavaScript北大北大青鸟雷锋雷峰塔一样,没有什么关系,除了在名字上沾亲带故的以外,就是两个完全不同的东西。

WebSocket

WebSocket一种在单个TCP连接上进行全双工通讯的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范。WebSocket API也被W3C定为标准。——维基百科

背景:

现在,很多网站为了实现推送技术,所用的技术都是轮询。轮询是在特定的时间间隔(如每1秒)由客户端对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端。这种传统的模式带来很明显的缺点,即客户端需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

而比较新的技术去做轮询的效果是Comet)。这种技术虽然可以双向通信,但依然需要反复发出请求。而且在Comet中,普遍采用的长链接,也会消耗服务器资源。
在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
Websocket使用ws或wss的统一资源标志符,类似于HTTPS,其中wss表示在TLS之上的Websocket。如:

1
2
ws://example.com/wsapi
wss://secure.example.com/

Websocket使用和 HTTP 相同的 TCP 端口,可以绕过大多数防火墙的限制。默认情况下,Websocket协议使用80端口;运行在TLS之上时,默认使用443端口。

WebSocket出现的目的:即时通讯,替代HTTP轮询

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

最初的轮询(polling)阶段

上图表明,客户端发送一个request,服务器不管有没有新消息,都会立即返回一个response,然后关闭连接,这次HTTP请求结束。请记住 Request = Response , 在HTTP1.0和HTTP1.1中都是这样,也就是说一个request只能有一个response对应。客户端需要不断执行这个请求过程(也就是轮询),查询服务端有没有新的消息(数据)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
轮询场景:

Client:亲亲,有没有新消息(Request)
Server:木有(Response)
Client:亲亲,有没有新消息(Request)
Server:木有。。(Response)
Client:亲亲,有没有新消息(Request)
Server:好烦,没有。。(Response)
Client:那个。。有没有新消息(Request)
Server: 有啦,给你(Response)
Client:亲亲,有没有新消息(Request)
Server:。。没。。。没有(Response)
...
...

从上面可以看出来,客户端不断的建立HTTP连接,然后等待服务端处理,可以提现HTTP协议的另一个缺陷:被动性,也就是服务端不能主动联系客户端,只能有客户端发起。而且,HTTP request的Header是很长的,为了传输一个很小的数据却占用了很多的带宽流量去传输Header。可见,轮询需要服务器有很快的处理速度,且非常消耗资源,也不具备即时性。

长轮询 (Long polling) 阶段

Long Polling 是对 Polling 的改进,原理跟 Polling 相似,都是采用轮询的方式,不过Long Polling 采取的是阻塞模型:客户端发起连接后,如果服务端没有新消息,就一直不返回Response给客户端。直到有新消息或者超时才返回给客户端,返回之后这次请求结束。客户端再次建立连接,重复这个过程。。。。

1
2
3
4
5
情景:
Client:亲亲,有没有新消息? 没有的话,等有了再给我吧 (Request)
Server:额。。。~~~ (1小时后) ~~~ 有新消息了,给你 (Response)
...
...

相比于 Polling ,Long Polling 在某种程度上减小了对网络宽带的消耗等问题,但缺陷也很明显:假设服务器端的数据更新速度很快,服务器在传送一个数据包给客户端后必须等待客户端的下一个Get请求到来,才能传递第二个更新的数据包给客户端,那么这样的话,客户端显示实时数据最快的时间为2×RTT(往返时间),而且如果在网络拥塞的情况下,这个时间用户是不能接受的,比如在股市的的报价上;另外,由于http数据包的头部数据量往往很大(通常有400多个字节),但是真正被服务器需要的数据却很少(有时只有10个字节左右),这样的数据包在网络上周期性的传输,难免对网络带宽是一种浪费;而且 Long Polling 要求服务器具有高并发性,也就是同时接待大量客户端的能力。

WebSocket
从上面分析可以看出,Polling ,Long Polling 不是最好的方式,Polling 需要服务端更快的处理速度,Long Polling 需要高并发性。在这种情况下,WebSocket出现,解决了上面提到的 HTTP 协议存在的几个缺陷。

下面三张图,是WebSocket建立连接、传输数据以及关闭连接的模型,至于为什么放三张相似的图,因为。。。我觉得这三张图都挺好看的


1
2
3
4
5
6
7
8
9
情景:
Client:亲亲,我要建立WebSocket协议,需要的服务:chat,WebSocket协议版本:17 (HTTP Request)
Server:ok,确认,已升级为WebSocket协议 (HTTP Protocols Switched)
Client:麻烦你有新消息的时候推送给我哦。。
Server:ok,有的时候会告诉你的。
Server:balabalabalabala
Server:balabalabalabala
Server:我看到一个笑话,哈哈哈
Server:哈哈哈哈哈哈哈。。。。。

Websocket是应用层第七层上的一个应用层协议,它必须依赖 HTTP 协议进行一次握手 ,握手成功后,数据就直接从 TCP 通道传输,与 HTTP 无关了。
Websocket的数据传输是以 frame (帧) 形式传输的,比如会将一条消息分为几个 frame,按照先后顺序传输出去。这样做会有几个好处:

  1. 大数据的传输可以分片传输,不用考虑到数据大小导致的长度标志位不足够的情况。
  2. 和 HTTP 的chunk一样,可以边生成数据边传递消息,即提高传输效率。

一个典型的Websocket握手请求如下:

1
2
3
4
5
6
7
8
客户端请求
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13

1
2
3
4
5
6
服务器回应
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Location: ws://example.com/

字段说明:

  1. Connection必须设置Upgrade,表示客户端希望连接升级。
  2. Upgrade字段必须设置Websocket,表示希望升级到Websocket协议。
  3. Sec-WebSocket-Key是随机的字符串,服务器端会用这些数据来构造出一个SHA-1的信息摘要。把“Sec-WebSocket-Key”加上一个特殊字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,然后计算SHA-1摘要,之后进行BASE-64编码,将结果做为“Sec-WebSocket-Accept”头的值,返回给客户端。如此操作,可以尽量避免普通HTTP请求被误认为Websocket协议。
  4. Sec-WebSocket-Version 表示支持的Websocket版本。RFC6455要求使用的版本是13,之前草案的版本均应当被弃用。
  5. Origin字段是可选的,通常用来表示在浏览器中发起此Websocket连接所在的页面,类似于Referer。但是,于Referer不同的是,Origin只包含了协议和主机名称。
  6. 其他一些定义在HTTP协议中的字段,如Cookie等,也可以在Websocket中使用。
Socket

Socket并不是一个协议,而是为了方便使用TCP或UDP而抽象出来的一层,是位于应用层和传输控制层之间的一组接口。如果你要使用HTTP来构建服务,那么就不需要关心Socket,如果你想基于TCP/IP来构建服务,那么Socket可能就是你会接触到的API。

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,
TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;
HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。—— 百度百科

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。
在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,
对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。 —— XX百科

当两台主机通信时,必须通过Socket连接,Socket则利用TCP/IP协议建立TCP连接。
TCP连接则更依靠于底层的IP协议,IP协议的连接则依赖于链路层等更低层次。
WebSocket则是一个典型的应用层协议。

2. WebSocket 和 HTTP 有什么关系?

先看一下这两个概念在维基百科中的解释:

WebSocket is a computer communications protocol, providing full-duplex communication channels over a single TCP connection. The WebSocket protocol was standardized by the IETF as RFC 6455 in 2011, and the WebSocket API in Web IDL is being standardized by the W3C.
WebSocket is designed to be implemented in web browsers and web servers, but it can be used by any client or server application. The WebSocket Protocol is an independent TCP-based protocol. Its only relationship to HTTP is that its handshake is interpreted by HTTP servers as an Upgrade request.[1]
The WebSocket protocol enables interaction between a browser and a web server with lower overheads, facilitating real-time data transfer from and to the server. This is made possible by providing a standardized way for the server to send content to the browser without being solicited by the client, and allowing for messages to be passed back and forth while keeping the connection open. In this way, a two-way (bi-directional) ongoing conversation can take place between a browser and the server. The communications are done over TCP port) number 80 (or 443 in the case of TLS-encrypted connections), which is of benefit for those environments which block non-web Internet connections using a firewall).

—— From Wikipedia, the free encyclopedia

The Hypertext Transfer Protocol (HTTP) is an application protocol for distributed, collaborative, and hypermedia information systems.
HTTP is the foundation of data communication for the World Wide Web.
Hypertext is structured text that uses logical links (hyperlinks) between nodes) containing text. HTTP is the protocol to exchange or transfer hypertext.
Development of HTTP was initiated by Tim Berners-Lee at CERN in 1989. Standards development of HTTP was coordinated by the Internet Engineering Task Force (IETF) and the World Wide Web Consortium (W3C), culminating in the publication of a series of Requests for Comments (RFCs). The first definition of HTTP/1.1, the version of HTTP in common use, occurred in RFC 2068 in 1997, although this was obsoleted by RFC 2616 in 1999 and then again by RFC 7230 and family in 2014.
A later version, the successor HTTP/2, was standardized in 2015, and is now supported by major web servers.

—— From Wikipedia, the free encyclopedia

相同点:
WebSocket 和 HTTP 都是基于TCP的应用层协议,都是可靠性传输协议。

不同点:

  1. 本来就是两种完全不同的协议。。。
  2. WebSocket 是全双工协议,可以双向发送或接受信息,连接建立之后,通信双方都可以在任何时刻向另一方发送数据。HTTP请求需要等待客户端发起请求服务端才能响应。
  3. 与 HTTP 不同的是,Websocket 需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)
  4. Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。
  5. HTTP 协议要不断的建立,关闭Request,由于HTTP是无状态协议,每一次发送都是一次新的开始,所以每次都要重新传输identity info (鉴别信息),来告诉服务端你是谁。Websocket 只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就可以避免反复解析HTTP协议,还要查看identity info(鉴别信息)。

联系:
Websocket 通过 HTTP/1.1 协议的101状态码进行握手。
为了创建Websocket连接,需要通过客户端发出请求,之后服务器进行回应,这个过程通常称为“握手)”(handshaking)。

虽然WebSocket在握手的时候是通过 HTTP 进行的(为了兼容性考虑,也许以后WebSocket会有自己的握手方式),但也仅仅是这样而已,它们就是两种不同的应用层协议。

3. WebSocket 和 HTML5 是什么关系?

HTML5是指的一系列新的API,或者说新规范,新技术。而WebSocket就是HTML5中出的的一种协议。

4. 什么是 长连接/短连接、长轮询/短轮询?

查了许多资料,于是总结一下自己的理解:

长连接/短连接,长轮询/短轮询 本身就是不通层次的概念。

长/短连接 是针对TCP传输层的概念,也就是,TCP连接才有长/短连接之说。

短连接是指通讯双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此连接,即每次连接只完成一项业务的发送。

长连接指在一个TCP连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要TCP keep alive。TCP keep alive 的两种方式:

  1. 应用层面的心跳机制
    自定义心跳消息头 : 一般客户端主动发送, 服务器接收后进行回应(也可以不回应).
  2. TCP协议自带的 keep alive:打开keep-alive功能即可. 具体属性也可以通过API设定.

TCP KeepAlive 是用于检测TCP连接的状态,而心跳机制有两个作用:一是检测TCP的状态,二是检测通讯双方的状体。

考虑一种情况,某台服务器因为某些原因导致负载超高,CPU 100%,无法响应任何业务请求,但是使用 TCP 探针则仍旧能够确定连接状态,这就是典型的连接活着但业务提供方已死的状态,对客户端而言,这时的最好选择就是断线后重新连接其他服务器,而不是一直认为当前服务器是可用状态,一直向当前服务器发送些必然会失败的请求。

从上面我们可以知道,KeepAlive 并不适用于检测双方存活的场景,这种场景还得依赖于应用层的心跳。应用层心跳有着更大的灵活性,可以控制检测时机,间隔和处理流程,甚至可以在心跳包上附带额外信息。从这个角度而言,应用层的心跳的确是最佳实践。

写到这顺便说一下 HTTP Keep Alive 和 TCP keep alive 这两个看上去肯定有点儿啥关系的概念。事实上,HTTP keep-alive与TCP keep-alive 是两个完全没有关系的东西。

HTTP keep-alive是HTTP协议的一个特性,目的是为了让TCP连接保持的更久一点,以便客户端/服务端在同一个TCP连接上可以发送多个HTTP request/response。

TCP keep-alive是一种检测连接状况的保活机制。It keeps TCP connection opened by sending small packets. 当网络两端建立了TCP连接之后,闲置idle(双方没有任何数据流发送往来)了tcp_keepalive_time后,服务器内核就会尝试向客户端发送侦测包,来判断TCP连接状况(有可能客户端崩溃、强制关闭了应用、主机不可达等等)。如果没有收到对方的回答(ack包),则会在 tcp_keepalive_intvl后再次尝试发送侦测包,直到收到对对方的ack,如果一直没有收到对方的ack,一共会尝试 tcp_keepalive_probes次,每次的间隔时间在这里分别是15s, 30s, 45s, 60s, 75s。如果尝试tcp_keepalive_probes,依然没有收到对方的ack包,则会丢弃该TCP连接。TCP连接默认闲置时间是2小时,一般设置为30分钟足够了。

既然长/短连接是针对TCP的概念,但是我们却经常看到HTTP 长连接(HTTP persistent connection)这样的说法,到底什么鬼?憋急,先看一段解释:

HTTP persistent connection, also called HTTP keep-alive, or HTTP connection reuse, is the idea of using a single TCP connection to send and receive multiple HTTP requests/responses, as opposed to opening a new connection for every single request/response pair. The newer HTTP/2 protocol uses the same idea and takes it further to allow multiple concurrent requests/responses to be multiplexed over a single connection.

—— From Wikipedia, the free encyclopedia

可以发现,HTTP persistent connection就是上面我们解释的HTTP Keep Alive。其实很简单,TCP长连接是针对TCP层的概念,就是让一个TCP连接长时间保持不要断开。HTTP的长连接(keep alive)是HTTP协议的一个特性,也是希望保持住长时间的TCP连接,才能在这个TCP通道上发送多个HTTP请求,而不必每次请求都打开一个新的TCP连接。

长轮询/短轮询 在上文已经介绍了,它是服务器的实现方式!由服务端编写的代码决定。

5. WebSocket在哪些场景下使用?

1.社交聊天

最著名的就是微信,QQ,这一类社交聊天的app。这一类聊天app的特点是低延迟,高即时。即时是这里面要求最高的,如果有一个紧急的事情,通过IM软件通知你,假设网络环境良好的情况下,这条message还无法立即送达到你的客户端上,紧急的事情都结束了,你才收到消息,那么这个软件肯定是失败的。

2.弹幕

说到这里,大家一定里面想到了A站和B站了。确实,他们的弹幕一直是一种特色。而且弹幕对于一个视频来说,很可能弹幕才是精华。发弹幕需要实时显示,也需要和聊天一样,需要即时。

3.多玩家游戏

4.协同编辑

现在很多开源项目都是分散在世界各地的开发者一起协同开发,此时就会用到版本控制系统,比如Git,SVN去合并冲突。但是如果有一份文档,支持多人实时在线协同编辑,那么此时就会用到比如WebSocket了,它可以保证各个编辑者都在编辑同一个文档,此时不需要用到Git,SVN这些版本控制,因为在协同编辑界面就会实时看到对方编辑了什么,谁在修改哪些段落和文字。

5.股票基金实时报价

金融界瞬息万变——几乎是每毫秒都在变化。如果采用的网络架构无法满足实时性,那么就会给客户带来巨大的损失。几毫秒钱股票开始大跌,几秒以后才刷新数据,一秒钟的时间内,很可能用户就已经损失巨大财产了。

6.体育实况更新

全世界的球迷,体育爱好者特别多,当然大家在关心自己喜欢的体育活动的时候,比赛实时的赛况是他们最最关心的事情。这类新闻中最好的体验就是利用Websocket达到实时的更新!

7.视频会议/聊天

视频会议并不能代替和真人相见,但是他能让分布在全球天涯海角的人聚在电脑前一起开会。既能节省大家聚在一起路上花费的时间,讨论聚会地点的纠结,还能随时随地,只要有网络就可以开会。

8.基于位置的应用

越来越多的开发者借用移动设备的GPS功能来实现他们基于位置的网络应用。如果你一直记录用户的位置(比如运行应用来记录运动轨迹),你可以收集到更加细致化的数据。

9.在线教育

在线教育近几年也发展迅速。优点很多,免去了场地的限制,能让名师的资源合理的分配给全国各地想要学习知识的同学手上,Websocket是个不错的选择,可以视频聊天、即时聊天以及其与别人合作一起在网上讨论问题…

10.智能家居

这也是我一毕业加入的一个伟大的物联网智能家居的公司。考虑到家里的智能设备的状态必须需要实时的展现在手机app客户端上,毫无疑问选择了Websocket。

从上面我列举的这些场景来看,一个共同点就是,高实时性!

###6 . 如果做即时通讯,是使用Socket还是WebSocket?

使用 Socket 和 WebSocket 都可以做即时通讯。具体怎么做呢?公司项目IOS端使用了第三方库 CocoaAsynSocket ,它是对socket的OC封装,支持TCP、UDP连接。CocoaAsynSocket 的使用非常简单,也有官方和其他资料可以查找,这里就不啰嗦了。这篇文章只是对即时通讯涉及的一些基本概念,根据我自己的理解做一个总结和记录.