使用netty实现消息收发 整合SpringBoot

使用netty实现消息收发

引入websocket包编写客户端

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

<dependency>
    <groupId>org.java-websocket</groupId>
    <artifactId>Java-WebSocket</artifactId>
    <version>1.3.8</version>
</dependency>

服务端启动类

package com.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class NettyServer {
    public static void main(String[] args) throws Exception{
        EventLoopGroup master= new NioEventLoopGroup();
        EventLoopGroup slaver= new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap =new ServerBootstrap();
            serverBootstrap.group(master,slaver)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ServerInitializer());
            ChannelFuture channelFuture= serverBootstrap.bind(8088).sync();
            channelFuture.channel().closeFuture().sync();
        }finally {
            // 关闭线程
            master.shutdownGracefully();
            slaver.shutdownGracefully();
        }

    }
}

初始化服务端

package com.netty;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
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 ServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline =socketChannel.pipeline();

        pipeline.addLast("HttpServerCodec",new HttpServerCodec());
        pipeline.addLast(new ChunkedWriteHandler());
        pipeline.addLast(new HttpObjectAggregator(1024*64));
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));

        pipeline.addLast(new CustomHandler());
    }
}

服务端消息处理助手

package com.netty;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.time.LocalDateTime;

public class CustomHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    private static ChannelGroup clients=new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        String content =textWebSocketFrame.text();
        System.out.println("接收到的数据:"+ content);
        // 推送消息到所有客户端
        for(Channel channel:clients){
            channel.writeAndFlush(new TextWebSocketFrame("服务器在"+LocalDateTime.now()+"收到消息"+"'"+content+"'"));
        }
    }

    // 客户端连接之后获取客户端channel并放入group中管理
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        clients.add( ctx.channel());
    }

    // 移除对应客户端的channel
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // 长短id
        System.out.println(ctx.channel().id().asLongText());
        System.out.println(ctx.channel().id().asShortText());
        clients.remove(ctx.channel());
    }
}

客户端用于测试

package com.netty;

import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Scanner;

public class WebsocketClient {

    public static WebSocketClient client;
    public static void main(String[] args) {
        try {
            client = new WebSocketClient(new URI("ws://localhost:8088/ws"),new Draft_6455()) {
                @Override
                public void onOpen(ServerHandshake serverHandshake) {
                    System.out.println(("握手成功"));
                }

                @Override
                public void onMessage(String msg) {
                    System.out.println(("客户端收到消息:"+msg));
                }

                @Override
                public void onClose(int i, String s, boolean b) {
                    System.out.println("链接已关闭");
                }

                @Override
                public void onError(Exception e){
                    e.printStackTrace();
                    System.out.println(("发生错误已关闭"));
                }
            };
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

        client.connect();
        while(!client.getReadyState().equals(WebSocket.READYSTATE.OPEN)){
            System.out.println(("正在连接..."));
        }
        while (true){
            Scanner sc = new Scanner(System.in);
            String x = sc.nextLine();
            //连接成功,发送信息
            client.send(x);
        }
    }
}

先启动服务端在启动客户端
在这里插入图片描述
客户端连接上了,发一条消息试试。
服务端收到了消息
在这里插入图片描述
服务端回复了消息。
在这里插入图片描述
多启动几个客户端,可以发现服务端在收到消息后会向所有客户端推送相同的消息。

springboot整合netty

修改之前的服务端启动类

package com.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class NettyServer {

    private static class SingletionNettyServer {
        static  final NettyServer instance=new NettyServer();
    }

    public static NettyServer getInstance(){
        return  SingletionNettyServer.instance;
    }
    private EventLoopGroup master;
    private EventLoopGroup slaver;
    private ServerBootstrap serverBootstrap;
    private ChannelFuture channelFuture;

    public NettyServer(){
        master= new NioEventLoopGroup();
        slaver= new NioEventLoopGroup();
        serverBootstrap =new ServerBootstrap();
        serverBootstrap.group(master,slaver)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ServerInitializer());
    }

    public void start(){
        this.channelFuture= serverBootstrap.bind(8088);
        System.err.println("netty 启动完毕");
    }
}

新建一个组件让springboot帮我们启动netty

package com.netty;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component
public class NettyBooter implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        if(contextRefreshedEvent.getApplicationContext().getParent()==null){
            try {
                NettyServer.getInstance().start();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

完成这两步之后就可以启动springboot了。
在这里插入图片描述
启动客户端发一条消息,效果和之前也是一样的。
在这里插入图片描述
在这里插入图片描述

发布了70 篇原创文章 · 获赞 6 · 访问量 4075

猜你喜欢

转载自blog.csdn.net/weixin_43424932/article/details/105186068