美文网首页java学习之路
spring boot 整合netty-socketio

spring boot 整合netty-socketio

作者: 唯有努力不欺人丶 | 来源:发表于2020-03-20 10:00 被阅读0次

其实这个文章写得没啥技术含量,而且网上教程很多。
但是还是觉得用自己的语言表述出来,以后再用也不用一行代码一行代码的写了,直接cv就行了。

1.导包
        <!-- netty socketio -->
        <dependency>
            <groupId>com.corundumstudio.socketio</groupId>
            <artifactId>netty-socketio</artifactId>
            <version>1.7.13</version>
        </dependency>
2.代码配置

这里需要两个配置类(我把socketio的配置信息都写在了类里而不是配置文件中)

  • 启动类
@Component
@Order(value=1)
public class MyCommandLineRunner implements CommandLineRunner {
    private final SocketIOServer server;


    @Autowired
    public MyCommandLineRunner(SocketIOServer server) {
        this.server = server;
    }


    @Override
    public void run(String... args) throws Exception {
        server.start();
    }
}
  • 事件处理类
    对于socket服务端来讲,其实事件就几个:
    • 客户端连接
    • 客户端断开
    • 客户端发来消息
    • 给客户端发消息

然后首先说连接断开发来消息,都是可以知道是哪个客户端的。我这里是设置socket连接的参数 params来分辨是谁的。这里可以用来存具体的用户信息,token啥的都可以。
最后给客户端发消息大体上分两种:一种给某一个客户端发消息,还有一种是给所有用户或者某一类用户发消息。其实处理是一样的,只不过如果是所有用户则遍历全部客户端。
然后我直接贴代码:

@Component
public class MessageEventHandler {

    @Autowired
    public static SocketIOServer socketIoServer;

    public static ConcurrentMap<String, SocketIOClient> socketIOClientMap = new ConcurrentHashMap<>();

    @OnConnect
    public void onConnect(SocketIOClient client) {
        String params = client.getHandshakeData().getSingleUrlParam("params");
        System.err.println(params + "已连接上");
        System.err.println(client.getRemoteAddress());
        System.err.println("客户端sessionid" + client.getSessionId());
        // 存储SocketIOClient,用于发送消息
        socketIOClientMap.put(params, client);

    }

    /**
     * 客户端断开连接
     * 
     * @param client
     */
    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        String params = client.getHandshakeData().getSingleUrlParam("params");
        System.err.println(params + "已断开");
        socketIOClientMap.remove(params);
    }

    /**
     * 客户端事件
     * 
     * @param client
     * @param request
     * @param data
     */
    @OnEvent(value = "messageevent")
    public void onEvent(SocketIOClient client, AckRequest request, String data) {

    }

    // 广播消息
    public static boolean sendMsg(String event, String message) {
        for (SocketIOClient client : socketIOClientMap.values()) {
            if (client.isChannelOpen()) {
                client.sendEvent(event, message);
            }
        }
        return true;
    }
}

如上,socket基本准备工作完成了,剩下的就是在启动类做一些具体的配置(这个配置可以用配置文件然后在代码中引用,但是我嫌麻烦,是直接在类中写的字面量,推荐配置文件吧)
socketio配置文件的基本配置:

# SocketIO配置
socketio:
    # SocketIO端口
    port: 9090
    # 连接数大小
    workCount: 100
    # 允许客户请求
    allowCustomRequests: true
    # 协议升级超时时间(毫秒),默认10秒,HTTP握手升级为ws协议超时时间
    upgradeTimeout: 10000
    # Ping消息超时时间(毫秒),默认60秒,这个时间间隔内没有接收到心跳消息就会发送超时事件
    pingTimeout: 60000
    # Ping消息间隔(毫秒),默认25秒。客户端向服务器发送一条心跳消息间隔
    pingInterval: 25000
    # 设置HTTP交互最大内容长度
    maxHttpContentLength: 1048576
    # 设置最大每帧处理数据的长度,防止他人利用大数据来攻击服务器
    maxFramePayloadLength: 1048576

我说了我是类中直接写的,然后在boot项目的启动类中加入启动代码:

    @Bean
    public SocketIOServer socketIOServer() {
        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
                //这里注意,这不能写localhost。
        config.setHostname("192.168.0.11");
        config.setPort(9090);
        config.setAuthorizationListener(new AuthorizationListener() {// 类似过滤器
            @Override
            public boolean isAuthorized(HandshakeData data) {
                //可以有逻辑,我这里没写
                return true;
            }
        });
        final SocketIOServer server = new SocketIOServer(config);
        return server;
    }

    @Bean
    public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {
        return new SpringAnnotationScanner(socketServer);
    }

最后附上一个前端测试页面(我也是在网上嫖的,都忘了是哪个帖子找到的了,在此感谢大佬):

<!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://192.168.0.11:9090?params=123");
  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('update', 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>

这篇笔记就到这里,如果稍微帮到你了记得点个喜欢点个关注,也祝大家工作顺顺利利,生活健健康康!

相关文章