WebSocket实现android消息推送

来源:互联网 发布:经济大数据分析书籍 编辑:程序博客网 时间:2024/04/30 04:20

WebSocket实现android消息推送

WebSocket是HTML5出的协议,基于TCP。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。

WebSocket协议之前,双工通信是通过多个http链接来实现,这导致了效率低下。WebSocket解决了这个问题。

有了websocket协议,服务器就可以主动给客户端发送消息,而不是要等客户端的轮询。

实现一个简单的Websocket服务器

#-*- coding:utf8 -*-import threadingimport hashlibimport socketimport base64global clientsclients = {}#通知客户端def notify(message):    for connection in clients.values():        connection.send('%c%c%s' % (0x81, len(message), message))#客户端处理线程class websocket_thread(threading.Thread):    def __init__(self, connection, username):        super(websocket_thread, self).__init__()        self.connection = connection        self.username = username    def run(self):        print 'new websocket client joined!'        data = self.connection.recv(1024)        headers = self.parse_headers(data)        token = self.generate_token(headers['Sec-WebSocket-Key'])        self.connection.send('\HTTP/1.1 101 WebSocket Protocol Hybi-10\r\n\Upgrade: WebSocket\r\n\Connection: Upgrade\r\n\Sec-WebSocket-Accept: %s\r\n\r\n' % token)        while True:            try:                data = self.connection.recv(1024)            except socket.error, e:                print "unexpected error: ", e                clients.pop(self.username)                break            data = self.parse_data(data)            if len(data) == 0:                continue            message = "来自服务端的消息: " + data            notify(message)    def parse_data(self, msg):        v = ord(msg[1]) & 0x7f        if v == 0x7e:            p = 4        elif v == 0x7f:            p = 10        else:            p = 2        mask = msg[p:p+4]        data = msg[p+4:]        return ''.join([chr(ord(v) ^ ord(mask[k%4])) for k, v in enumerate(data)])    def parse_headers(self, msg):        headers = {}        header, data = msg.split('\r\n\r\n', 1)        for line in header.split('\r\n')[1:]:            key, value = line.split(': ', 1)            headers[key] = value        headers['data'] = data        return headers    def generate_token(self, msg):        key = msg + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'        ser_key = hashlib.sha1(key).digest()        return base64.b64encode(ser_key)#服务端class websocket_server(threading.Thread):    def __init__(self, port):        super(websocket_server, self).__init__()        self.port = port    def run(self):        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)        sock.bind(('0.0.0.0', self.port))        sock.listen(5)        print 'websocket server started!'        while True:            connection, address = sock.accept()            try:                username = "ID" + str(address[1])                thread = websocket_thread(connection, username)                thread.start()                clients[username] = connection            except socket.timeout:                print 'websocket connection timeout!'if __name__ == '__main__':    server = websocket_server(9000)     server.start()

注意:这里服务器的ip设置最好设置为0.0.0.0,允许局域网其他计算机访问

网页端代码,用于向安卓端推送消息

