netty学习(5):netty实现注册中心和发送JSON数据到指定的客户端

1. 实现:在netty客户端实现netty客户端注册功能,netty客户端需要发送注册消息到netty服务端。

2. 在父工程创建Message类,定义消息格式和消息类型

定义消息类型:

package message;

public enum MessageType {
    RegisterRequest,
    RegisterResponse,

    QueryRegisterRequest,
    QueryRegisterResponse,

    Request,
    Response
}

定义Message

package message;

import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

@Data
public class Message extends JSONObject {
    private String uuid;
    private MessageType messageType;
    private String from; //消息来源
    private String to;
    private JSONObject data; //消息实体
    private JSONObject message = new JSONObject();

    public Message(MessageType messageType, String from, String to, JSONObject data) {
        this.uuid = UUID.randomUUID().toString();
        this.messageType = messageType == null ? MessageType.Request : messageType;
        this.from = from;
        this.to = to;
        this.data = data;
        message.put("uuid", this.uuid);
        message.put("messageType", messageType);
        message.put("from", from);
        message.put("to", to);
        message.put("data", data);
    }

    //序列化
    public byte[] toByte() {
        System.out.println("message:" + this.message.toJSONString());
        return this.message.toJSONString().getBytes(StandardCharsets.UTF_8);
    }

    //反序列化
    public static Message toMessage(String msg) {
        return (Message) JSONObject.parseObject(msg);
    }

    public String toString() {
        return this.message.toJSONString();
    }
}

3. 服务端实现注册中心

创建Register类,管理注册的客户端

package server.register;

import io.netty.channel.Channel;
import java.util.HashMap;

public class Register {
    private static HashMap<String, Channel> registerTable = new HashMap<>();

    private Register() {

    }

    public static void addServer(String name, Channel channel) {
        registerTable.put(name, channel);
        System.out.println(name + "注册成功!");
    }

    public static void removeServer(String name, Channel channel) {
        registerTable.remove(name);
    }

    public static Channel getServer(String name) {
        return registerTable.get(name);
    }

    public static HashMap<String, Channel> getAllServer() {
        return registerTable;
    }
}

修改NettyServiceHandler,对服务器接收的消息根据类型处理,如果是注册消息,则去注册,请求消息则发送到相应的客户端。

package server.netty;

import com.alibaba.fastjson.JSONObject;
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.util.concurrent.GlobalEventExecutor;
import server.register.Register;

import java.util.HashMap;

public class NettyServiceHandler extends SimpleChannelInboundHandler<String> {
    private static final ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 获取到当前与服务器连接成功的channel
        Channel channel = ctx.channel();
        group.add(channel);
        System.out.println(channel.remoteAddress() + " 上线," + "在线数量:" + group.size());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 获取到当前要断开连接的Channel
        Channel channel = ctx.channel();
        System.out.println(channel.remoteAddress() + "下线," + "在线数量:" + group.size());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        Channel channel = ctx.channel();
        System.out.println("netty客户端" + channel.remoteAddress() + "发送过来的消息:" + msg);
        JSONObject message = JSONObject.parseObject(msg);
//        group.forEach(ch -> { // JDK8 提供的lambda表达式
//            if (ch != channel) {
//                ch.writeAndFlush(msg + "\r\n");
//            }
//        });
        HandlerMessage(message, channel);
    }

    public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) throws Exception {
        throwable.printStackTrace();
        channelHandlerContext.close();
    }

    public void HandlerMessage(JSONObject message, Channel channel) {
        String messageType = message.getString("messageType");
        switch (messageType) {
            case "RegisterRequest":
                message.put("channel", channel);
                register(message);
                break;
            case "QueryRegisterRequest":
                break;
            default:
                request(message);
        }
    }

    public void register(JSONObject message) {
        Register.addServer(message.getString("from"), (Channel) message.get("channel"));
    }

    public void request(JSONObject message) {
        Channel channel = Register.getServer(message.getString("to"));
        channel.writeAndFlush(message.toJSONString() + "\r\n");
    }

    public HashMap<String, Channel> queryRegister() {
        return Register.getAllServer();
    }
}

4. 客户端自动注册

客户端启动时把自己的信息发送到服务端

package client.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import message.Message;
import message.MessageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
@Slf4j
public class NettyClient {
    public final static Logger logger = LoggerFactory.getLogger(NettyClient.class);

    @Resource
    private SocketInitializer socketInitializer;

    @Getter
    private Bootstrap bootstrap;

