地址

SSE技术详解:一种全新的HTML5服务器推送事件技术

Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

HTML5时代,为Web端即时通讯的实现带来了WebSocket和SSE(Server-sent Events)两种技术方案。

Ajax短轮询:脚本发送的http请求

  • 传统的web应用要想与服务器交互,必须提交一个表单(form),服务器接收并处理传来的表单,然后返回全新的页面,因为前后两个页面的数据大部分都是相同的,这个过程传输了很多冗余的数据、浪费了带宽。于是Ajax技术便应运而生。
  • Ajax是Asynchronous JavaScript and XML的简称,由Jesse James Garrett 首先提出。这种技术开创性地允许浏览器脚本(JS)发送http请求。
  • Ajax的出现使客户端与服务器端传输数据少了很多,也快了很多,也满足了以丰富用户体验为特点的web2.0时代初期发展的需要,但是慢慢地也暴露了他的弊端。比如无法满足即时通信等富交互式应用的实时更新数据的要求。这种浏览器端的小技术毕竟还是基于http协议,http协议要求的请求/响应的模式也是无法改变的,除非http协议本身有所改变。

Comet:一种hack技术

  • 基于http长连接服务器推技术便被hack出来。这种技术被命名为Comet
  • 以下是典型的Ajax和Comet数据传输方式的对比,区别简单明了
    • 典型的Ajax通信方式也是http协议的经典使用方式,要想取得数据,必须首先发送请求。在低延迟要求比较高的web应用中,只能增加服务器请求的频率。
    • Comet则不同,客户端与服务器端保持一个长连接,只有客户端需要的数据更新时,服务器才主动将数据推送给客户端。

Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE_2.jpg

Comet的实现主要有两种方式

  • 基于Ajax的长轮询(long-polling)方式
  • 基于 Iframe 及 htmlfile 的流(http streaming)方式。

基于Ajax的长轮询(long-polling)方式

浏览器发出XMLHttpRequest 请求,服务器端接收到请求后,会阻塞请求直到有数据或者超时才返回,浏览器JS在处理请求返回信息(超时或有效数据)后再次发出请求,重新建立连接。在此期间服务器端可能已经有新的数据到达,服务器会选择把数据保存,直到重新建立连接,浏览器会把所有数据一次性取回。

Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE_3.jpg

基于 Iframe 及 htmlfile 的流(http streaming)方式

  • Iframe是html标记,这个标记的src属性会保持对指定服务器的长连接请求,服务器端则可以不停地返回数据,相对于第一种方式,这种方式跟传统的服务器推则更接近。
  • 在第一种方式中,浏览器在收到数据后会直接调用JS回调函数,但是这种方式该如何响应数据呢?可以通过在返回数据中嵌入JS脚本的方式,如<script type="text/javascript">js_func(“data from server ”)</script>,服务器端将返回的数据作为回调函数的参数,浏览器在收到数据后就会执行这段JS脚本。

Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE_4.jpg

Websocket:未来的解决方案1

如果说Ajax的出现是互联网发展的必然,那么Comet技术的出现则更多透露出一种无奈,仅仅作为一种hack技术,因为没有更好的解决方案。Comet解决的问题应该由谁来解决才是合理的呢?浏览器,html标准,还是http标准?主角应该是谁呢?本质上讲,这涉及到数据传输方式,http协议应该是首选,是时候改变一下这个懒惰的协议的请求/响应模式了。

W3C给出了答案,在新一代html标准html5中提供了一种浏览器和服务器间进行全双工通讯的网络技术Websocket。从Websocket草案得知,Websocket是一个全新的、独立的协议,基于TCP协议,与http协议兼容、却不会融入http协议,仅仅作为html5的一部分。于是乎脚本又被赋予了另一种能力:发起websocket请求。这种方式我们应该很熟悉,因为Ajax就是这么做的,所不同的是,Ajax发起的是http请求而已。

