WebSocket是HTML5出的协议,基于TCP。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
WebSocket协议之前,双工通信是通过多个http链接来实现,这导致了效率低下。WebSocket解决了这个问题。
有了websocket协议,服务器就可以主动给客户端发送消息,而不是要等客户端的轮询。
#-*- coding:utf8 -*-
import threading
import hashlib
import socket
import base64
global clients
clients = {}
#通知客户端
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,允许局域网其他计算机访问
网页端代码,用于向安卓端推送消息
html>
<head>
<meta charset="utf-8">
head>
<body>
<h3>WebSocketTesth3>
<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
导入步骤
在gradle的repository中添加
mavenCentral()
在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