socket.io 在java與微信小程式上的應用
阿新 • • 發佈:2018-12-20
最近有一個這樣的功能場景。使用者操作完成後。伺服器主動通知另一個客戶端顯示結果。
這裡涉及一個伺服器推的這麼一個東西。需要實現這麼一個功能,對比了幾個實現方式。最終選擇了socket.io。
1、commet,最初想到這個功能要求不高,想簡單的通過commet方式實現就算了。但考慮到commet已經是比較老舊的做法了,其中有很多弊端,所以放棄了。
2、netty。netty是非常棒的java nio框架。但考慮到我需要實現的功能,有點殺雞用牛刀的感覺,而且要兼顧小程式的實現,選擇放棄
3、socket.io,非常適合。封裝了socket的特性,用法簡單。而且對不同語言的相容性很好。
廢話好說。直接看程式碼。
1、伺服器端,使用的是java語言。
首先新增jar支援,java上伺服器端用的是netty-socketio這個jar,是對netty做的二次封裝。
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.16</version>
</dependency>
java伺服器端的實現:
/* * 檔名:SocketIoServer.java 版權:Copyright by www.poly.com 描述: 修改人:gogym 修改時間:2018年10月23日 跟蹤單號: 修改單號: * 修改內容: */ import java.util.HashMap; import java.util.Map; import com.corundumstudio.socketio.AckCallback; import com.corundumstudio.socketio.AckRequest; import com.corundumstudio.socketio.AuthorizationListener; import com.corundumstudio.socketio.Configuration; import com.corundumstudio.socketio.HandshakeData; import com.corundumstudio.socketio.SocketIOClient; import com.corundumstudio.socketio.SocketIONamespace; import com.corundumstudio.socketio.SocketIOServer; import com.corundumstudio.socketio.listener.ConnectListener; import com.corundumstudio.socketio.listener.DataListener; import com.corundumstudio.socketio.listener.DisconnectListener; import com.corundumstudio.socketio.listener.PingListener; public class SocketIoServer { public static void main(String[] args) { // 啟動服務 SocketIoServer sio = new SocketIoServer(); sio.initSocket(); } // 儲存session與端對映關係 public Map<String, SocketIOClient> clientMap = new HashMap<String, SocketIOClient>(); /** * Description: 初始化 * * @see */ public void initSocket() { Configuration config = new Configuration(); // 一般不需要設定Hostname,設定localhost後,從其他IP連線會連不上來 // config.setHostname("localhost"); // 設定埠 config.setPort(10015); // 往伺服器寫ping訊息,用來檢測客戶端是否存活,如果設定時間內沒有ping通,則清理掉客戶端連線 config.setPingTimeout(3000); // ping間隔時長 config.setPingInterval(30000); // config.setBossThreads(5); // config.setWorkerThreads(15); config.setAuthorizationListener(new AuthorizationListener() { @Override public boolean isAuthorized(HandshakeData handshakedata) { // 這裡可以攔截連線過來的URL。可以獲取引數等。比如統一鑑權就可以在這裡處理 System.out.println(handshakedata.getUrl()); return true; } }); SocketIOServer server = new SocketIOServer(config); // 新增一個名稱空間,名稱空間可以用於區分不同的業務連線 SocketIONamespace namespace = server.addNamespace("/chat"); server.start(); } /** * Description: 新增監聽程式 * * @param namespace * @see */ public void addListener(SocketIONamespace namespace) { // 新增連線監聽 namespace.addConnectListener(new ConnectListener() { @Override public void onConnect(SocketIOClient client) { System.out.println(client.getRemoteAddress() + "連線上了"); // 把連線上的客戶端儲存起來 clientMap.put(client.getSessionId().toString(), client); } }); // 新增連線斷開監聽 namespace.addDisconnectListener(new DisconnectListener() { @Override public void onDisconnect(SocketIOClient client) { System.out.println(client.getRemoteAddress() + "離開了"); clientMap.remove(client.getSessionId().toString()); } }); // 新增ping監聽 namespace.addPingListener(new PingListener() { @Override public void onPing(SocketIOClient socketioclient) { // 往客戶端寫ping訊息,用來檢測客戶端是否存活 System.out.println("ping:" + socketioclient.getRemoteAddress()); } }); // 新增自定義監聽,例如:使用者註冊 namespace.addEventListener("register_event", String.class, new DataListener<String>() { @Override public void onData(SocketIOClient client, String str, AckRequest ack) throws Exception { // 傳送ack給客戶端告知伺服器端已經收到訊息 ack.sendAckData("ok"); } }); } public void sendMsg(String sessionId, String msg) { // 通過sessionid獲取socket連線 SocketIOClient client = clientMap.get(sessionId); // 發條訊息給客戶端。客戶端監聽的是message client.sendEvent("message", new AckCallback<Object>(Object.class, 5 /* 注意這裡的單位是秒 */) { @Override public void onSuccess(Object result) { // 接收客戶端返回的ack。意味著客戶端已經接收到訊息了 System.out.println("ack from client: " + client.getSessionId() + " data: " + result); } @Override public void onTimeout() { System.out.println("ACK超時"); } }, msg); } }
JAVA客戶端的實現
/* * 檔名:SocketIoClient.java 版權:Copyright by www.poly.com 描述: 修改人:gogym 修改時間:2018年10月23日 跟蹤單號: 修改單號: * 修改內容: */ package com.poly.rbl.plugin.socketio; import io.socket.client.Ack; import io.socket.client.IO; import io.socket.client.Socket; import io.socket.emitter.Emitter; import com.poly.rbl.utils.DateTimeUtil; public class SocketIoClient { public static void main(String[] args) { IO.Options options = new IO.Options(); // 設定協議為websocket options.transports = new String[] {"websocket"}; // 失敗重連次數 options.reconnectionAttempts = 5; // 失敗重連的時間間隔 options.reconnectionDelay = 3000; // 連線超時時間(ms) options.timeout = 3000; // 開啟重連 options.reconnection = true; // 可以攜帶一些連線引數 // options.query="token=1234"; try { final Socket socket = IO.socket("http://app.52rbl.com:8004/delivery", options); // 連線伺服器 socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() { @Override public void call(Object... args) { System.out.println(DateTimeUtil.getCurrentTime() + ":client connect! "); // 連線成功,馬上向伺服器傳送資訊,例如:使用者註冊 socket.emit("register_event", "發給伺服器的訊息", new Ack() { @Override public void call(Object... aobj) { System.out.println(aobj[0]); } }); } }); // 監聽斷線 socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() { @Override public void call(Object... args) { System.out.println(DateTimeUtil.getCurrentTime() + ":client disconnect!"); } }); // 監聽ping,其實這個監聽沒有多少意義 socket.on(Socket.EVENT_PING, new Emitter.Listener() { @Override public void call(Object... arg0) { // 往伺服器寫ping System.out.println("ping:" + arg0); } }); // 監聽pong,這個監聽沒有多少意義 socket.on(Socket.EVENT_PONG, new Emitter.Listener() { @Override public void call(Object... arg0) { // ping了以後接收伺服器的pong響應 System.out.println("pong:" + arg0[0]); } }); // 監聽伺服器傳送的訊息,也可以自定義一個簡單字串 socket.on(Socket.EVENT_MESSAGE, new Emitter.Listener() { @Override public void call(Object... args) { // 接收訊息後,往伺服器傳送一個ack,告訴伺服器訊息收到了 Ack ack = (Ack)args[args.length - 1]; ack.call(args[0].hashCode()); for (Object obj : args) { System.out.println(DateTimeUtil.getCurrentTime() + ":receive server message=" + obj.toString()); } } }); // 連線伺服器 socket.connect(); } catch (Exception e) { e.printStackTrace(); } } }
var socket = io('http://192.168.1.11:8003/', {
transports: ['websocket']
});
//連線監聽
socket.on('connect', () => {
console.log("成功")
//向伺服器傳送註冊資訊
socket.emit('register_event', params, (data) => {
console.log(data)
});
})
socket.on('connect_error', d => {
console.log("connect_error")
})
socket.on('connect_timeout', d => {
console.log("connect_timeout")
})
socket.on('disconnect', reason => {
console.log("disconnect")
})
socket.on('reconnect', attemptNumber => {
console.log("reconnect")
})
socket.on('reconnect_attempt', () => {
socket.io.opts.transports = ['polling', 'websocket'];
});
//監聽訊息
socket.on('message', (data,cb) => {
console.log(data);
//返回ACK給伺服器
cb("ok")
});
完