    @Getter
    private Channel channel;

    /**
     * netty服务监听端口
     */
    @Value("${netty.port:6666}")
    private int port;

    @Value("${netty.host:127.0.0.1}")
    private String host;

    @Value("${netty.name}")
    private String name;
    /**
     * 启动netty
     */
    public void start() {
        this.init();
        this.channel = this.bootstrap.connect(host, port).channel();
        logger.info("Netty connect on port: {}, the host {}, the channel {}", this.port, this.host, this.channel);
        //自动注册
        register();
    }

    /**
     * 初始化netty配置
     */
    private void init() {
        EventLoopGroup group = new NioEventLoopGroup();
        this.bootstrap = new Bootstrap();
        //设置线程组
        bootstrap.group(group)
                .channel(NioSocketChannel.class) //设置客户端的通道实现类型
                .handler(this.socketInitializer);
    }

    //netty发送消息
    public void sendMessage(String message) {
        this.channel.writeAndFlush(message + "\r\n");
    }

    //netty发送消息
    public void sendMessage(Message message) {
        this.channel.writeAndFlush(message.toString() + "\r\n");
    }

    public void register() {
        Message message = new Message(MessageType.RegisterRequest, name, null, null);
        sendMessage(message);
        logger.info("register");
    }
}

5. 客户端RestController层接收消息

RESTFUL风格,从url解析目标客户端的名称

package client.control;

import client.netty.NettyClient;
import com.alibaba.fastjson.JSONObject;
import message.Message;
import message.MessageType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;

@RestController
@RequestMapping("/client1")
public class NettyControl {
    @Value("${netty.name}")
    private String from;

    @Resource
    private NettyClient nettyClient;

    @PostMapping("/{to}/msg")
    public String sendMsg(@PathVariable("to") String to, @RequestBody JSONObject data) {
        Message message = new Message(MessageType.Request, from, to, data);
        this.nettyClient.sendMessage(message);
        return message.toString();
    }
}

6. postman测试

启动服务和两个客户端,客户端已经注册成功。
在这里插入图片描述
client1发送到client2
在这里插入图片描述
在这里插入图片描述
client2发送到client1
在这里插入图片描述
在这里插入图片描述
服务端收到的消息
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Spring Boot和Netty实现发送Json消息,你可以使用Net的`ChannelHandlerContext`对象来发送消息。下面是一个简单的示例: 首先,创建一个`JsonMessage`类表示要发送Json消息: ```java public class JsonMessage { private String message // 省略构造方法和getter/set @Override public String toString() { return "JsonMessage{" + "message='" + message + '\'' + '}'; } } ``` 然后,在`JsonHandler`中添加逻辑以接收和发送Json消息。下面是一个示例: ```java import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; public class JsonHandler extends SimpleChannelInboundHandler<String> { private ObjectMapper objectMapper = new ObjectMapper(); @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { // 接收到客户端发送Json字符串 System.out.println("Received message: " + msg); // 解析Json字符串为对象 JsonMessage jsonMessage = objectMapper.readValue(msg, JsonMessage.class); // 处理消息逻辑 // ... // 构造要发送Json消息对象 JsonMessage response = new JsonMessage("Hello from server!"); // 将Json消息对象转换为字符串 String responseJson = objectMapper.writeValueAsString(response); // 发送Json消息客户端 ByteBuf buf = ctx.alloc().buffer(); buf.writeBytes(responseJson.getBytes()); ctx.writeAndFlush(buf); } } ``` 在上面的示例中,我们将接收到的Json字符串解析为`JsonMessage`对象,并构造要发送的响应消息。然后,我们使用`ObjectMapper`将响应消息对象转换为Json字符串,并通过`ChannelHandlerContext`发送客户端。 需要注意的是,你可以根据具体的业务需求在`channelRead0`方法中添加适当的处理逻辑。并且在实际应用中,你可能还需要处理异常、断开连接等其他情况。 最后,你可以通过编写Spring Boot的启动类来启动Netty服务器,并监听指定的端口: ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); int port = 8080; try { new JsonServer(port).run(); } catch (Exception e) { e.printStackTrace(); } } } ``` 在上面的示例中,我们在Spring Boot应用的启动类中创建了一个新的`JsonServer`实例,并通过调用`run`方法来启动Netty服务器。 现在,你可以运行Spring Boot应用,并发送Json消息到服务器,然后服务器会将响应消息发送客户端。记得根据自己的实际需求进行适当的修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值