Netty+UDP+Java,与spring集成,client+server

1.maven中引入依赖包:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>h3c</groupId>
    <artifactId>UdpClient</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <springboot.version>2.0.5.RELEASE</springboot.version>
        <swagger.version>2.7.0</swagger.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.31.Final</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.4</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <!-- 当运行“mvn package”进行打包时,会打包成一个可以直接运行的 JAR 文件,使用“java -jar”命令就可以直接运行-。 -->
                <!-- 打的包里面才会有maven依赖的jar包和spring boot的启动类(独立启动) -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.5</version>
                <configuration>
                    <skipTests>true</skipTests>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2.server端编写:

2.1 NettyUdpServer:


import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

/**
 * description:
 * author:
 * date: 2018-11-28 12:07
 **/
@Component
public class NettyUdpServer {

    private static final Logger log = LoggerFactory.getLogger(NettyUdpServer.class);

    private static final EventLoopGroup group = new NioEventLoopGroup(1);

    @Autowired
    ServerChannelInitializer serverChannelInitializer;

    @Value("${port}")
    private int port;

    //监听端口的通道,即server的处理通道
    private Channel channel;

    /**
     * 开启udp server服务
     *
     * @return
     */
    public ChannelFuture start() {
        //启动类
        Bootstrap serverBootstrap = new Bootstrap();
        serverBootstrap.group(group)//组配置,初始化ServerBootstrap的线程组
                .channel(NioDatagramChannel.class)//数据包通道,udp通道类型
                .option(ChannelOption.SO_BROADCAST, true)//支持广播
                .handler(serverChannelInitializer);//通道处理者
        //Future:异步任务的生命周期,可用来获取任务结果
        ChannelFuture channelFuture1 = serverBootstrap.bind(port).syncUninterruptibly();//绑定端口,开启监听,同步等待
        if (channelFuture1 != null && channelFuture1.isSuccess()) {
            log.info("[UDP] server start success, port = {}", port);
            channel = channelFuture1.channel();//获取通道
        } else {
            log.error("udp server start failed!!");
            channelFuture1.cause().printStackTrace();
        }
        return channelFuture1;
    }

    /**
     * 停止udp server服务
     * 销毁前的拦截
     */
    @PreDestroy
    public void destroy() {
        try {
            if (channel != null) {
                ChannelFuture await = channel.close().await();
                if (!await.isSuccess()) {
                    log.error("udp channel close fail, {}", await.cause());
                }
            }
            Future<?> future1 = group.shutdownGracefully().await();
            if (!future1.isSuccess()) {
                log.error("udp group shutdown fail, {}", future1.cause());
            }
            log.info("udp shutdown success");
        } catch (InterruptedException e) {
            log.info("udp shutdown fail");
            e.printStackTrace();
        }
    }

}

2.2 ServerChannelInitializer:



import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * description: 通道初始化,主要用于设置各种Handler
 * author:
 * date: 2018-11-28 14:55
 **/
@Component
public class ServerChannelInitializer extends ChannelInitializer<NioDatagramChannel> {

    @Autowired
    ServerChannelInboundHandler serverChannelHandler;

    @Override
    protected void initChannel(NioDatagramChannel nioDatagramChannel) throws Exception {
        ChannelPipeline pipeline = nioDatagramChannel.pipeline();
//        pipeline.addLast(new StringDecoder());
        //自定义的InboundHandler输入处理者
        pipeline.addLast("serverChannelHandler", serverChannelHandler);
//        pipeline.addLast(new StringEncoder());
    }
}

2.3 ServerChannelInboundHandler:


import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * description: 通道数据输入的处理
 * author:
 * date: 2018-11-28 15:49
 **/
@Component
@ChannelHandler.Sharable
@Slf4j
public class ServerChannelInboundHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramPacket datagramPacket) throws Exception {
        System.out.println("[UDP] server 收到的消息:" + datagramPacket.content().toString(CharsetUtil.UTF_8));
        String response = "{" + datagramPacket.content().toString(CharsetUtil.UTF_8) + "}的响应,我是服务端啊!!!";
        DatagramPacket datagramPacket1 = new DatagramPacket(Unpooled.copiedBuffer(response, CharsetUtil.UTF_8), datagramPacket.sender());
        channelHandlerContext.channel().writeAndFlush(datagramPacket1);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
    }

}

3.client端的编写

3.1 NettyUdpClient:


import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * description:
 * author: yangzihe
 * date: 2018-12-28 13:59
 **/
@Component
public class NettyUdpClient {

    private static final Logger log = LoggerFactory.getLogger(NettyUdpClient.class);

    @Value("${host}")
    private String HOST;
    @Value("${port}")
    private int PORT;

