当前位置:   article > 正文

SpringBoot + Netty-SocketIO在项目中实战详解

springboot使用netty-io

序言:因工作项目需要使用到推送功能,且与前端Socket.IO框架对接,因此使用了Netty-SocketIO。Netty-SocketIO顾名思义是基于Netty的SocketIO,底层是基于Netty。有关SocketIO的相关API与官网提供的NodeJS版本API相似,相关配置与Netty相关配置相似。以下代码在SpringBoot项目中书写,解释都在代码里,直接看代码吧。

  • netty-socketio maven依赖
  1. <dependency>
  2. <groupId>com.corundumstudio.socketio</groupId>
  3. <artifactId>netty-socketio</artifactId>
  4. <version>1.7.7</version>
  5. </dependency>
  • application.properties相关配置
  1. #============================================================================
  2. # netty socket io setting
  3. #============================================================================
  4. # host在本地测试可以设置为localhost或者本机IP,在Linux服务器跑可换成服务器IP
  5. socketio.host=localhost
  6. socketio.port=9099
  7. # 设置最大每帧处理数据的长度,防止他人利用大数据来攻击服务器
  8. socketio.maxFramePayloadLength=1048576
  9. # 设置http交互最大内容长度
  10. socketio.maxHttpContentLength=1048576
  11. # socket连接数大小(如只监听一个端口boss线程组为1即可)
  12. socketio.bossCount=1
  13. socketio.workCount=100
  14. socketio.allowCustomRequests=true
  15. # 协议升级超时时间(毫秒),默认10秒。HTTP握手升级为ws协议超时时间
  16. socketio.upgradeTimeout=1000000
  17. # Ping消息超时时间(毫秒),默认60秒,这个时间间隔内没有接收到心跳消息就会发送超时事件
  18. socketio.pingTimeout=6000000
  19. # Ping消息间隔(毫秒),默认25秒。客户端向服务器发送一条心跳消息间隔
  20. socketio.pingInterval=25000
  • SocketIOConfig.java配置文件相关配置
  1. import com.corundumstudio.socketio.SocketConfig;
  2. import org.springframework.beans.factory.annotation.Value;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import com.corundumstudio.socketio.SocketIOServer;
  6. @Configuration
  7. public class SocketIOConfig {
  8. @Value("${socketio.host}")
  9. private String host;
  10. @Value("${socketio.port}")
  11. private Integer port;
  12. @Value("${socketio.bossCount}")
  13. private int bossCount;
  14. @Value("${socketio.workCount}")
  15. private int workCount;
  16. @Value("${socketio.allowCustomRequests}")
  17. private boolean allowCustomRequests;
  18. @Value("${socketio.upgradeTimeout}")
  19. private int upgradeTimeout;
  20. @Value("${socketio.pingTimeout}")
  21. private int pingTimeout;
  22. @Value("${socketio.pingInterval}")
  23. private int pingInterval;
  24. /**
  25. * 以下配置在上面的application.properties中已经注明
  26. * @return
  27. */
  28. @Bean
  29. public SocketIOServer socketIOServer() {
  30. SocketConfig socketConfig = new SocketConfig();
  31. socketConfig.setTcpNoDelay(true);
  32. socketConfig.setSoLinger(0);
  33. com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
  34. config.setSocketConfig(socketConfig);
  35. config.setHostname(host);
  36. config.setPort(port);
  37. config.setBossThreads(bossCount);
  38. config.setWorkerThreads(workCount);
  39. config.setAllowCustomRequests(allowCustomRequests);
  40. config.setUpgradeTimeout(upgradeTimeout);
  41. config.setPingTimeout(pingTimeout);
  42. config.setPingInterval(pingInterval);
  43. return new SocketIOServer(config);
  44. }
  45. }

