netty 通讯

简单 netty 客户端 

连接 

public final static EventLoopGroup group = new NioEventLoopGroup(); 
private void connect(GatewayModel node) throws IOException, InterruptedException {
        Bootstrap b = new Bootstrap();
        b.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline p = ch.pipeline();
                        //添加编码,解码器
                        p.addLast(new MessageEncoder());
                        p.addLast(new MessageDecoder());
                        p.addLast(new IdleStateHandler(5, 10, 10, TimeUnit.SECONDS));
                        p.addLast(new ClientProcessHandler(smsService));
                    }
                });
        ChannelFuture f = b.connect(node.getIp(), node.getPort()).sync();
        Channel channel = f.channel();
        ServerChannelManager.add(node.getId(), channel);
    }

客户端 handler

public class ClientProcessHandler extends SimpleChannelInboundHandler<Packet> {

    private static final Logger logger = LoggerFactory.getLogger(ClientProcessHandler.class);

    private SmsService smsService;

    public ClientProcessHandler(SmsService smsService) {
        super();
        this.smsService = smsService;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
        logger.info("connect server:" + address.getHostName() + ":" + address.getPort());
    }

//    @Override
//    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
//        if (evt instanceof IdleStateEvent) {
//            Packet packet = PacketFactory.getInstance().createHeartBeatReqPacket();
//            ctx.writeAndFlush(packet);
//            InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
//            logger.debug("ping server: " + address.getHostName() + ":" + address.getPort());
//        }
//    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
        String host = address.getHostName();
        int port = address.getPort();
        String nodeId = address.getHostName() + ":" + address.getPort();
        logger.error("disconnect from server:" + nodeId + " ,trying to connect server in 3 seconds...");
        ctx.channel().eventLoop().schedule(() -> doReconnect(host, port), 3, TimeUnit.SECONDS);
        ctx.close();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Packet packet) throws Exception {
        InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
        PacketHeader header = packet.getPacketHeader();
        ByteBuf body = packet.getBody();
        int commandId = header.getCommandId();
        switch (commandId) {
            case TransferCommand.HEART_BEAT_REQ:
                //心跳响应
                logger.debug("pong from server: " + address.getHostName() + ":" + address.getPort());
                break;
            case TransferCommand.MSG_ACCEPT_REQ:
                //短信上行请求
                int linkIdLen = body.readShort();
                String linkId = body.readBytes(linkIdLen).toString(Charset.forName(Constant.CHARSET_UTF8));
                //发送方手机号类型(现在都是联通的,都是3)
                int operationType = body.readByte();
                int senderLength = body.readShort();
                String sender = body.readBytes(senderLength).toString(Charset.forName(Constant.CHARSET_UTF8));
                int receiverLen = body.readShort();
                String receiver = body.readBytes(receiverLen).toString(Charset.forName(Constant.CHARSET_UTF8));
                //短信内容编码方式
                byte encoding = body.readByte();
                int contentLen = body.readShort();
                String content = body.readBytes(contentLen).toString(Charset.forName(Constant.CHARSET_UTF8));
                MessageUp up = new MessageUp();
                up.setSender(sender);
                up.setReceiver(receiver);
                up.setMsgContent(content);
                up.setSendTime(new Date());
                up.setLinkId(linkId);
                logger.info("receive msg from client :【{}】 ", sender);
                up.setChannel(ctx.channel());
                smsService.receiveMsg(up);
                break;
            default:
                logger.error("error commandId....【{}】,the commandId must be : 【{}】", commandId, TransferCommand.HEART_BEAT_REQ + "," + TransferCommand.MSG_SEND_RES + "," + TransferCommand.MSG_STATUS_REQ);
                break;
        }

    }

    private void doReconnect(String host, int port) {
        String nodeId = host + ":" + port;
        EventLoopGroup group = GatewayContext.group;
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            //添加编码,解码器
                            p.addLast(new MessageEncoder());
                            p.addLast(new MessageDecoder());
                            p.addLast(new IdleStateHandler(5, 5, 5, TimeUnit.SECONDS));
                            p.addLast(new ClientProcessHandler(smsService));
                        }
                    });
            // Start the client.
            ChannelFuture f = b.connect(host, port).sync();
            if (f.isSuccess()) {
                Channel channel = f.channel();
                ServerChannelManager.add(nodeId, channel);
                logger.info("reconnect server : 【{}】 success ", nodeId);
            }
        } catch (Exception e) {
            ServerChannelManager.remove(nodeId);
            logger.error("reconnect server:【{}】 failed,start reconnect  in 3 seconds...", nodeId);
            group.schedule(() -> doReconnect(host, port), 3, TimeUnit.SECONDS);
        }
    }
}

传输包

public class Packet {

    public static final int HEADER_SIZE = 12;

    /*
     * 包头
     */
    private PacketHeader packetHeader;
    /*
     * 包体
     */
    private ByteBuf body;

    public Packet(int commandId, int totalSize) {
        this.packetHeader = new PacketHeader();
        this.packetHeader.setCommandId(commandId);
        this.packetHeader.setTotalSize(totalSize);
    }

    public ByteBuf getBody() {
        return body;
    }

    public Packet setBody(ByteBuf body) {
        this.body = body;
        return this;
    }

    public PacketHeader getPacketHeader() {
        return this.packetHeader;
    }

    public Packet setTotalSize(int totalSize) {
        this.packetHeader.setTotalSize(totalSize);
        return this;
    }

}

编码解码

public class MessageDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if(in == null)
            return;
        if (in.readableBytes() < Packet.HEADER_SIZE) {
            in.clear();
            return;
        }
        in.markReaderIndex();
        ByteBuf bb = in.readBytes(in.readableBytes());
        int totalSize = bb.readInt();
        int commandId = bb.readInt();
        int sequenceId = bb.readInt();
        Packet packet = new Packet(commandId, totalSize);
        packet.setBody(bb);
        out.add(packet);
    }
}

public class MessageEncoder extends MessageToByteEncoder<Packet> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf out) throws Exception {
        PacketHeader header = packet.getPacketHeader();
        //写入消息的总长度
        out.writeInt(header.getTotalSize());
        //写入命令标识符
        out.writeInt(header.getCommandId());
        //写入序列号
        out.writeInt(header.getSequenceId());
        //开始写入包体
        if (packet.getBody() != null)
            out.writeBytes(packet.getBody());
    }
}
  public static void main(String[] args) {
    	String s = "buff头部";
    	String s1 ="buff实体";
    	ByteBuf in = Unpooled.copyShort(s.getBytes().length);
    	in.writeBytes(s.getBytes());
    	in.writeShort(s1.getBytes().length);
    	in.writeBytes(s1.getBytes());
    	System.out.println(in.readBytes(in.readShort()).toString(Charset.forName("UTF-8")));
    	System.out.println(in.readBytes(in.readShort()).toString(Charset.forName("UTF-8")));
	}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值