flask-socketio实现

websocket可以实现client和server之间的双向通信,可以用来做为聊天室的传输方式 。下面一个小例子展示如果使用:
网页的代码部分:

    <script type="text/javascript" src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
    <script type="text/javascript" src="//cdn.bootcss.com/socket.io/1.5.1/socket.io.min.js"></script>
    <script type="text/javascript" charset="utf-8">
        $(document).ready(function () {

            var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port);
            socket.on('message', function (msg) {
                if (msg.data === 'error') {
                    window.open('/');
                }
                else {
                    var message = msg.data;
                    var username = msg.username
                    $('#chat').append(username + ": ");
                    $('#chat').append(message);
                    $('#chat').append('<br>')
                    var chatlist = document.getElementById('chat');
                    chatlist.scrollTop = chatlist.scrollHeight;
                    chatlist.scrollTop = chatlist.scrollHeight;
                }
            });

            $('#mess').submit(function (event) {
                var message = $('#message').val();
                socket.emit('message', {data: message});
                return false;
            });
        })
    </script>

服务端:


@socketio.on('message')
def client_msg(msg):
    if current_user.is_authenticated:
        message = Message(from_user=current_user.username, content=msg['data'])
        db.session.add(message)
        db.session.commit()
        a = {'data': (msg['data']), 'username': current_user.username}
        send(a, broadcast=True)
    else:
        send({'data': 'error'}, broadcast=False)
        disconnect()


服务端创建了一个’message’事件,接收前端’message’事件发来的消息,并存入数据库,随后将这个消息传送给所有已连接的client(包括发送这条消息的客户端,因为client这里设计的逻辑是:发送的消息不会展示在页面,只显示接受的消息)。因为websocket建立的时候是通过http进行握手的,所有在websocket建立之前可以从cookie中得到用户的信息,并且该扩展可以从对应的cookie中得到用户信息,因此current_user可用。
下面的是在事件触发后,扩展内部的部分代码,handler()就是’message’下面定义的函数:

        with app.request_context(self.server.environ[sid]):
            if self.manage_session:
                # manage a separate session for this client's Socket.IO events
                # created as a copy of the regular user session
                if 'saved_session' not in self.server.environ[sid]:
                    self.server.environ[sid]['saved_session'] = \
                        _ManagedSession(flask.session)
                session_obj = self.server.environ[sid]['saved_session']
            else:
                # let Flask handle the user session
                # for cookie based sessions, this effectively freezes the
                # session to its state at connection time
                # for server-side sessions, this allows HTTP and Socket.IO to
                # share the session, with both having read/write access to it
                session_obj = flask.session._get_current_object()  #获得真实对象   _request_ctx_stack.top.session指的就是真实对象,session是代理后的对象
            _request_ctx_stack.top.session = session_obj 
            flask.request.sid = sid
            flask.request.namespace = namespace
            flask.request.event = {'message': message, 'args': args}
            try:
                if message == 'connect':
                    ret = handler()

当manage_session为True时,扩展会复制一个session到self.server.environ中,并以SID作为key,然后将这个_request_ctx_stack.top.session指向这个session对象,这样就可以在event对应的函数中修改session,但是这个修改的session并不会被保存在client中,因为websocket不支持设置cookie,被修改的session在下次事件被触发时生效。
flask-socketio和js中的socket 默认的域都是socket.io,如果想修改这个值,必须前后端同时修改,否则不能建立,

        path = environ['PATH_INFO']
        if path is not None and \
                path.startswith('/{0}/'.format(self.engineio_path)):
            return self.engineio_app.handle_request(environ, start_response)
        elif self.wsgi_app is not None:
            return self.wsgi_app(environ, start_response)
        else:
            start_response("404 Not Found", [('Content-type', 'text/plain')])
            return ['Not Found']

flask-socketio初始化:
        if app is not None:
            # here we attach the SocketIO middlware to the SocketIO object so it
            # can be referenced later if debug middleware needs to be inserted
            self.sockio_mw = _SocketIOMiddleware(self.server, app,
                                                 socketio_path=resource)
            app.wsgi_app = self.sockio_mw

class _SocketIOMiddleware(socketio.Middleware):
    """This WSGI middleware simply exposes the Flask application in the WSGI
    environment before executing the request.
    """
    def __init__(self, socketio_app, flask_app, socketio_path='socket.io'):
        self.flask_app = flask_app
        super(_SocketIOMiddleware, self).__init__(socketio_app,
                                                  flask_app.wsgi_app,
                                                  socketio_path)

    def __call__(self, environ, start_response):
        environ = environ.copy()
        environ['flask.app'] = self.flask_app
        return super(_SocketIOMiddleware, self).__call__(environ,
                                                         start_response)

flask-socketio在初始化的时候,会增加一个中间件来分别处理socket通信和http通信,真正处理这件事是engineio.Middleware 。因为socketio的实现是通过engineio实现的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值