    @Autowired
    ClientChannelInitializer clientChannelInitializer;

    //与服务端建立连接后得到的通道对象
    private Channel channel;

    /**
     * 初始化 `Bootstrap` 客户端引导程序
     *
     * @return
     */
    private final Bootstrap getBootstrap() {
        Bootstrap b = new Bootstrap();
        EventLoopGroup group = new NioEventLoopGroup();
        b.group(group)
                .channel(NioDatagramChannel.class)//数据包通道,udp通道类型
                .handler(clientChannelInitializer)//通道处理者
                .option(ChannelOption.SO_BROADCAST, true);//开启广播
        return b;
    }

    /**
     * 建立连接,获取连接通道对象
     *
     * @return
     */
    public void connect() {
        ChannelFuture channelFuture = getBootstrap().connect(HOST, PORT).syncUninterruptibly();
        if (channelFuture != null && channelFuture.isSuccess()) {
            log.warn("udp client connect host = {}, port = {} success", HOST, PORT);
            channel = channelFuture.channel();
        } else {
            log.error("udp client connect host = {}, port = {} failed!", HOST, PORT);
        }
    }

    /**
     * 向服务器发送消息
     *
     * @param msg
     * @throws Exception
     */
    public void sendMsg(Object msg) {
        if (channel != null) {
            channel.writeAndFlush(msg);
        } else {
            log.warn("消息发送失败,连接尚未建立!");
        }
    }

}



3.2 ClientChannelInitializer:


import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * description: 通道初始化,主要用于设置各种Handler
 * author:
 * date: 2018-11-28 14:55
 **/
@Component
public class ClientChannelInitializer extends ChannelInitializer<NioDatagramChannel> {

    @Autowired
    ClientChannelHandler clientChannelHandler;


    @Override
    protected void initChannel(NioDatagramChannel nioDatagramChannel) throws Exception {
        ChannelPipeline pipeline = nioDatagramChannel.pipeline();
        //数据的解码
//        pipeline.addLast(new StringDecoder());
        //自定义Handler
        pipeline.addLast("clientChannelHandler", clientChannelHandler);
        //数据的编码
//        pipeline.addLast(new StringEncoder());

    }
}

3.3 ClientChannelHandler:


import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.SocketUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import h3c.utils.HexUtil;

import java.nio.charset.Charset;

/**
 * description:
 * author: yangzihe
 * date: 2018-12-28 14:06
 **/
@Component
@ChannelHandler.Sharable
@Slf4j
public class ClientChannelHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    @Value("${host}")
    private String HOST;
    @Value("${port}")
    private int PORT;

    /**
     * 通道建立成功后
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //当channel就绪后
        log.info("[UDP] client channel is ready!");
        String s = "客户端连接成功后发送的第一条消息!";
        DatagramPacket datagramPacket = new DatagramPacket(Unpooled.copiedBuffer(s, CharsetUtil.UTF_8), SocketUtils.socketAddress(HOST, PORT));
        ctx.channel().writeAndFlush(datagramPacket);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramPacket datagramPacket) throws Exception {
        System.out.println("[UDP] client 收到的消息:" + datagramPacket.content().toString(CharsetUtil.UTF_8));
    }
}

4.配置文件application.properties:

server.port=8090

host=127.0.0.1
port=4005

5.启动类SpringBootApplication:


import h3c.tcp.server.NettyUdpServer;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.SocketUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import h3c.tcp.client.NettyUdpClient;

/**
 * ClassName: SpringBootApplication
 * description:
 * author: yangzihe
 * date: 2018-09-30 09:15
 **/
@org.springframework.boot.autoconfigure.SpringBootApplication//@EnableAutoConfiguration @ComponentScan
public class SpringBootApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootApplication.class, args);
    }

    @Autowired
    NettyUdpServer nettyTcpServer;
    @Autowired
    NettyUdpClient nettyTcpClient;
    @Value("${host}")
    private String HOST;
    @Value("${port}")
    private int PORT;

    @Override
    public void run(String... args) throws Exception {
        //启动服务端
        ChannelFuture start = nettyTcpServer.start();
        //启动客户端,发送数据
        nettyTcpClient.connect();
        String s = "客户端send";
        DatagramPacket datagramPacket = new DatagramPacket(Unpooled.copiedBuffer(s, CharsetUtil.UTF_8), SocketUtils.socketAddress(HOST, PORT));
        nettyTcpClient.sendMsg(datagramPacket);

        //服务端管道关闭的监听器并同步阻塞,直到channel关闭,线程才会往下执行,结束进程
        start.channel().closeFuture().syncUninterruptibly();
    }
}

运行SpringBootApplication,结果:

猜你喜欢

转载自blog.csdn.net/yzh_1346983557/article/details/88707947