<!--@http://www.cnblogs.com/zhuweisky/p/3930780.html--><!DOCTYPE html></html>    <head>        <meta charset="utf-8">    </head>    <body>        <h3>WebSocketTest</h3>        <div id="login">            <div>                <input id="serverIP" type="text" placeholder="服务器IP" value="127.0.0.1" autofocus="autofocus" />                <input id="serverPort" type="text" placeholder="服务器端口" value="9000" />                <input id="btnConnect" type="button" value="连接" onclick="connect()" />            </div>            <div>                <input id="sendText" type="text" placeholder="发送文本" value="I'm WebSocket Client!" />                <input id="btnSend" type="button" value="发送" onclick="send()" />            </div>            <div>                <div>                    来自服务端的消息                </div>                <textarea id="txtContent" cols="50" rows="10" readonly="readonly"></textarea>            </div>        </div>    </body>    <script>        var socket;        function connect() {            var host = "ws://" + $("serverIP").value + ":" + $("serverPort").value + "/"            socket = new WebSocket(host);            try {                socket.onopen = function (msg) {                    $("btnConnect").disabled = true;                    alert("连接成功!");                };                socket.onmessage = function (msg) {                    if (typeof msg.data == "string") {                        displayContent(msg.data);                    }                    else {                        alert("非文本消息");                    }                };                socket.onclose = function (msg) { alert("socket closed!") };            }            catch (ex) {                log(ex);            }        }        function send() {            var msg = $("sendText").value            socket.send(msg);        }        window.onbeforeunload = function () {            try {                socket.close();                socket = null;            }            catch (ex) {            }        };        function $(id) { return document.getElementById(id); }        Date.prototype.Format = function (fmt) { //author: meizz             var o = {                "M+": this.getMonth() + 1, //月份                 "d+": this.getDate(), //日                 "h+": this.getHours(), //小时                 "m+": this.getMinutes(), //分                 "s+": this.getSeconds(), //秒                 "q+": Math.floor((this.getMonth() + 3) / 3), //季度                 "S": this.getMilliseconds() //毫秒             };            if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));            for (var k in o)                if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));            return fmt;        }        function displayContent(msg) {            $("txtContent").value += "\r\n" +new Date().Format("yyyy/MM/dd hh:mm:ss")+ ":  " + msg;        }        function onkey(event) { if (event.keyCode == 13) { send(); } }    </script></html>

安卓端实现

WebSocketClient地址 https://github.com/TooTallNate/Java-WebSocket

导入步骤

  1. 在gradle的repository中添加

    mavenCentral()

  2. 在build中添加

    compile “org.java-websocket:Java-WebSocket:1.3.4”

3.运行gradle同步

利用WebSocket自己手搓一个工具类,放到Service中启动

package com.halfopen.h.cislsign;import android.util.Log;import org.java_websocket.client.WebSocketClient;import org.java_websocket.handshake.ServerHandshake;import java.net.URI;import java.net.URISyntaxException;import static cn.jpush.android.api.JPushInterface.a.s;/** * Created by h on 2017/7/23. */public class MyWebSocketClient {    //WebSocketClient 和 address    private WebSocketClient mWebSocketClient;    private String address = "ws://10.222.108.43:9000";//初始化WebSocketClient    /**     *     * @throws URISyntaxException     */    private void initSocketClient() throws URISyntaxException {        if(mWebSocketClient == null) {            mWebSocketClient = new WebSocketClient(new URI(address)) {                @Override                public void onOpen(ServerHandshake serverHandshake) {                    Log.d("flag--","onOpen(WebSocketClient.java:32)-->>"+"成功建立websocket连接");                }                @Override                public void onMessage(String s) {                    //服务端消息                    Log.d("flag--","onMessage(WebSocketClient.java:39)-->>"+"收到来自服务器的消息"+s);                }                @Override                public void onClose(int i, String s, boolean remote) {                    //连接断开,remote判定是客户端断开还是服务端断开                    Log.d("flag--","onClose(WebSocketClient.java:46)-->>"+"Connection closed by " + ( remote ? "remote peer" : "us" ) + ", info=" + s);                    closeConnect();                }                @Override                public void onError(Exception e) {                    Log.d("flag--","onError(WebSocketClient.java:53)-->>"+s);                }            };        }    }    //连接    private void connect() {        new Thread(){            @Override            public void run() {                mWebSocketClient.connect();            }        }.start();    }    //断开连接    private void closeConnect() {        try {            mWebSocketClient.close();        }        catch(Exception e) {            e.printStackTrace();        }        finally {            mWebSocketClient = null;        }    }    /**     *发送消息     */    private void sendMsg(String msg) {        mWebSocketClient.send(msg);    }    //    public void start(){        try {            initSocketClient();            connect();        } catch (URISyntaxException e) {            e.printStackTrace();        }    }}

注意:安卓客户端要和websocekt服务器互通,并且地址和端口要向对应。

这里写图片描述

这里写图片描述

这里写图片描述

参考链接

https://www.zhihu.com/question/20215561
http://blog.csdn.net/icechenbing/article/details/7407588