使用websocket實現聊天室功能

前言

websocket是HTML5出的一個新的網絡通訊協議,與HTTP協議沒有關係。它們倆能夠說是獨立的兩個協議,可是也會有一些共同點。javascript

HTTP 協議是一種無狀態的、無鏈接的、單向的應用層協議。它採用了請求/響應模型。通訊請求只能由客戶端發起,服務端對請求作出應答處理。css

這種通訊模型有一個弊端:HTTP 協議沒法實現服務器主動向客戶端發起消息。html

這種單向請求的特色,註定了若是服務器有連續的狀態變化,客戶端要獲知就很是麻煩。大多數 Web 應用程序將經過頻繁的異步JavaScript和XML(AJAX)請求實現長輪詢。輪詢的效率低,很是浪費資源(由於必須不停鏈接,或者 HTTP 鏈接始終打開)。前端

它是一個非持久化的協議,還有着有版本之分,有1.0,1.1,它的生命週期有Request來界定,在1.0版本中,一次請求,一次響應,那麼此次請求就結束了。可是如今主流版本已是1.1了,對於這種請求也有了改進,能夠實現長鏈接,也就是說在一個HTTP當中能夠發送多個請求,接收多個響應,可是必定要明確的一個點,必須一個請求對應一個響應,並且必須先請求,才能返回響應
View Code

websocket簡介

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">

                    &nbsp;<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">
                    &nbsp;<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>
前端部分代碼(一對一)

 

相關文章
相關標籤/搜索