与http协议不同的请求/响应模式不同,Websocket在建立连接之前有一个Handshake(Opening Handshake)过程,在关闭连接前也有一个Handshake(Closing Handshake)过程,建立连接之后,双方即可双向通信。

SSE:未来的解决方案2

SSE(Server-Sent Event,服务端推送事件)是一种允许服务端向客户端推送新数据的HTML5技术。与由客户端每隔几秒从服务端轮询拉取新数据相比,这是一种更优的解决方案。

与WebSocket相比,SSE有一些显著的优势。个人认为它最大的优势就是便利:不需要添加任何新组件,用任何你习惯的后端语言和框架就能继续使用。你不用为新建虚拟机、弄一个新的IP或新的端口号而劳神,就像在现有网站中新增一个页面那样简单。我喜欢把这称为既存基础设施优势。

SSE的第二个优势是服务端的简洁。相对而言,WebSocket则很复杂,不借助辅助类库基本搞不定。

SSE还有一个优势:它是一种文本协议,脚本调试非常容易。

不过,这就引出了WebSocket相较SSE的一个潜在优势:WebSocket是二进制协议,而SSE是文本协议(通常使用UTF-8编码)。当然,我们可以通过SSE连接传输二进制数据:在SSE中,只有两个具有特殊意义的字符,它们是CR和LF,而对它们进行转码并不难。但用SSE传输二进制数据时数据会变大,如果需要从服务端到客户端传输大量的二进制数据,最好还是用WebSocket。

WebSocket相较SSE最大的优势在于它是双向交流的,这意味向服务端发送数据就像从服务端接收数据一样简单。用SSE时,一般通过一个独立的Ajax请求从客户端向服务端传送数据。相对于WebSocket,这样使用Ajax会增加开销。

从服务端向客户端传输数据的性能如何?如果是文本数据而非二进制数据,SSE和WebSocket没什么区别。它们都用TCP/IP套接字,都是轻量级协议。延迟、带宽、服务器负载等都没有区别

SSE技术详解:一种全新的HTML5服务器推送事件技术

前言

  • 一般来说,Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询Comet技术WebSocket技术SSE(Server-sent Events)
  • 关于这4种技术方式的优缺点,请参考《Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE》。
  • 服务器推送事件(Server-sent Events),简称SSE,是 HTML 5 规范中的一个组成部分,可以用来从服务端实时推送数据到浏览器端
  • 相对于与之类似的 COMET 和 WebSocket 技术来说,服务器推送事件的使用更简单,对服务器端的改动也比较小。

概述

  • 由 XMLHttpRequest 对象来发出请求,得到服务器响应之后进行页面的局部更新。这种方式的不足之处在于:服务器端产生的数据变化不能及时地通知浏览器,而是需要等到下次请求发出时才能被浏览器获取。对于某些对数据实时性要求很高的应用来说,这种延迟是不能接受的。
  • 为了满足这类应用的需求,就需要有某种方式能够从服务器端推送数据给浏览器,以保证服务器端的数据变化可以在第一时间通知给用户。
  • 目前常见的解决办法有不少,主要可以分成两类。这两类方法的区别在于是否基于 HTTP 协议来实现
    • 不使用 HTTP 协议的做法是使用 HTML 5 新增的 WebSocket 规范,
    • 使用 HTTP 协议的做法则包括简易轮询COMET 技术HTML 5 服务器推送事件

四种技术的基本介绍

