# 8. 怎样制造出实时效果-ws

![](https://github.com/XiaohanLiang/review/tree/b072a593745a8bc3284d9e176e0a8e91afc16cfa/upper/img/gotty.png)

我前两天在折腾一个网页 Terminal (名字叫gotty), 就有时候你在Chrome里执行一些简单的命令, 但是切屏去命令行太麻烦了. 因此搞了一个这个, 用着用着觉得有一点很神奇, 就这&#x79CD;**"实时"**&#x7684;效果是怎么做出来的? 很多网页也想做到实时的效果, 比如实时股价, 实时交通拥堵地图等, 他们的做法简单点就是疯狂用http刷(就是Ajax轮询) 或是long polling. 这个用的那种?

## 平等聊天 & 一问一答

我们仔细想想这种东西... http 是什么样的, 客户端问, 服务端答, 就写死了只能这样, 服务器能主动说些什么吗? 不行, 如果客户端不问你就不能主动说任何东西. 就算搞 http-pipeline, 那也是一次问好几个问题, 然后服务器回答好几个问题, 那说到底还不是一问一答...

那么tcp是什么样的呢? tcp可以"不问自答"吗? 服务端可以主动给客户端发消息吗? 答案是可以的, tcp连接建立完成, 双方开始正常通信以后, 双方就是平等的关系: 其中一个人主动发问, 另一个人回答ACK, 无论谁都可以主动联系对方, 因此就不存在只有固定一个人提问另一个人回答的形式. **这种"平等聊天"的特性成为了websocket的基础**

说到这儿不禁让人想起iPhone上的App推送, 或者微信消息来了你的手机会主动"叮"一下提醒你, 他是怎么主动告诉你的? 明明没有人主动去请求最新消息呀. 现在常用的做法是**弄出一个tcp长连接 + 心跳**. 服务端每次发现有你的消息的时候, 就根据你的Channel ID拿到你的长连接, 然后把你的消息发送给你, **实现服务端主动发消息的效果**

上面的那个 WebTerminal 就使用了TCP平等聊天的特点, 本质上是一个TCP长连接, 考虑到没有人能裸用TCP所以我们对它做了一个最简单的封装, 我们叫它 websocket 协议.

## WS协议体

![](https://github.com/XiaohanLiang/review/tree/b072a593745a8bc3284d9e176e0a8e91afc16cfa/upper/img/ws-protocol.png)

ws协议实现了我们设想中: "既然TCP不能裸用, 那我们对它进行最minimized的封装", 报头只有两个byte, 非常简单, 是最接近裸TCP特性的 (正文里的 rgb255 是设置网页背景颜色的)

![](https://github.com/XiaohanLiang/review/tree/b072a593745a8bc3284d9e176e0a8e91afc16cfa/upper/img/ws-handshake.png)

ws的握手是用http做的. 也就是在某几个http消息发完以后双方就正式开始使用ws协议通信了, 报文就要带上两字节的报头了 (用http做握手挺魔性的, 我没见过用一个复杂协议去握手一个简单协议的, 不过非要这么做好像也不会损失什么, 我猜ws被设计之初就是为了在网页上做出实时的效果, 而网页上搞http是最容易最方便的, 因此使用http做握手, 因此也才叫它 WEB-socket 吧, 我猜的)
