赞
踩
前言:
1、使用netty-socketio搭建socketIo服务;
2、client连接socketIo服务时,保存下该client对象;
3、使用TestController,向指定client推送消息;
一、netty-socket.io版本;
- <dependency>
- <groupId>com.corundumstudio.socketio</groupId>
- <artifactId>netty-socketio</artifactId>
- <version>1.7.16</version>
- </dependency>
二、创建socketIoServer实例;
- /**
- * 创建socketIOServer实例
- * @return
- */
- @Bean
- public SocketIOServer socketIOServer() {
- com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
- config.setHostname(host);
- config.setPort(port);
- setAuthorizationListener(config);
- return new SocketIOServer(config);
- }
三、socketIo client连接校验说明;
设想是通过服务端颁发token给client页面,当client页面进行连接时,将服务端颁发的token传递回来。服务端通过client传递的一系列参数,取出服务端保存的token,与传递的token做验证。
本文未做上述逻辑校验,仅是将client传递的参数打印在控制台。
- /**
- * 设置socketio client连接时的安全校验
- * @param config
- */
- private void setAuthorizationListener(com.corundumstudio.socketio.Configuration config) {
- config.setAuthorizationListener(new AuthorizationListener() {
- @Override
- public boolean isAuthorized(HandshakeData data) {
-
- String userId = data.getSingleUrlParam("userId");
- String pageSign = data.getSingleUrlParam("pageSign");
- String token = data.getSingleUrlParam("token");
- System.out.println("userId:" + userId + ",pageSign:" + pageSign + ",token: " + token);
-
- return true;
- }
- });
- }

四、启用netty-socket.io注解功能;
只有打开了SpringAnnotationScanner,netty-socket.io的注解才会生效。
- /**
- * 开启netty socketio的注解功能
- * @param socketServer
- * @return
- */
- @Bean
- public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {
- return new SpringAnnotationScanner(socketServer);
- }
五、通过校验的client连接保存下来;
保存client的时候,标识是哪个用户在哪个页面发起的连接,以便后续给指定用户的指定页面发送消息。注意:未处理同一个用户同时在多个浏览器登录的情况(可将token作为连接标识的一部分)。
- @OnConnect
- public void onConnect(SocketIOClient client) {
- this.socketClientComponent.storeClientId(client);
- System.out.println("客户端连接:" + getParamsFromClient(client));
- }
六、client断开连接时,从已连接池中移除掉;
- @OnDisconnect
- public void onDisconnect(SocketIOClient client) {
- this.socketClientComponent.delClientId(client);
- System.out.println("客户端断开:" + getParamsFromClient(client));
- }
七、client保存说明;
有效client目前是根据userId+pageSign作为连接唯一标识,将client对象保存在本地缓存中。本地缓存有撑爆的可能,正确的做法应该是同一个用户在同一个浏览器登录中,不管在多少个页面下,使用的是同一个socket。根据不同eventName事件名称来区分不同页面。服务端通过socketIoClient的sessionId来获取到真实的socketIoClient对象(socketIOServer.getClient(client.getSessionId()))。
- /**
- * socketio client 操作组件
- * @author haishui211
- */
- @Component
- public class SocketClientComponent {
-
- private Map<String, SocketIOClient> clients = new HashMap<String, SocketIOClient>();
-
- /**
- * 保存socketio client 客户端
- * @param userId
- * @param client
- */
- public void storeClientId(SocketIOClient client) {
- clients.put(getKeyFromClient(client), client);
- }
-
- /**
- * 移除socketio client 客户端
- */
- public void delClientId(SocketIOClient client) {
- clients.remove(getKeyFromClient(client));
- }
-
- /**
- * 给指定client发送指定事件的数据
- * @param businessName
- * @param data
- */
- public void send(String userId, String pageSign, String businessName, Map<String, Object> data) {
- SocketIOClient client = clients.get(getKey(userId, pageSign));
- if(client != null) {
- client.sendEvent(businessName, data);
- }
- }
-
- private String getKeyFromClient(SocketIOClient client) {
- HandshakeData data = client.getHandshakeData();
- String userId = data.getSingleUrlParam("userId");
- String pageSign = data.getSingleUrlParam("pageSign");
- return getKey(userId, pageSign);
- }
-
- private String getKey(String userId, String pageSign) {
- return "userId:" + userId + ":pageSign:" + pageSign;
- }
- }

八、testController模拟消息发送;
- @RestController
- @RequestMapping("/test")
- public class TestController {
-
- @Autowired
- private SocketClientComponent socketClientComponent;
-
- @PostMapping("/push")
- public void push(@RequestBody Map<String, Object> data) {
- String eventName = (String) data.get("eventName");
- String userId = (String) data.get("userId");
- String pageSign = (String) data.get("pageSign");
- socketClientComponent.send(userId, pageSign, eventName, data);
- }
- }
九、页面客户端;
- 1、引用的Js;
- <script
- src="http://code.jquery.com/jquery-3.4.1.js"
- integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
- crossorigin="anonymous"></script>
- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
-
- 2、连接发起;
- var socket = io.connect('http://localhost:9999?userId=12311&pageSign=firstPage&token=1234');
-
- socket.on('connect', function() {
- output('<span class="connect-msg">成功连接到服务端!</span>');
- });
-
- socket.on('testEvent', function(data) {
- output(JSON.stringify(data));
- });
-
- socket.on('disconnect', function() {
- output('<span class="disconnect-msg">The client has disconnected!</span>');
- });

十、测试数据;
- {
- "hhhh":"1234",
- "eventName":"testEvent",
- "pageSign":"firstPage",
- "userId":"12311"
- }
结果:
十一、demo地址;
https://github.com/haishui211/springRep.git
项目名:nettySocketIoDemo001,html页面放在了static目录
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。