以下就是提供一个SocketIOService接口,供其他地方需要使用时调用。

  1. public interface SocketIOService {
  2. //推送的事件
  3. public static final String PUSH_EVENT = "push_event";
  4. // 启动服务
  5. void start() throws Exception;
  6. // 停止服务
  7. void stop();
  8. // 推送信息
  9. void pushMessageToUser(PushMessage pushMessage);
  10. }
  • SocketIOServiceImpl.java接口实现类
  1. import java.util.List;
  2. import java.util.Map;
  3. import java.util.concurrent.ConcurrentHashMap;
  4. import javax.annotation.PostConstruct;
  5. import javax.annotation.PreDestroy;
  6. import org.apache.commons.lang3.StringUtils;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.stereotype.Service;
  9. import com.corundumstudio.socketio.SocketIOClient;
  10. import com.corundumstudio.socketio.SocketIOServer;
  11. @Service(value = "socketIOService")
  12. public class SocketIOServiceImpl implements SocketIOService {
  13. // 用来存已连接的客户端
  14. private static Map<String, SocketIOClient> clientMap = new ConcurrentHashMap<>();
  15. @Autowired
  16. private SocketIOServer socketIOServer;
  17. /**
  18. * Spring IoC容器创建之后,在加载SocketIOServiceImpl Bean之后启动
  19. * @throws Exception
  20. */
  21. @PostConstruct
  22. private void autoStartup() throws Exception {
  23. start();
  24. }
  25. /**
  26. * Spring IoC容器在销毁SocketIOServiceImpl Bean之前关闭,避免重启项目服务端口占用问题
  27. * @throws Exception
  28. */
  29. @PreDestroy
  30. private void autoStop() throws Exception {
  31. stop();
  32. }
  33. @Override
  34. public void start() {
  35. // 监听客户端连接
  36. socketIOServer.addConnectListener(client -> {
  37. String loginUserNum = getParamsByClient(client);
  38. if (loginUserNum != null) {
  39. clientMap.put(loginUserNum, client);
  40. }
  41. });
  42. // 监听客户端断开连接
  43. socketIOServer.addDisconnectListener(client -> {
  44. String loginUserNum = getParamsByClient(client);
  45. if (loginUserNum != null) {
  46. clientMap.remove(loginUserNum);
  47. client.disconnect();
  48. }
  49. });
  50. // 处理自定义的事件,与连接监听类似
  51. socketIOServer.addEventListener(PUSH_EVENT, PushMessage.class, (client, data, ackSender) -> {
  52. // TODO do something
  53. });
  54. socketIOServer.start();
  55. }
  56. @Override
  57. public void stop() {
  58. if (socketIOServer != null) {
  59. socketIOServer.stop();
  60. socketIOServer = null;
  61. }
  62. }
  63. @Override
  64. public void pushMessageToUser(PushMessage pushMessage) {
  65. String loginUserNum = pushMessage.getLoginUserNum();
  66. if (StringUtils.isNotBlank(loginUserNum)) {
  67. SocketIOClient client = clientMap.get(loginUserNum);
  68. if (client != null)
  69. client.sendEvent(PUSH_EVENT, pushMessage);
  70. }
  71. }
  72. /**
  73. * 此方法为获取client连接中的参数,可根据需求更改
  74. * @param client
  75. * @return
  76. */
  77. private String getParamsByClient(SocketIOClient client) {
  78. // 从请求的连接中拿出参数(这里的loginUserNum必须是唯一标识)
  79. Map<String, List<String>> params = client.getHandshakeData().getUrlParams();
  80. List<String> list = params.get("loginUserNum");
  81. if (list != null && list.size() > 0) {
  82. return list.get(0);
  83. }
  84. return null;
  85. }
  86. }
  • 前端相关测试页面编写
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  5. <title>NETTY SOCKET.IO DEMO</title>
  6. <base>
  7. <script src="../static/js/jquery-1.11.1.min.js"></script>
  8. <script src="../static/js/socket.io.js"></script>
  9. <style>
  10. body {
  11. padding: 20px;
  12. }
  13. #console {
  14. height: 450px;
  15. overflow: auto;
  16. }
  17. .username-msg {
  18. color: orange;
  19. }
  20. .connect-msg {
  21. color: green;
  22. }
  23. .disconnect-msg {
  24. color: red;
  25. }
  26. </style>
  27. </head>
  28. <body>
  29. <div id="console" class="well"></div>
  30. </body>
  31. <script type="text/javascript">
  32. var socket;
  33. connect();
  34. function connect() {
  35. var loginUserNum = '88';
  36. var opts = {
  37. query: 'loginUserNum=' + loginUserNum
  38. };
  39. socket = io.connect('http://localhost:9099', opts);
  40. socket.on('connect', function () {
  41. console.log("连接成功");
  42. serverOutput('<span class="connect-msg">连接成功</span>');
  43. });
  44. socket.on('push_event', function (data) {
  45. output('<span class="username-msg">' + data + ' </span>');
  46. console.log(data);
  47. });
  48. socket.on('disconnect', function () {
  49. serverOutput('<span class="disconnect-msg">' + '已下线! </span>');
  50. });
  51. }
  52. function output(message) {
  53. var element = $("<div>" + " " + message + "</div>");
  54. $('#console').prepend(element);
  55. }
  56. function serverOutput(message) {
  57. var element = $("<div>" + message + "</div>");
  58. $('#console').prepend(element);
  59. }
  60. </script>
  61. </html>

到此,以上就是netty-socketio与SpringBoot项目整合以及使用。如有错误,谢谢指出。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/973975
推荐阅读
相关标签
  

闽ICP备14008679号