在介绍 HTML 5 服务器推送事件(SSE技术)之前,首先介绍一些上面提到的几种服务器端数据推送技术。

  • 一种是 WebSocket。

    • 正如名称所表示的一样,WebSocket 使用的是套接字连接基于 TCP 协议
    • 使用 WebSocket 之后,实际上在服务器端和浏览器之间建立一个套接字连接,可以进行双向的数据传输
    • WebSocket 的功能是很强大的,使用起来也灵活,可以适用于不同的场景。
    • 不过 WebSocket 技术也比较复杂,包括服务器端和浏览器端的实现都不同于一般的 Web 应用。而且更不幸的是WebSocket像其它较新的Web端技术一样存在浏览器兼容性问题,好在已经比较成熟的封装方案来解决这种技术限制,比如:开源的Socket.io,详见《Socket.IO介绍:支持WebSocket、用于WEB端的即时通讯的框架》。
  • 简易轮询

    • 即浏览器端定时向服务器端发出请求,来查询是否有数据更新。
    • 这种做法比较简单,可以在一定程度上解决问题。不过对于轮询的时间间隔需要进行仔细考虑。轮询的间隔过长,会导致用户不能及时接收到更新的数据;轮询的间隔过短,会导致查询请求过多,增加服务器端的负担。
  • Comet 技术

    • 改进了简易轮询的缺点(详见:Comet技术详解:基于HTTP长连接的Web端实时通信技术),
    • 使用的是长轮询长轮询的方式在每次请求时,服务器端会保持该连接在一段时间内处于打开状态,而不是在响应完成之后就立即关闭
    • 这样做的好处是在连接处于打开状态的时间段内,服务器端产生的数据更新可以被及时地返回给浏览器。
    • 当上一个长连接关闭之后,浏览器会立即打开一个新的长连接来继续请求。不过 COMET 技术的实现在服务器端和浏览器端都需要第三方库的支持。

综合比较上面提到的 4 种不同的技术

  • 简易轮询由于其本身的缺陷,并不推荐使用。
  • Comet 技术并不是 HTML 5 标准的一部分,从兼容标准的角度出发,也不推荐使用。
  • WebSocket 规范和服务器推送技术都是 HTML 5 标准的组成部分,在主流浏览器上都提供了原生的支持,是推荐使用的。不过 WebSocket 规范更加复杂一些,适用于需要进行复杂双向数据通讯的场景。对于简单的服务器数据推送的场景,使用服务器推送(SSE技术)事件就足够了。
  • SSE技术,服务器推送事件(SSE技术)已经在除 IE 外的大部分桌面和移动浏览器上得到了支持。

与WebSocket的比较

  • SSE适用于更新频繁、低延迟并且数据都是从服务端到客户端。
  • 它和WebSocket的区别:
    • 便利,不需要添加任何新组件,用任何习惯的后端语言和框架就能继续使用,不用为新建虚拟机弄一个新的IP或新的端口号而劳神。
    • 服务器端的简洁。因为SSE能在现有的HTTP/HTTPS协议上运作,所以它能够直接运行于现有的代理服务器和认证技术。

WebSocket相较SSE最大的优势在于它是双向交流的,这意味着服务器发送数据就像从服务器接受数据一样简单,而SSE一般通过一个独立的Ajax请求从客户端向服务端传送数据,因此相对于WebSocket使用Ajax会增加开销。因此,如果需要以每秒一次或者更快的频率向服务端传输数据,就应该用WebSocket。

SSE(Server-sent Events)在HTML 5中的技术规范和定义

  • Server-sent Events 规范比较简单,主要由两个部分组成:第一个部分是服务器端与浏览器端之间的通讯协议。第二部分则是在浏览器端可供 JavaScript 使用的 EventSource 对象。
  • 通讯协议是基于纯文本的简单协议
  • 服务器端的响应的内容类型是“text/event-stream”。响应文本的内容可以看成是一个事件流,由不同的事件所组成。
  • 每个事件由类型和数据两部分组成,同时每个事件可以有一个可选的标识符
  • 不同事件的内容之间通过仅包含回车符和换行符的空行(“\r\n”)来分隔。每个事件的数据可能由多行组成。

服务器端响应的示例 :

1
2
3
4
5
6
7
8
9
10
11
12
data: first event

data: second event
id: 100

event: myevent
data: third event
id: 101

