netty-socketio 概述
netty-socketio是一個開源的Socket.io服務器端的一個java的實現,它基於Netty框架,可用於服務端推送消息給客戶端。
說到服務端推送技術,一般會涉及WebSocket,WebSocket是HTML5最新提出的規范,雖然主流瀏覽器都已經支持,但仍然可能有不兼容的情況,為了兼容所有瀏覽器,給程序員提供一致的編程體驗,SocketIO將WebSocket、AJAX和其它的通信方式全部封裝成了統一的通信接口,也就是說,使用SocketIO時不用擔心兼容問題,底層會自動選用最佳的通信方式。
netty-socketio 框架事件流程

netty-socketio 示例demo
pom.xml
<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啟動成功!");
}
}
Message
@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());
}
}
消息處理器 MessageEventHandler
@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 頁面
<!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
點擊網頁按鈕

