使用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>
前端部分代码(一对一)

 

相关文章
相关标签/搜索