netty-socketio 概述
netty-socketio是一個開源的Socket.io服務器端的一個java的實現,它基於Netty框架,可用於服務端推送消息給客戶端。javascript
說到服務端推送技術,通常會涉及WebSocket,WebSocket是HTML5最新提出的規範,雖然主流瀏覽器都已經支持,但仍然可能有不兼容的狀況,爲了兼容全部瀏覽器,給程序員提供一致的編程體驗,SocketIO將WebSocket、AJAX和其它的通訊方式所有封裝成了統一的通訊接口,也就是說,使用SocketIO時不用擔憂兼容問題,底層會自動選用最佳的通訊方式。css
netty-socketio 框架事件流程
netty-socketio 示例demo
pom.xmlhtml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.corundumstudio.socketio</groupId> <artifactId>netty-socketio</artifactId> <version>1.7.17</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.4</version> <scope>provided</scope> </dependency> </dependencies>
啓動類 NettySocketioApplication前端
@SpringBootApplication @Slf4j public class NettySocketioApplication implements CommandLineRunner { public static void main(String[] args) { SpringApplication.run(NettySocketioApplication.class, args); } @Autowired private SocketIOServer socketIOServer; @Override public void run(String... strings) { socketIOServer.start(); log.info("socket.io啓動成功!"); } }
Messagejava
@Data public class Message { private String msg; }
配置類 NettySocketioConfig程序員
@Configuration public class NettySocketioConfig { /** * netty-socketio服務器 */ @Bean public SocketIOServer socketIOServer() { com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration(); config.setHostname("localhost"); config.setPort(9092); SocketIOServer server = new SocketIOServer(config); return server; } /** * 用於掃描netty-socketio的註解,好比 @OnConnect、@OnEvent */ @Bean public SpringAnnotationScanner springAnnotationScanner() { return new SpringAnnotationScanner(socketIOServer()); } }
消息處理器 MessageEventHandlerweb
@Component @Slf4j public class MessageEventHandler { @Autowired private SocketIOServer socketIoServer; public static ConcurrentMap<String, SocketIOClient> socketIOClientMap = new ConcurrentHashMap<>(); /** * 客戶端鏈接的時候觸發 * * @param client */ @OnConnect public void onConnect(SocketIOClient client) { String mac = client.getHandshakeData().getSingleUrlParam("mac"); //存儲SocketIOClient,用於發送消息 socketIOClientMap.put(mac, client); //回發消息 client.sendEvent("message", "onConnect back"); log.info("客戶端:" + client.getSessionId() + "已鏈接,mac=" + mac); } /** * 客戶端關閉鏈接時觸發 * * @param client */ @OnDisconnect public void onDisconnect(SocketIOClient client) { log.info("客戶端:" + client.getSessionId() + "斷開鏈接"); } /** * 客戶端事件 * * @param client 客戶端信息 * @param request 請求信息 * @param data 客戶端發送數據 */ @OnEvent(value = "messageevent") public void onEvent(SocketIOClient client, AckRequest request, Message data) { log.info("發來消息:" + data); //回發消息 client.sendEvent("messageevent", "我是服務器都安發送的信息"); //廣播消息 sendBroadcast(); } /** * 廣播消息 */ public void sendBroadcast() { for (SocketIOClient client : socketIOClientMap.values()) { if (client.isChannelOpen()) { client.sendEvent("Broadcast", "當前時間", System.currentTimeMillis()); } } } }
html 頁面spring
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no"> <title>websocket-java-socketio</title> <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script> </head> <body> <h1>Socket.io Test</h1> <div><p id="status">Waiting for input</p></div> <div><p id="message">hello world!</p></div> <button id="connect" onClick='connect()'/>Connect</button> <button id="disconnect" onClick='disconnect()'>Disconnect</button> <button id="send" onClick='send()'/>Send Message</button> </body> <script type="text/javascript"> /** * 前端js的 socket.emit("事件名","參數數據")方法,是觸發後端自定義消息事件的時候使用的, * 前端js的 socket.on("事件名",匿名函數(服務器向客戶端發送的數據))爲監聽服務器端的事件 **/ var socket = io.connect("http://localhost:9092?mac=2"); var firstconnect = true; function connect() { if(firstconnect) { //socket.on('reconnect', function(){ status_update("Reconnected to Server"); }); //socket.on('reconnecting', function( nextRetry ){ status_update("Reconnecting in " //+ nextRetry + " seconds"); }); //socket.on('reconnect_failed', function(){ message("Reconnect Failed"); }); //firstconnect = false; } else { socket.socket.reconnect(); } } //監聽服務器鏈接事件 socket.on('connect', function(){ status_update("Connected to Server"); }); //監聽服務器關閉服務事件 socket.on('disconnect', function(){ status_update("Disconnected from Server"); }); //監聽服務器端發送消息事件 socket.on('messageevent', function(data) { message(data) //console.log("服務器發送的消息是:"+data); }); //斷開鏈接 function disconnect() { socket.disconnect(); } function message(data) { document.getElementById('message').innerHTML = "Server says: " + data; } function status_update(txt){ document.getElementById('status').innerHTML = txt; } function esc(msg){ return msg.replace(/</g, '<').replace(/>/g, '>'); } //點擊發送消息觸發 function send() { console.log("點擊了發送消息,開始向服務器發送消息") var msg = "我很好的,是的."; socket.emit('messageevent', {msgContent: msg}); }; </script> </html>
執行輸出
運行 SpringBoot 服務器編程
> mvn spring-boot:run
點擊網頁按鈕後端