: this is a comment
data: fourth event
data: fourth event continue
  • 每个事件之间通过空行来分隔。
  • 对于每一行来说,冒号(“:”)前面表示的是该行的类型,冒号后面则是对应的值。可能的类型包括:
    • 类型为空白,表示该行是注释,会在处理时被忽略。
    • 类型为 data,表示该行包含的是数据。以 data 开头的行可以出现多次。所有这些行都是该事件的数据。
    • 类型为 event,表示该行用来声明事件的类型。浏览器在收到数据时,会产生对应类型的事件。
    • 类型为 id,表示该行用来声明事件的标识符。
    • 类型为 retry,表示该行用来声明浏览器在连接断开之后进行再次连接之前的等待时间。

在代码清单 1 中,

  1. 第一个事件只包含数据“first event”,会产生默认的事件;
  2. 第二个事件的标识符是 100,数据为“second event”;
  3. 第三个事件会产生类型为“myevent”的事件;
  4. 最后一个事件的数据为“fourth event\nfourth event continue”。当有多行数据时,实际的数据由每行数据以换行符连接而成。
  • 如果服务器端返回的数据中包含了事件的标识符,浏览器会记录最近一次接收到的事件的标识符。
    • 如果与服务器端的连接中断,当浏览器端再次进行连接时,会通过 HTTP 头“Last-Event-ID”来声明最后一次接收到的事件的标识符。
    • 服务器端可以通过浏览器端发送的事件标识符来确定从哪个事件开始来继续连接。
  • 对于服务器端返回的响应,浏览器端需要在 JavaScript 中使用 EventSource 对象来进行处理。
    • EventSource 使用的是标准的事件监听器方式,只需要在对象上添加相应的事件处理方法即可。

EventSource 提供了三个标准事件,

SSE技术详解:一种全新的HTML5服务器推送事件技术_QQ20160526-0.png

如之前所述,服务器端可以返回自定义类型的事件。对于这些事件,可以使用 addEventListener 方法来添加相应的事件处理方法。

EventSource 对象的使用示例:

1
2
3
4
5
6
7
8
var es = new EventSource('events');
es.onmessage = function(e) {
console.log(e.data);
};

es.addEventListener('myevent', function(e) {
console.log(e.data);
});
  • 在指定 URL 创建出 EventSource 对象之后,可以通过 onmessage 和 addEventListener 方法来添加事件处理方法。
  • 当服务器端有新的事件产生,相应的事件处理方法会被调用。
  • EventSource 对象的 onmessage 属性的作用类似于 addEventListener( ‘ message ’ ),不过 onmessage 属性只支持一个事件处理方法。

SSE实战示例:服务器端和浏览器端实现

  • 服务器端推送事件是一个比较简单的协议。服务器端的实现也相对比较简单,只需要按照协议规定的格式,返回响应内容即可。
  • 本文使用 Java 作为服务器端的实现语言。相应的实现基于开源的 jetty-eventsource-servlet 项目。示例用来模拟一个物体在某个限定空间中的随机移动。该物体从一个随机位置开始,然后从上、下、左和右四个方向中随机选择一个方向,并在该方向上移动随机的距离。服务器端不断改变该物体的位置,并把位置信息推送给浏览器,由浏览器来显示。

