Netty 客户端的创建

1. 为什么会有这个冲动?

最近使用到了netty需要进行测试,所以想着编写一个客户端。刚开始的时候编写了一个简单地main方法。每测试一次就需要重启一下,太麻烦了……,所以就想着如果像接口一样每次都调用一次接口那就不用重启了。其中代码参考了网络上找到的,但忘记是谁的了,如有需要删除,请私信。

2. 目录结构

3.代码

记录顺序就按照包的顺序

package com.bkht.testcollect.modules.channel;

import com.bkht.testcollect.modules.handler.MessageHandler;
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.handler.timeout.IdleStateHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * Netty 通道初始化
 *
 * @author lipw
 */
@Component
@RequiredArgsConstructor
public class ChannelInit extends ChannelInitializer<SocketChannel> {
    private final MessageHandler messageHandler;

    @Override
    protected void initChannel(SocketChannel socketChannel) {
        socketChannel.pipeline()
                // 每隔60s的时间触发一次userEventTriggered的方法,并且指定IdleState的状态位是WRITER_IDLE,事件触发给服务器发送ping消息
                .addLast("idle", new IdleStateHandler(0, 60, 0, TimeUnit.SECONDS))
                // 添加解码器
                .addLast(new StringDecoder())
                // 添加编码器
                .addLast(new StringEncoder())
                // 添加消息处理器
                .addLast("messageHandler", messageHandler);
    }
}
package com.bkht.testcollect.modules.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * 读取YML中的服务配置
 *
 * @author lipw
 */
@Configuration
@ConfigurationProperties(prefix = ClientProperties.PREFIX)
@Data
public class ClientProperties {

    public static final String PREFIX = "netty";

    /**
     * 客户端IP
     */
    private Integer clientPort;

    /**
     * 默认连接的服务器Ip
     */
    private String serverIp;

    /**
     * 默认;连接的服务器端口
     */
    private Integer serverPort;
}

package com.bkht.testcollect.modules.controller;

import com.alibaba.fastjson.JSONObject;
import com.bkht.testcollect.modules.server.TcpClient;
import com.bkht.testcollect.modules.test.NettyClient;
import io.netty.bootstrap.Bootstrap;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * 模拟发送api
 *
 * @author lipw
 */
@RequiredArgsConstructor
@RestController
@Slf4j
public class HttpApi {

    @Resource
    private TcpClient tcpClient;

    /**
     * 消息发布
     */
    @GetMapping("/send")
    public String send(String message) {
        System.out.println("send:" + message);
        tcpClient.getSocketChannel().writeAndFlush(message);
        return "已经发送:" + message + ",成功!";
    }

    /**
     * 消息发布
     */
    @PostMapping("/send/json")
    public String send(@RequestBody JSONObject body) {
        tcpClient.getSocketChannel().writeAndFlush(body.toJSONString());
        return "发送成功";
    }

    /**
     * 连接
     */
    @GetMapping("connect")
    public String connect(String ip, Integer port) throws Exception {
        tcpClient.connect(ip, port);
        return "重启指令发送成功";
    }

    /**
     * 重连
     */
    @GetMapping("reconnect")
    public String reconnect() throws Exception {
        tcpClient.reconnect();
        return "重启指令发送成功";
    }
}
package com.bkht.testcollect.modules.handler;

import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 息处理,单例启动
 *
 * @author lipw
 */
@Slf4j
@Component
@ChannelHandler.Sharable
@RequiredArgsConstructor
public class MessageHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {
        log.debug("\n");
        log.debug("channelId:" + ctx.channel().id());

        System.out.println("channelId:" + ctx.channel().id());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        log.debug("\n");
        log.debug("开始连接");

        System.out.println("开始连接");
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.debug("\n");
        log.info("成功建立连接,channelId:{}", ctx.channel().id());

        System.out.println("成功建立连接,channelId:{}"+ ctx.channel().id());
        super.channelActive(ctx);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        log.info("心跳事件时触发");

        System.out.println("心跳事件时触发");
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            // 当我们长时间没有给服务器发消息时,发送ping消息,告诉服务器我们还活跃
            if (event.state().equals(IdleState.WRITER_IDLE)) {
                log.debug("发送心跳");
                System.out.println("发送心跳");
                ctx.writeAndFlush("ping");
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

}
package com.bkht.testcollect.modules.init;

import com.bkht.testcollect.modules.server.TcpClient;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class InitNettyClient implements CommandLineRunner {

    @Resource
    private TcpClient tcpClient;

    @Override
    public void run(String... args) throws Exception {
        tcpClient.start();
    }
}
package com.bkht.testcollect;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TestcollectApplication {

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

}
server:
  port: 8087

spring:
  application:
    name: tcp-client

# tcp
netty:
  # 客户端监听端口
  client-port: 8088
  # 默认连接的服务器 ip
  server-ip: 127.0.0.1
  # 默认连接的服务器端口
  server-port: 9099

# 日志配置
logging:
  level:
    com.netty: debug

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
如果你想在 Spring Boot 中使用 Netty 客户,可以按照以下步骤进行操作: 1. 添加 Netty 依赖 在你的 Spring Boot 项目的 pom.xml 文件中添加以下依赖: ```xml <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.42.Final</version> </dependency> ``` 2. 创建 Netty 客户 创建一个 Netty 客户的示例代码如下: ```java @Component public class NettyClient { private EventLoopGroup group; private Bootstrap bootstrap; private Channel channel; private ChannelFuture channelFuture; @Value("${netty.server.host}") private String host; @Value("${netty.server.port}") private int port; @PostConstruct public void start() throws Exception { group = new NioEventLoopGroup(); bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new StringEncoder(), new StringDecoder(), new NettyClientHandler()); } }); channelFuture = bootstrap.connect(host, port).sync(); channel = channelFuture.channel(); } @PreDestroy public void stop() throws Exception { channel.closeFuture().sync(); group.shutdownGracefully(); } public void sendMessage(String message) { channel.writeAndFlush(message); } } ``` 上述代码中,我们创建了一个 Netty 客户,包括了 Netty 的启动、停止和发送消息等功能。 3. 创建 Netty 客户处理器 创建一个 Netty 客户处理器的示例代码如下: ```java @Component public class NettyClientHandler extends SimpleChannelInboundHandler<String> { @Override protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { // 处理接收到的消息 } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // 处理异常 } } ``` 上述代码中,我们继承了 Netty 的 SimpleChannelInboundHandler 类,并重写了 messageReceived 和 exceptionCaught 方法,用于处理接收到的消息和异常。 4. 发送消息 我们可以在任何时候通过 Netty 客户的 sendMessage 方法向服务发送消息,示例代码如下: ```java @Autowired private NettyClient nettyClient; public void send() { nettyClient.sendMessage("hello world"); } ``` 通过上述步骤,我们就可以在 Spring Boot 中使用 Netty 客户了。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值