一、为什么需要 WebSocket?
初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处?
答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起。
举例来说,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。
WebSocket的出现,使得浏览器具备了实时双向通信的能力
优点:支持双向通信,更灵活,更高效,可扩展性更好。
其他特点包括:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是ws
(如果加密,则为wss
),服务器网址就是 URL。
WebSocket 属性
以下是 WebSocket 对象的属性。假定我们使用了以上代码创建了 Socket 对象:
属性 | 描述 |
---|---|
Socket.readyState | 只读属性 readyState 表示连接状态,可以是以下值:0 - 表示连接尚未建立。1 - 表示连接已建立,可以进行通信。2 - 表示连接正在进行关闭。3 - 表示连接已经关闭或者连接不能打开。 |
Socket.bufferedAmount | 只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。 |
WebSocket 事件
以下是 WebSocket 对象的相关事件。假定我们使用了以上代码创建了 Socket 对象:
事件 | 事件处理程序 | 描述 |
---|---|---|
open | Socket.onopen | 连接建立时触发 |
message | Socket.onmessage | 客户端接收服务端数据时触发 |
error | Socket.onerror | 通信发生错误时触发 |
close | Socket.onclose | 连接关闭时触发 |
WebSocket 方法
以下是 WebSocket 对象的相关方法。假定我们使用了以上代码创建了 Socket 对象:
方法 | 描述 |
---|---|
Socket.send() | 使用连接发送数据 |
Socket.close() | 关闭连接 |
示例
// 初始化一个 WebSocket 对象 var ws = new WebSocket("ws://localhost:9998/echo"); // 建立 web socket 连接成功触发事件 ws.onopen = function () { // 使用 send() 方法发送数据 ws.send("发送数据"); alert("数据发送中..."); }; // 接收服务端数据时触发事件 ws.onmessage = function (evt) { var received_msg = evt.data; alert("数据已接收..."); }; // 断开 web socket 连接成功触发事件 ws.onclose = function () { alert("连接已关闭..."); };
后端代码:
from flask import Flask,request,render_template from geventwebsocket.handler import WebSocketHandler # from gevent.pywsgi import WSGIServer # 启动服务 为了让的服务支持Wsgi from geventwebsocket.websocket import WebSocket # 实现你的websocket的模块 import json app = Flask(__name__) user_dict = {} @app.route("/<username>") def index(username): print(333) user_socket = request.environ.get("wsgi.websocket") #把用户的信息存在了eviron字典中 然后键是wsgi.websocket 这样取到的是用户的信息 print(user_socket) if user_socket: user_dict[username] = user_socket #把用户的信息存进字典 print(user_dict) while True: msg = user_socket.receive() #收到消息 recv_msg = json.loads(msg) #把你发来的消息反序列化 send_msg = { "user_name":recv_msg.get("user_name"), #取到username "msg":recv_msg.get("msg") #取到用户信息 } print(send_msg) for i in user_dict.values(): #循环你的消息字典 如果你的对象等于本机的 就直接返回 不去管 if i == user_socket: continue i.send(json.dumps(send_msg)) @app.route("/ws") def ws(): print(333) return render_template("群聊.html") if __name__ == "__main__": http_serv = WSGIServer(("0.0.0.0",9980),app,handler_class=WebSocketHandler) http_serv.serve_forever()
前端界面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>群聊</title> </head> <body> 你的昵称: <input type="text" id="nickname"> <button onclick="connws()">连接服务器</button> <br><br> 发送消息: <input type="text" id="talk"> <button onclick="send_msg()">发送消息</button> <div style=" 500px;height: 200px;border: 1px red solid;" id="text"> </div> </body> <script type="application/javascript"> var user_name = null; var ws = null; function connws(){//这个是你的信息进行提交的时候 user_name = document.getElementById("nickname").value; ws = new WebSocket("ws://192.168.11.63:9980/"+user_name); ws.onmessage = function(data){ // onmessage接收消息 var recv_msg = JSON.parse(data.data); {#console.log(recv_msg);#} createDiv(recv_msg.user_name,recv_msg.msg) //把你发送的信息渲染到那个框中 } } function send_msg(){ //这个你要发送的信息或者他人要发送的信息 var talk = document.getElementById("talk").value; // 获取你的提交的信息 createDiv("w",talk); send_str = { user_name:user_name, msg:talk }; ws.send(JSON.stringify(send_str)); }; function createDiv(self,content){ // 这个是提交信息的时候下面出现的对话框 var divtag = document.createElement("div"); //定义个div标签 var who = self+" : "; if (self == "w"){ who = "我 : "; } divtag.innerText = who + content; //如果事其他人的话就把你的信息给 他人的名字加上信息 var text = document.getElementById("text"); text.appendChild(divtag) } </script> </html>