websocket是HTML5出的一個新的網絡通訊協議,與HTTP協議沒有關係。它們倆能夠說是獨立的兩個協議,可是也會有一些共同點。javascript
HTTP 協議是一種無狀態的、無鏈接的、單向的應用層協議。它採用了請求/響應模型。通訊請求只能由客戶端發起,服務端對請求作出應答處理。css
這種通訊模型有一個弊端:HTTP 協議沒法實現服務器主動向客戶端發起消息。html
這種單向請求的特色,註定了若是服務器有連續的狀態變化,客戶端要獲知就很是麻煩。大多數 Web 應用程序將經過頻繁的異步JavaScript和XML(AJAX)請求實現長輪詢。輪詢的效率低,很是浪費資源(由於必須不停鏈接,或者 HTTP 鏈接始終打開)。前端
它是一個非持久化的協議,還有着有版本之分,有1.0,1.1,它的生命週期有Request來界定,在1.0版本中,一次請求,一次響應,那麼此次請求就結束了。可是如今主流版本已是1.1了,對於這種請求也有了改進,能夠實現長鏈接,也就是說在一個HTTP當中能夠發送多個請求,接收多個響應,可是必定要明確的一個點,必須一個請求對應一個響應,並且必須先請求,才能返回響應
WebSocket 是 HTML5 開始提供的一種在單個 TCP 鏈接上進行全雙工通信的協議。java
websocket是一個基於HTTP的網絡協議,它和HTTP最主要的區別就是它比較持久web
pip install flask
pip install gevent-websocket
聊天室功能使用了flask來進行模板,url之類的解析,不一樣之處是再也不使用flask自帶的容器,而是看成一個應用,被gevent裏的一個uwsgiserver容器來調用json
知識補充:flask
// 新建一個websocket連接 var s = new WebSocket("%s://%s/foobar/"); s.onopen = function() {} // 接收後端發送過來的數據 s.onmessage = function(e) {} s.onerror = function(e) {} // s.onclose = function(e) {} // 發送數據 s.send(value);
後端:bootstrap
from flask import Flask, request, render_template from geventwebsocket.websocket import WebSocket from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer import json app = Flask(__name__) @app.route("/index") def index(): return render_template("ws.html") user_socket_dict = {} @app.route("/ws/<username>") def ws(username): user_socket = request.environ.get("wsgi.websocket") # type: WebSocket if not user_socket: return "使用WebSocket方式鏈接" user_socket_dict[username] = user_socket print(user_socket_dict) while True: try: # 接收客戶端傳入數據 user_msg = user_socket.receive() # 將以用戶名爲鍵,鏈接爲值的字典迭代出全部的鍵值對 for k,v in user_socket_dict.items(): # 將當前發送數據的用戶以及數據放在一塊兒組成字典 # print(v) who_send_msg = { "send_user": username, "send_msg": user_msg } # print(who_send_msg) # 若是當前鏈接與迭代出來的鏈接相同,就跳過本次循環 if user_socket == v: continue # 不然 將用戶以及用戶數據以json格式發送出去 v.send(json.dumps(who_send_msg)) except Exception as e: # 當捕捉到異常的時候就將當前用戶從字典中刪除 user_socket_dict.pop(username)if __name__ == '__main__': http_serv = WSGIServer(("0.0.0.0",8000),app,handler_class=WebSocketHandler) http_serv.serve_forever()
前端代碼:後端
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <style> #chat_window { width: 450px; height: 450px; border: 1px solid black; border-radius: 20px; margin: 30px auto; } .span_div { margin: 25px; font-size: 18px; } .chat_span { font-size: 28px; border: 2px solid red; border-radius: 20px; } </style> </head> <body> <div class="container"> <h2 style="text-align: center">websocket聊天室</h2> <div class="row"> <div class="panel panel-info col-lg-6 col-lg-offset-3"> <div class="panel-heading">微信</div> <div class="panel-body"> <div style="text-align: center"> <label for="username">自報家門:</label> <input type="text" id="username"> <label for="to_username">發送目標:</label> <input type="text" id="to_username"> <button class="btn btn-danger" id="create_ws" onclick="go_to()">建立ws鏈接 </button> </div> <div id="chat_window"> </div> <div class="col-lg-12"> <div class="input-group"> <input type="text" class="form-control" id="send_msg"> <span class="input-group-btn"> <button class="btn btn-success" type="button" id="btn_send">發送</button> </span> </div><!-- /input-group --> </div><!-- /.col-lg-6 --> </div><!-- /.row --> </div> </div> </div> </div> </body> <script type="application/javascript"> var ws_url = "ws://127.0.0.1:8000/ws/"; var ws = null; function go_to() { var username = document.getElementById("username"); // 將用戶參數和url路徑一塊兒組成新的url ws = new WebSocket(ws_url + username.value); console.log(ws); // 接收後端傳入的信息 ws.onmessage = function (serv_msg) { msg = JSON.parse(serv_msg.data); console.log(msg); creat_chat('y', msg); }; } // 添加聊天記錄 function creat_chat(self, content) { if (self == 'w') { self = 'right'; // 將本身的聊天記錄放入span標籤 var span_tag = document.createElement('span'); span_tag.innerText = content.send_msg; // 將用戶名放入span標籤 var span_tag1 = document.createElement('span'); span_tag1.innerText = ":我"; span_tag1.setAttribute('class', 'chat_span') } else { self = 'left'; // 將好友的聊天記錄放入span標籤 var span_tag = document.createElement('span'); span_tag.innerText = content.send_user + ":"; span_tag.setAttribute('class', 'chat_span'); // 將用戶名放入span標籤 var span_tag1 = document.createElement('span'); span_tag1.innerText = content.send_msg; } // 建立一個大的div標籤 var div_tag = document.createElement('div'); div_tag.setAttribute('class', 'span_div'); // 修改樣式 div_tag.style = 'text-align:' + self; // 將聊天記錄和用戶名添加進來 div_tag.appendChild(span_tag); div_tag.appendChild(span_tag1); var chat_window = document.getElementById('chat_window'); chat_window.appendChild(div_tag) } // 事件監聽 ,點擊發送按鈕要執行的代碼 document.getElementById("btn_send").addEventListener("click", function () { // 取出你輸入框裏面的數據 var send_msg = document.getElementById("send_msg"); // 獲取發送目標標籤對象 var to_user = document.getElementById("to_username"); // 組成發送字典 send_msg_json = { send_msg: send_msg.value, to_user: to_user.value }; // 將字典進行序列化併發送 ws.send(JSON.stringify(send_msg_json)); var s_msg = {send_msg: send_msg.value}; creat_chat("w", s_msg); send_msg.value = '' }) </script> </html>
from flask import Flask, request, render_template from geventwebsocket.websocket import WebSocket from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer import json app = Flask(__name__) @app.route("/index2") def index(): return render_template("ws_one.html") user_socket_dict = {} @app.route("/ws/<username>") def ws(username): user_socket = request.environ.get("wsgi.websocket") # type: WebSocket if not user_socket: return "使用WebSocket方式鏈接" user_socket_dict[username] = user_socket while True: try: # 接收客戶端傳入數據 user_msg = user_socket.receive() user_msg = json.loads(user_msg) to_user_socket = user_socket_dict.get(user_msg.get("to_user")) # 將當前發送數據的用戶以及數據放在一塊兒組成字典 send_msg = { "send_user": username, "send_msg": user_msg.get("send_msg") } to_user_socket.send(json.dumps(send_msg)) except WebSocketHandler as e: # 當捕捉到異常的時候就將當前用戶從字典中刪除 user_socket_dict.pop(username) print(e) print(user_socket_dict) if __name__ == '__main__': http_serv = WSGIServer(("0.0.0.0",8000),app,handler_class=WebSocketHandler) http_serv.serve_forever()
前端代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <style> #chat_window { width: 450px; height: 450px; border: 1px solid black; border-radius: 20px; margin: 30px auto; } .span_div { margin: 25px; font-size: 18px; } .chat_span { font-size: 28px; border: 2px solid red; border-radius: 20px; } </style> </head> <body> <div class="container"> <h2 style="text-align: center">websocket聊天室</h2> <div class="row"> <div class="panel panel-info col-lg-6 col-lg-offset-3"> <div class="panel-heading">微信</div> <div class="panel-body"> <div style="text-align: center"> <label for="username">自報家門:</label> <input type="text" id="username"> <label for="to_username">發送目標:</label> <input type="text" id="to_username"> <button class="btn btn-danger" id="create_ws" onclick="go_to()">建立ws鏈接 </button> </div> <div id="chat_window"> </div> <div class="col-lg-12"> <div class="input-group"> <input type="text" class="form-control" id="send_msg"> <span class="input-group-btn"> <button class="btn btn-success" type="button" id="btn_send">發送</button> </span> </div><!-- /input-group --> </div><!-- /.col-lg-6 --> </div><!-- /.row --> </div> </div> </div> </div> </body> <script type="application/javascript"> var ws_url = "ws://127.0.0.1:8000/ws/"; var ws = null; function go_to() { var username = document.getElementById("username"); // 將用戶參數和url路徑一塊兒組成新的url ws = new WebSocket(ws_url + username.value); console.log(ws); // 接收後端傳入的信息 ws.onmessage = function (serv_msg) { msg = JSON.parse(serv_msg.data); console.log(msg); creat_chat('y', msg); }; } // 添加聊天記錄 function creat_chat(self, content) { if (self == 'w') { self = 'right'; // 將本身的聊天記錄放入span標籤 var span_tag = document.createElement('span'); span_tag.innerText = content.send_msg; // 將用戶名放入span標籤 var span_tag1 = document.createElement('span'); span_tag1.innerText = ":我"; span_tag1.setAttribute('class', 'chat_span') } else { self = 'left'; // 將好友的聊天記錄放入span標籤 var span_tag = document.createElement('span'); span_tag.innerText = content.send_user + ":"; span_tag.setAttribute('class', 'chat_span'); // 將用戶名放入span標籤 var span_tag1 = document.createElement('span'); span_tag1.innerText = content.send_msg; } // 建立一個大的div標籤 var div_tag = document.createElement('div'); div_tag.setAttribute('class', 'span_div'); // 修改樣式 div_tag.style = 'text-align:' + self; // 將聊天記錄和用戶名添加進來 div_tag.appendChild(span_tag); div_tag.appendChild(span_tag1); var chat_window = document.getElementById('chat_window'); chat_window.appendChild(div_tag) } // 事件監聽 ,點擊發送按鈕要執行的代碼 document.getElementById("btn_send").addEventListener("click", function () { // 取出你輸入框裏面的數據 var send_msg = document.getElementById("send_msg"); var to_user = document.getElementById("to_username"); send_msg_json = { send_msg:send_msg.value, to_user:to_user.value }; ws.send(JSON.stringify(send_msg_json)); var s_msg = {send_msg: send_msg.value}; creat_chat("w", s_msg); send_msg.value = '' }) </script> </html>