EventSource 接口的实现类 MovementEventSource:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public class MovementEventSource implements EventSource {
private int width = 800;
private int height = 600;
private int stepMax = 5;
private int x = 0;
private int y = 0;
private Random random = new Random();
private Logger logger = Logger.getLogger(getClass().getName());

public MovementEventSource(int width, int height, int stepMax) {
this.width = width;
this.height = height;
this.stepMax = stepMax;
this.x = random.nextInt(width);
this.y = random.nextInt(height);
}

@Override
public void onOpen(Emitter emitter) throws IOException {
query(emitter); //开始生成位置信息
}

@Override
public void onResume(Emitter emitter, String lastEventId)
throws IOException {
updatePosition(lastEventId); //更新起始位置
query(emitter); //开始生成位置信息
}

//根据Last-Event-Id来更新起始位置
private void updatePosition(String id) {
if (id != null) {
String[] pos = id.split(",");
if (pos.length > 1) {
int xPos = -1, yPos = -1;
try {
xPos = Integer.parseInt(pos[0], 10);
yPos = Integer.parseInt(pos[1], 10);
} catch (NumberFormatException e) {

}
if (isValidMove(xPos, yPos)) {
x = xPos;
y = yPos;
}
}
}
}

private void query(Emitter emitter) throws IOException {
emitter.comment("Start sending movement information.");
while(true) {
emitter.comment("");
move(); //移动位置
String id = String.format("%s,%s", x, y);
emitter.id(id); //根据位置生成事件标识符
emitter.data(id); //发送位置信息数据
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
logger.log(Level.WARNING, \
"Movement query thread interrupted. Close the connection.", e);
break;
}
}
emitter.close(); //当循环终止时,关闭连接
}

@Override
public void onClose() {

}

//获取下一个合法的移动位置
private void move() {
while (true) {
int[] move = getMove();
int xNext = x + move[0];
int yNext = y + move[1];
if (isValidMove(xNext, yNext)) {
x = xNext;
y = yNext;
break;
}
}
}

//判断当前的移动位置是否合法
private boolean isValidMove(int x, int y) {
return x >= 0 && x <= width && y >=0 && y <= height;
}

//随机生成下一个移动位置
private int[] getMove() {
int[] xDir = new int[] {-1, 0, 1, 0};
int[] yDir = new int[] {0, -1, 0, 1};
int dir = random.nextInt(4);
return new int[] {xDir[dir] * random.nextInt(stepMax), \
yDir[dir] * random.nextInt(stepMax)};
}
}
  • 类 MovementEventSource 需要实现 EventSource 接口的 onOpen、onResume 和 onClose 方法,
    • onOpen 方法在浏览器端的连接打开的时候被调用,
    • onResume 方法在浏览器端重新建立连接时被调用,
    • onClose 方法则在浏览器关闭连接的时候被调用。
    • onOpen 和 onResume 方法都有一个 EventSource.Emitter 接口类型的参数,可以用来发送数据。
  • EventSource.Emitter 接口中包含的方法包括 data、event、comment、id 和 close 等,分别对应于通讯协议中各种不同类型的事件。而 onResume 方法还额外包含一个参数 lastEventId,表示通过 Last-Event-ID 头发送过来的最近一次事件的标识符。

MovementEventSource 类中事件生成的主要逻辑在 query 方法中。该方法中包含一个无限循环,每隔 2 秒钟改变一次位置,同时把更新之后的位置通过 EventSource.Emitter 接口的 data 方法发送给浏览器端。每个事件都有对应的标识符,而标识符的值就是位置本身。如果连接断开之后,浏览器重新进行连接,可以从上一次的位置开始继续移动该物体。

servlet 实现类 MovementServlet比较简单,只需要继承自 EventSourceServlet 类并覆写 newEventSource 方法即可。在 newEventSource 方法的实现中,需要返回一个 MovementEventSource 类的对象。每当浏览器端建立连接时,该 servlet 会创建一个新的 MovementEventSource 类的对象来处理该请求。

1
2
3
4
5
6
public class MovementServlet extends EventSourceServlet { 
@Override
protected EventSource newEventSource(HttpServletRequest request, String clientId) {
return new MovementEventSource(800, 600, 20);
}
}

浏览器端实现

浏览器端的实现也比较简单,只需要创建出 EventSource 对象,并添加相应的事件处理方法即可。

代码如下。在页面中使用一个方块表示物体。当接收到新的事件时,根据事件数据中给出的坐标信息,更新方块在页面上的位置。

1
2
3
4
5
6
7
8
var es = new EventSource('sse/movement'); 
es.addEventListener('message', function(e) {
var pos = e.data.split(','), x = pos[0], y = pos[1];
$('#box').css({
left : x + 'px',
top : y + 'px'
});
});

