博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
初试WebSocket构建聊天程序
阅读量:5906 次
发布时间:2019-06-19

本文共 3845 字,大约阅读时间需要 12 分钟。

上一篇文章中使用了Ajax long polling实现了一个简单的聊天程序,对于web实时通信,今天就来试用一下基于WebSocket的长连接方式。

WebSocket简介

为了增强web通信的功能,在HTML5中,提供了WebSocket,它不仅仅是一种web通信方式,也是一种应用层协议。

WebSocket提供了客户端和服务端之间的双全工跨域通信,通过客户端和服务端之间建立WebSocket连接(实际上是TCP连接,后面会看到),在同一时刻能够实现客户端到服务器和服务器到客户端的数据发送。

Ajax long polling是一种客户端去服务端拉取数据的方式,而WebSocket则能真正实现服务端主动向客户端推送数据。下图形象的展示了WebSocket的工作方式。

对于WebSocket这种新的应用层协议,在实现应用的时候,客户端和服务端都需要遵循WebSocket协议,关于更多的WebSocket内容,请参考。

实现

首先,还是先看看通过WebSocket实现的聊天程序的代码以及效果,然后再看WebSocket工作方式相关的内容。

客户端

因为并不是所有版本的浏览器都能够支持WebSocket,所以例子中通过下面代码来检测当前浏览器是否支持WebSocket。

if(window.WebSocket){    //support WebSocket, more code here}else{    alert("WebSocket was not supported");}

对于客户端,主要就是updater这个对象,该对象会创建并维护了一个WebSocket对象,通过这个WebSocket对象就可以跟服务端进行交互(收取或发送消息)。

var updater = {     socket: null,     start: function() {         var url = "ws://" + location.host + "/chatsocket";         updater.socket = new WebSocket(url);                  updater.socket.onopen = function(event) {         }                  updater.socket.onclose = function(event) {             alert("server socket closed");         }                  updater.socket.onmessage = function(event) {             updater.showMessage(event.data);         }     },     showMessage: function(message) {         console.log(message);         $("#inbox").append(message);         $("#message").val("");     } };

服务端

对于服务端,这次使用了gevent-websocket这个库,可以很方便的通过pip进行安装。

服务端通过MessageBuffer这个类来管理所有的消息,以及所有的WebSocket client。由于WebSocket是一种长连接的方式,所以可以很容易的统计出当前在线的client的数量。

class MessageBuffer(object):    def __init__(self, cache_size = 200):        self.cache = []        self.cache_size = cache_size        self.clients = []            def new_message(self, msg):        self.cache.append(msg)        if len(self.cache) > self.cache_size:            self.cache = self.cache[-self.cache_size:]                def update_clients(self, msg):        for client in self.clients:            client.send(msg)

跟上次相比,使用WebSocket之后,服务器代码更加简洁了。当客户端发起"/chatsocket"请求后,服务器就会跟客户端建立连接,并将客户端加入"messageBuffer.clients"列表中;当客户端断开连接,就会将客户端从"messageBuffer.clients"列表中移除。

当服务器收到新消息后,就会通过"messageBuffer.update_clients"方法,将新消息推送到所有的客户端。

def application(env, start_response):    # visit the main page    if env['PATH_INFO'] == '/':        # some code to load main page here        elif env['PATH_INFO'] == '/chatsocket':        ws = env["wsgi.websocket"]        messageBuffer.clients.append(ws)        print "new client join, total client count %d" %len(messageBuffer.clients)        while True:            message = ws.receive()            if message is None:                messageBuffer.clients.remove(ws)                print "client leave, total client count %d" %len(messageBuffer.clients)                break            print "Got message: %s" %message            message = "
{0}
".format(message) messageBuffer.new_message(message) messageBuffer.update_clients(message)

运行效果

下面就是代码的运行效果。

由于WebSocket是长连接的方式,所以可以方便的统计当前在线客户端数量。

当关闭服务器的时候,客户端也可以检测到连接的断开。

WebSocket工作机制

下面就从工作机制来看看WebSocket是怎么为应用提供长连接服务的。

WebSocket连接建立

虽然WebSocket是一种新的应用层协议,但是它的工作也是要依赖于http协议的。

通过Wireshark,我们可以抓到下面的数据包。

这两个数据包就是建立WebSocket连接的握手过程(WebSocket Protocol handshake):

1. 客户端的WebSocket实例绑定一个需要连接到的服务器地址,当客户端连接服务端的时候,会向服务端发送一个类似下面的HTTP GET请求

在上面的请求中有一个Upgrade首部,这个首部是告诉服务端需要将通信协议切换到WebSocket

2. 在收到带有"Upgrade: websocket"首部的请求后,如果服务端支持WebSocket协议,那么它就会将自己的通信协议切换到WebSocket,同时发给客户端类似以下的响应报文头。

响应报文的状态码为101,表示同意客户端协议转换请求,并将它转换为WebSocket协议。到此,客户端和服务端的WebSocket连接就建立成功了,以后的通信就是基于WebSocket连接了。

WebSocket连接保活

WebSocket底层的工作/实现都是基于TCP协议,所以连接的保活机制是跟TCP一样的,就是通过"TCP Keep-Alive"心跳包来保证连接始终处于有效状态。

WebSocket连接关闭

对于WebSocket连接的关闭,也是主动关闭端发送"FIN, ACK"数据包来完成关闭的。

总结

本文简单介绍了HTML5中的WebSocket协议,并通过WebSocket实现了一个简单的聊天程序。

WebSocket能在客户端和服务端建立长连接,并提供全双工的数据传输,提供了服务器推送数据的模式。

跟Ajax long polling方式进行对比,这种服务器主动推送数据的方式更加适合实时数据交互应用。

Ps:

通过可以下载例子的源码。

 

转载地址:http://mvcpx.baihongyu.com/

你可能感兴趣的文章
vc2010混用debug或者release静态库提示error LNK2038的解决办法
查看>>
elasticsearch Java API 之Bulk API(批量操作)
查看>>
好的javascript程序员
查看>>
oracle自动生成uuid
查看>>
Spring Cloud Config采用数据库存储配置内容【Edgware+】
查看>>
[周榜单]极乐小程序榜单(第十三期)
查看>>
[JAVA多线程相关资料]
查看>>
单点登录实现思路
查看>>
POJ p1979 递归
查看>>
opencv计算时间
查看>>
性能瓶颈的分类
查看>>
maven scope system
查看>>
#综合实践#通过puppet管理远程docker容器——配置puppet和实现变更
查看>>
PLSQL连Oracle数据库Could not load "……\bin\oci.dll"
查看>>
centos6.4安装GitLab
查看>>
Spring(Test)
查看>>
Ruby on Rails vs. PHP vs. Python
查看>>
Android图片剪切
查看>>
如何将 rhevm 加入 AD 域
查看>>
使用putty远程连接linux防止关闭putty程序就停止
查看>>