美文网首页
SpringBoot 整合 Netty 实现 WebSocket

SpringBoot 整合 Netty 实现 WebSocket

作者: 扮鬼之梦 | 来源:发表于2020-06-17 16:36 被阅读0次

服务端

引入Netty依赖

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.50.Final</version>
</dependency>

创建NettyServer

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

public class NettyServer {

    private final int port;

    public NettyServer(int port) {
        this.port = port;
    }

    public void start() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            ServerBootstrap sb = new ServerBootstrap();
            sb.option(ChannelOption.SO_BACKLOG, 1024);
            sb.group(group, bossGroup) // 绑定线程池
                    .channel(NioServerSocketChannel.class) // 指定使用的channel
                    .localAddress(this.port)// 绑定监听端口
                    .childHandler(new ChannelInitializer<SocketChannel>() { // 绑定客户端连接时候触发操作
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //websocket协议本身是基于http协议的,所以这边也要使用http解编码器
                            ch.pipeline().addLast(new HttpServerCodec());
                            //以块的方式来写的处理器
                            ch.pipeline().addLast(new ChunkedWriteHandler());
                            ch.pipeline().addLast(new HttpObjectAggregator(8192));
                            ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", "WebSocket", true, 65536 * 10));
                            ch.pipeline().addLast(new MyWebSocketHandler());//自定义消息处理类
                        }
                    });
            ChannelFuture cf = sb.bind().sync(); // 服务器异步创建绑定
            System.out.println(NettyServer.class + "已启动,正在监听: " + cf.channel().localAddress());
            cf.channel().closeFuture().sync(); // 关闭服务器通道
        } finally {
            group.shutdownGracefully().sync(); // 释放线程池资源
            bossGroup.shutdownGracefully().sync();
        }
    }
}

创建MyWebSocketHandler

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

public class MyWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("与客户端建立连接,通道开启!");
        //添加到channelGroup通道组
        MyChannelHandlerPool.channelGroup.add(ctx.channel());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("与客户端断开连接,通道关闭!");
        //从channelGroup通道组删除
        MyChannelHandlerPool.channelGroup.remove(ctx.channel());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
    //接收的消息
        System.out.println(String.format("收到客户端%s的数据:%s" ,ctx.channel().id(), msg.text()));

        // 单独发消息
        // sendMessage(ctx);
        // 群发消息
        sendAllMessage();
    }

    private void sendMessage(ChannelHandlerContext ctx){
        String message = "消息";
        ctx.writeAndFlush(new TextWebSocketFrame(message));
    }

    private void sendAllMessage(){
        String message = "我是服务器,这是群发消息";
        MyChannelHandlerPool.channelGroup.writeAndFlush(new TextWebSocketFrame(message));
    }

}

创建MyChannelHandlerPool

import io.netty.channel.ChannelId;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.util.concurrent.ConcurrentHashMap;

public class MyChannelHandlerPool {

    public MyChannelHandlerPool() {
    }

    //可以存储userId与ChannelId的映射表
    public static ConcurrentHashMap<String, ChannelId> channelIdMap = new ConcurrentHashMap<>();

    //channelGroup通道组
    public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

}

启动(在SpringBoot启动类中加入以下内容)

import com.gnl.tool.netty.NettyServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ToolApplication {

    public static void main(String[] args) {
        SpringApplication.run(ToolApplication.class, args);
    //在SpringBoot启动类中加入以下内容
        try {
            new NettyServer(8000).start();
        } catch (Exception e) {
            System.out.println("NettyServerError:" + e.getMessage());
        }
    }

}

客户端(微信小程序)

wxml

<view>接收的消息</view>
<textarea style="border: 1px solid black;" value="{{msg}}"></textarea>


<view>发送的消息</view>
<textarea style="border: 1px solid black;" bindinput='inputTitle'></textarea>
<button style="border: 1px solid violet;" bindtap='send'>发送消息</button>



<button style="border: 1px solid red;" bindtap='openWebSocket'>打开WebSocket连接</button>
<button style="border: 1px solid red;" bindtap='closeWebSocket'>关闭WebSocket连接</button>

js

Page({

  /**
   * 页面的初始数据
   */
  data: {

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },
  /**
   * 绑定参数
   */
  inputTitle: function(e){
    var _this = this;
    _this.setData({ title: e.detail.value })
  },

  /**
   * 发送信息
   */
  send: function(){
    var _this = this;
    wx.sendSocketMessage({ 
      data: _this.data.title ,
      success: (result) => {
        console.log(result)
      },
      fail: (result) => {
        console.log(result)
        wx.showToast({
          title: result.errMsg,
          icon:"none",
          duration:5000
        })
      },
    
    })
  },
  /**
   * 打开连接
   */
  openWebSocket: function(){
    //创建一个 WebSocket 连接
    wx.connectSocket({
      url: 'ws://10.8.51.124:8000/ws',
      success: (result) => {
        console.log(result)
      },
    })

    //监听 WebSocket 连接打开事件
    wx.onSocketOpen(function (result) {
      console.log(result)
    })

    //监听 WebSocket 错误事件
    wx.onSocketError(function (result) {
      console.log(result)
      wx.showToast({
        title: result.errMsg,
      })
    })

    //监听 WebSocket 接受到服务器的消息事件
    wx.onSocketMessage((result) => {
      console.log(result)
      this.setData({
        msg: result.data
      })
    })

    //监听 WebSocket 关闭事件
    wx.onSocketClose((result) => {
      console.log(result)
    })

  },
  /**
   * 关闭连接
   */
  closeWebSocket: function(){
    wx.closeSocket({
      success: (result) => {
        console.log(result)
      },
    })
  }
})

测试

1.点击打开WebSocket连接,服务端打印连接成功消息


2.在发送的消息框内输入hello world,点击发送消息,服务端接收到消息,同时群发消息给客户端


3.点击关闭WebSocket连接,服务端打印关闭连接成功消息同时关闭连接


相关文章

网友评论

      本文标题:SpringBoot 整合 Netty 实现 WebSocket

      本文链接:https://www.haomeiwen.com/subject/bsmsxktx.html