技术参考

关于Ajax短轮询:
找这方面的资料没什么意义,除非忽悠客户,否则请考虑其它3种方案即可。

有关Comet技术的详细介绍请参见:
Comet技术详解:基于HTTP长连接的Web端实时通信技术
WEB端即时通讯:HTTP长连接、长轮询(long polling)详解
WEB端即时通讯:不用WebSocket也一样能搞定消息的即时性
开源Comet服务器iComet:支持百万并发的Web端即时通讯方案

有关WebSocket的详细介绍请参见:
WebSocket详解(一):初步认识WebSocket技术
WebSocket详解(二):技术原理、代码演示和应用案例
WebSocket详解(三):深入WebSocket通信协议细节
WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)
WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)
WebSocket详解(六):刨根问底WebSocket与Socket的关系
理论联系实际:从零理解WebSocket的通信原理、协议格式、安全性
八问WebSocket协议:为你快速解答WebSocket热门疑问
Socket.IO介绍:支持WebSocket、用于WEB端的即时通讯的框架
socket.io和websocket 之间是什么关系?有什么区别?

有关SSE的详细介绍文章请参见:
SSE技术详解:一种全新的HTML5服务器推送事件技术

即时通讯技术资料分类

[1] 网络编程基础资料:
TCP/IP详解 - 第11章·UDP:用户数据报协议
TCP/IP详解 - 第17章·TCP:传输控制协议
TCP/IP详解 - 第18章·TCP连接的建立与终止
TCP/IP详解 - 第21章·TCP的超时与重传
理论经典:TCP协议的3次握手与4次挥手过程详解
理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程
计算机网络通讯协议关系图(中文珍藏版)
NAT详解:基本原理、穿越技术(P2P打洞)、端口老化等
UDP中一个包的大小最大能多大?
Java新一代网络编程模型AIO原理及Linux系统AIO介绍
NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战
NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战

[2] 有关IM/推送的通信格式、协议的选择:
为什么QQ用的是UDP协议而不是TCP协议?
移动端即时通讯协议选择:UDP还是TCP?
如何选择即时通讯应用的数据传输格式
强列建议将Protobuf作为你的即时通讯应用数据传输格式
移动端IM开发需要面对的技术问题(含通信协议选择)
简述移动端IM开发的那些坑:架构设计、通信协议和客户端
理论联系实际:一套典型的IM通信协议设计详解
58到家实时消息系统的协议设计等技术实践分享

[3] 有关IM/推送的心跳保活处理:
Android进程保活详解:一篇文章解决你的所有疑问
Android端消息推送总结:实现原理、心跳保活、遇到的问题等
为何基于TCP协议的移动端IM仍然需要心跳保活机制?
微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)
微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)
移动端IM实践:实现Android版微信的智能心跳机制
移动端IM实践:WhatsApp、Line、微信的心跳策略分析

[4] 有关WEB端即时通讯开发:
新手入门贴:史上最全Web端即时通讯技术原理详解
Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE
SSE技术详解:一种全新的HTML5服务器推送事件技术
Comet技术详解:基于HTTP长连接的Web端实时通信技术
WebSocket详解(一):初步认识WebSocket技术
socket.io实现消息推送的一点实践及思路

[5] 有关IM架构设计:
浅谈IM系统的架构设计
简述移动端IM开发的那些坑:架构设计、通信协议和客户端
一套原创分布式即时通讯(IM)系统理论架构方案
从零到卓越:京东客服即时通讯系统的技术架构演进历程
蘑菇街即时通讯/IM服务器开发之架构选择
腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT
微信技术总监谈架构:微信之道——大道至简(演讲全文)
如何解读《微信技术总监谈架构:微信之道——大道至简》
快速裂变:见证微信强大后台架构从0到1的演进历程(一)
17年的实践:腾讯海量产品的技术方法论

