Springboot整合Netty,实现Socket通信

Springboot整合Netty,实现Socket通信

1.模拟单客户端

引入Netty依赖:

当前Springboot版本为:2.5.1

<!--Netty网络通信框架依赖(不用声明版本号,因为 spring-boot-dependencies 中已经声明了最新的Netty依赖)-->
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
</dependency>

SocketChannelInitializer.java:

package com.kd.opt.socket;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

/**
 * Springboot整合Netty,实现Socket信息交互(本项目用于与C语言程序进行交互)
 *
 * 设置出站和入站的编码器和解码器(该方法在SocketClientConfig.java中被重写)
 *
 * 客户端
 *
 * @author 小辰哥哥
 */

public class SocketChannelInitializer extends ChannelInitializer<SocketChannel> {
    protected void initChannel(SocketChannel channel) throws Exception {
        ChannelPipeline p = channel.pipeline();
        p.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
        p.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
        p.addLast(new SocketHandler());
    }
}

SocketHandler.java:

package com.kd.opt.socket;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Springboot整合Netty,实现Socket信息交互(本项目用于与C语言程序进行交互)
 *
 * 初始化操作、接受服务端发送过来的消息(该方法在SocketClient.java中被重写)
 *
 * 客户端
 *
 * @author 小辰哥哥
 */

public class SocketHandler extends ChannelInboundHandlerAdapter {

    // 日志打印
    private static final Logger LOGGER = LoggerFactory.getLogger(SocketHandler.class);

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        LOGGER.debug("SocketHandler Active(客户端)");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        LOGGER.debug("####接收服务端发送过来的消息####");
        LOGGER.debug("SocketHandler read Message:" + msg);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        LOGGER.debug("####客户端断开连接####");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

SocketClient.java:

package com.kd.opt.socket;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Springboot整合Netty,实现Socket信息交互(本项目用于与C语言程序进行交互)
 * 
 * 核心文件(与服务端进行数据交互)
 * 
 * 客户端
 *
 * @author 小辰哥哥
 */
public class SocketClient {
    // 服务端IP
    static final String HOST = System.getProperty("host", "127.0.0.1");

    // 服务端开放端口
    static final int PORT = Integer.parseInt(System.getProperty("port", "5555"));

    // 数据包大小
    static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));

    // 日志打印
    private static final Logger LOGGER = LoggerFactory.getLogger(SocketClient.class);

    // 主函数启动
    public static void main(String[] args) throws InterruptedException {
        sendMessage("Hello World");
    }

    /**
     * 核心方法(处理:服务端向客户端发送的数据、客户端向服务端发送的数据)
     *
     * @param content
     * @throws InterruptedException
     * @author 小辰哥哥
     */
    public static void sendMessage(String content) throws InterruptedException {
        // Configure the client.
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                            p.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
                            p.addLast(new SocketHandler() {
                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) {
                                    LOGGER.debug("####接收服务端发送过来的消息####");
                                    LOGGER.debug("服务端发送过来的数据:" + msg);

                                    // 主动与服务端断开连接(客户端触发)
                                    ctx.channel().close();
                                }
                            });
                        }
                    });

            ChannelFuture future = b.connect(HOST, PORT).sync();
            future.channel().writeAndFlush(content);

            // 程序阻塞
            future.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }

}

使用sokit软件(充当服务端)开始测试:
在这里插入图片描述
点击TCP侦听:
在这里插入图片描述
在这里插入图片描述
主函数启动程序:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
服务端发送消息,然后客户端主动断开连接:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
服务端主动断开连接:
在这里插入图片描述
在这里插入图片描述

2.模拟单服务端

yml相关配置:

# 配置Netty通信IP和端口
netty:
  port: 5555
  url: 127.0.0.1

NettyChannelInitializer.java:

package com.kd.opt.socket;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

/**
 * Springboot整合Netty,实现Socket信息交互(本项目用于与C语言程序进行交互)
 *
 * 设置出站和入站的编码器和解码器
 *
 * 服务端
 *
 * @author 小辰哥哥
 */
public class NettyChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel channel) throws Exception {
        channel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
        channel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
        channel.pipeline().addLast(new NettyHandler());
    }
}

NettyHandler.java:

package com.kd.opt.socket;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.SocketAddress;

/**
 * Springboot整合Netty,实现Socket信息交互(本项目用于与C语言程序进行交互)
 *
 * 初始化操作、处理客户端与服务端相关消息
 *
 * 服务端
 *
 * @author 小辰哥哥
 */
public class NettyHandler extends ChannelInboundHandlerAdapter {

    public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    // 日志打印
    private static final Logger LOGGER = LoggerFactory.getLogger(NettyHandler.class);

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        LOGGER.debug("SocketHandler Active(服务端)");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        // 客户端向服务端发送数据(获取客户端IP和端口、相关数据)
        SocketAddress socketAddress = ctx.channel().remoteAddress();

        LOGGER.debug("####接收客户端发送过来的消息####");
        LOGGER.debug("获取IP和端口:" + socketAddress);
        LOGGER.debug("SocketHandler read Message:" + msg);

        // 服务端向客户端发送数据
        ctx.write("Send Client:Dear Grilfriend!");
        
        // 刷新缓存区
        ctx.flush();
        
		// 断开客户端连接
        ctx.channel().close();
        
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

NettyServer.java:

package com.kd.opt.socket;

import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;

/**
 * Springboot整合Netty,实现Socket信息交互(本项目用于与C语言程序进行交互)
 *
 * 核心文件(开启服务端)
 *
 * 服务端
 *
 * @author 小辰哥哥
 */

@Component
public class NettyServer {

    // 日志打印
    private static final Logger LOGGER = LoggerFactory.getLogger(NettyServer.class);

    // 开启服务端口
    public static void start(InetSocketAddress address) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap()
                    .group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(address)
                    .childHandler(new NettyChannelInitializer())
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            // 绑定端口,开始接收进来的连接
            ChannelFuture future = bootstrap.bind(address).sync();
            LOGGER.debug("开启Netty服务端口:" + address.getPort());
            future.channel().closeFuture().sync();

        } catch (Exception e) {
            e.printStackTrace();
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

}

Springboot启动类:

package com.kd.opt;

import com.kd.opt.socket.NettyServer;
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 org.springframework.boot.autoconfigure.SpringBootApplication;

import java.net.InetSocketAddress;

// 正常模式启动(Netty模拟单客户端操作时)
//@SpringBootApplication
//public class OperateTicketApplication {
//
//    public static void main(String[] args) {
//        SpringApplication.run(OperateTicketApplication.class, args);
//    }
//
//}

// Netty模拟单服务端操作时
@SpringBootApplication
public class OperateTicketApplication implements CommandLineRunner {

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

    @Value("${netty.url}")
    private String URL;

    @Autowired
    private NettyServer server;

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

    @Override
    public void run(String... args) throws Exception {
        InetSocketAddress address = new InetSocketAddress(URL, PORT);
        server.start(address);
    }
}

启动项目:
在这里插入图片描述
使用sokit软件(充当客户端)开始测试:在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
开始进行数据通信,然后服务端断开客户端连接:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


总结

每天一个提升小技巧!!!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小辰哥哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值