[6] 有关IM安全的文章:
即时通讯安全篇(一):正确地理解和使用Android端加密算法
即时通讯安全篇(二):探讨组合加密算法在IM中的应用
即时通讯安全篇(三):常用加解密算法与通讯安全讲解
即时通讯安全篇(四):实例分析Android中密钥硬编码的风险
传输层安全协议SSL/TLS的Java平台实现简介和Demo演示
理论联系实际:一套典型的IM通信协议设计详解(含安全层设计)
微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解
来自阿里OpenIM:打造安全可靠即时通讯服务的技术实践分享

[7] 有关实时音视频开发:
即时通讯音视频开发(一):视频编解码之理论概述
即时通讯音视频开发(二):视频编解码之数字视频介绍
即时通讯音视频开发(三):视频编解码之编码基础
即时通讯音视频开发(四):视频编解码之预测技术介绍
即时通讯音视频开发(五):认识主流视频编码技术H.264
即时通讯音视频开发(六):如何开始音频编解码技术的学习
即时通讯音视频开发(七):音频基础及编码原理入门
即时通讯音视频开发(八):常见的实时语音通讯编码标准
即时通讯音视频开发(九):实时语音通讯的回音及回音消除概述
即时通讯音视频开发(十):实时语音通讯的回音消除技术详解
即时通讯音视频开发(十一):实时语音通讯丢包补偿技术详解
即时通讯音视频开发(十二):多人实时音视频聊天架构探讨
即时通讯音视频开发(十三):实时视频编码H.264的特点与优势
即时通讯音视频开发(十四):实时音视频数据传输协议介绍
即时通讯音视频开发(十五):聊聊P2P与实时音视频的应用情况
即时通讯音视频开发(十六):移动端实时音视频开发的几个建议
即时通讯音视频开发(十七):视频编码H.264、V8的前世今生
简述开源实时音视频技术WebRTC的优缺点
良心分享:WebRTC 零基础开发者教程(中文)

[8] IM开发综合文章:
移动端IM开发需要面对的技术问题
开发IM是自己设计协议用字节流好还是字符流好?
请问有人知道语音留言聊天的主流实现方式吗?
IM系统中如何保证消息的可靠投递(即QoS机制)
谈谈移动端 IM 开发中登录请求的优化
完全自已开发的IM该如何设计“失败重试”机制?
微信对网络影响的技术试验及分析(论文全文)
即时通讯系统的原理、技术和应用(技术论文)
开源IM工程“蘑菇街TeamTalk”的现状:一场有始无终的开源秀

[9] 开源移动端IM技术框架资料:
开源移动端IM技术框架MobileIMSDK:快速入门
开源移动端IM技术框架MobileIMSDK:常见问题解答
开源移动端IM技术框架MobileIMSDK:压力测试报告
开源移动端IM技术框架MobileIMSDK:Android版Demo使用帮助
开源移动端IM技术框架MobileIMSDK:Java版Demo使用帮助
开源移动端IM技术框架MobileIMSDK:iOS版Demo使用帮助
开源移动端IM技术框架MobileIMSDK:Android客户端开发指南
开源移动端IM技术框架MobileIMSDK:Java客户端开发指南
开源移动端IM技术框架MobileIMSDK:iOS客户端开发指南
开源移动端IM技术框架MobileIMSDK:Server端开发指南

[10] 有关推送技术的文章:
iOS的推送服务APNs详解:设计思路、技术原理及缺陷等
Android端消息推送总结:实现原理、心跳保活、遇到的问题等
扫盲贴:认识MQTT通信协议
一个基于MQTT通信协议的完整Android推送Demo
求教android消息推送:GCM、XMPP、MQTT三种方案的优劣
移动端实时消息推送技术浅析
扫盲贴:浅谈iOS和Android后台实时消息推送的原理和区别
绝对干货:基于Netty实现海量接入的推送服务技术要点
移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)
为何微信、QQ这样的IM工具不使用GCM服务推送消息?