package com.chinaums.japi.util;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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.util.ReferenceCountUtil; import java.nio.charset.Charset; public class NettyClient {
public static void main(String[] args) {
String req = "<ap><ProductID>IBB</ProductID><ChannelType>ERP</ChannelType><CorpNo/><OpNo/><AuthNo/><ReqSeqNo>TER1694770206768</ReqSeqNo><ReqDate>20230915</ReqDate><ReqTime>173006</ReqTime><Sign/><CCTransCode>ABCDEF</CCTransCode><Amt/><Corp/><Cmp/></ap>";
try {
String ret = sendXmlToIct("172.16.16.207", 19999, req);
System.out.println(ret);
} catch (InterruptedException e) {
System.out.println("异常了");
}
} /**
* 发送XML报文到ICT
* 调用该方法时不需要关心报文头,处理器会自动处理
*
* @param ip
* @param port
* @param xml
* @return
* @throws InterruptedException
*/
public static String sendXmlToIct(String ip, int port, String xml) throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加处理报文头的 ChannelHandler
pipeline.addLast(new MyHeaderReqHandler());
pipeline.addLast(new MyHeaderResHandler());
}
});
Channel channel = bootstrap.connect(ip, port).sync().channel();
channel.writeAndFlush(Unpooled.copiedBuffer(xml, Charset.forName("GBK")));
// 等待消息发送完成
channel.flush();
StringBuilder messageBuilder = new StringBuilder();
channel.pipeline().addLast(new SimpleChannelInboundHandler<ByteBuf>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
messageBuilder.append(msg.toString(Charset.forName("GBK")));
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
super.channelReadComplete(ctx);
ctx.channel().close();
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
// 处理异常
}
});
channel.closeFuture().sync();
return messageBuilder.toString();
} finally {
group.shutdownGracefully();
}
} /**
* 发送请求前报文头处理
* 这个也可以单独弄出去,而不是现在这样的内部类
* <p>
* Socket方式中报文结构为“包头+数据包”。
* 包头固定为7个字节长,第1字节为是否加密标志(0-不加密,1-加密)。
* 后6个字节是数据包的长度,即将报文长度直接转为字符串存储,长度不足6位则右边用空格补足,
* 比如:“1234 ”。比如汇兑的长度为1234字节的数据包,其包头为“01234 ”共7位,其中数据包长度包含加密包标志位。
* 由于加密需要双方约定专门的加密算法,因此一般ERP送的加密标志都为0-不加密。
*/
public static class MyHeaderReqHandler extends ChannelOutboundHandlerAdapter {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if (msg instanceof ByteBuf) {
ByteBuf data = (ByteBuf) msg;
// 获取数据包长度
int length = data.readableBytes();
// 创建一个新的ByteBuf来存储带有报文头的完整数据
ByteBuf newData = ctx.alloc().buffer(7 + length);
// 写入加密标志(0-不加密,1-加密)
newData.writeByte(0); // 这里写入了0,表示不加密
// 将数据包的长度转换为字符串,并用空格补足6位
String lengthStr = String.format("%06d", length);
newData.writeBytes(lengthStr.getBytes());
// 写入原始数据包
newData.writeBytes(data);
// 替换原始消息为带有报文头的新消息
ReferenceCountUtil.release(msg);
msg = newData;
}
super.write(ctx, msg, promise);
}
} /**
* 接收响应后报文头处理
* 这个也可以单独弄出去,而不是现在这样的内部类
* <p>
* Socket方式中报文结构为“包头+数据包”。
* 包头固定为7个字节长,第1字节为是否加密标志(0-不加密,1-加密)。
* 后6个字节是数据包的长度,即将报文长度直接转为字符串存储,长度不足6位则右边用空格补足,
* 比如:“1234 ”。比如汇兑的长度为1234字节的数据包,其包头为“01234 ”共7位,其中数据包长度包含加密包标志位。
* 由于加密需要双方约定专门的加密算法,因此一般ERP送的加密标志都为0-不加密。
*/
public static class MyHeaderResHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof ByteBuf) {
ByteBuf data = (ByteBuf) msg;
// 读取加密标志
byte encryptFlag = data.readByte();
// 读取数据包长度
byte[] lengthBytes = new byte[6];
data.readBytes(lengthBytes);
int length = Integer.parseInt(new String(lengthBytes).trim());
// 读取数据包内容
ByteBuf packet = data.readBytes(length);
// 将解析后的数据继续传递给下一个处理器处理
// 使用retain()方法确保数据不会被提前释放
ctx.fireChannelRead(packet.retain());
// 释放原始消息
ReferenceCountUtil.release(msg);
}
}
}
}

netty发送socket短连接请求,自定义报文头的更多相关文章

  1. C# Socket.Connect连接请求超时机制

    介绍 您可能注意到了,.Net的System.Net.Sockets.TcpClient和System.Net.Sockets.Socket都没有直接为Connect/BeginConnect提供超时 ...

  2. socket短连接、长连接

    通常短连接是这样:连接->传输数据->关闭连接那什么是长连接?一般长连接相对短连接而言的,长连接在传输结束后不关闭连接,而不断的发送包保持连接等待处理下一个数据包. 一般长连接用于少数cl ...

  3. SPDK发送和接收连接请求的处理

    因工作需要分析了部分SPDK代码,主要梳理login请求以及响应的处理,供参考. 参考代码——SPDK代码实现(以PLOGI为例): SPDK处理PLOGI分为三个阶段: 第一阶段通过一条GET_PA ...

  4. socket短连接太多,accept次数很多导致主线程CPU占满,工作线程CPU占用率低

    1.使用epoll的ET模式: 2.开启reuseport方法: Linux 最新SO_REUSEPORT特性:http://www.mamicode.com/info-detail-2201958. ...

  5. Netty(二):如何处理io请求?

    文接上一篇.上篇讲到netty暴露一个端口出来,acceptor, handler, pipeline, eventloop 都已准备好.但是并没体现其如何处理接入新的网络请求,今天我们就一起来看看吧 ...

  6. TCP连接过程及报文解析

    可能大家都听过TCP建立连接时需要经历三次握手和四次挥手的. 那么具体的握手挥手的过程是怎么样的呢? 这篇文章就通过WireShark抓包来了解TCP连接建立和断开的过程. 实验方法: 写一段简单的代 ...

  7. 如何用ASP.NET实现bosh模拟http双向长连接请求

    在做研究之前先简单说一下之前公司的通讯模块.最早的时候公司开发的web管理系统是需要配合c++桌面客户端进行一些系统底层操作,并非普通的b/s架构,或者c/s架构,因为需求是可以通过web管理系统向客 ...

  8. “ping”命令的原理就是向对方主机发送UDP数据包,HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”

    Socket  是一套建立在TCP/IP协议上的接口不是一个协议 应用层:  HTTP  FTP  SMTP  Web 传输层:  在两个应用程序之间提供了逻辑而不是物理的通信(TCP  UDP) T ...

  9. TCP/IP,http,socket,长连接,短连接

    TCP/IP TCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层. 在网络层有IP协议.ICMP协议.ARP协议.RARP协议和BOOTP协议. 在传输层中有TCP协议与UDP协议. 在应 ...

  10. TCP/IP,http,socket,长连接,短连接——小结。

    来源:http://blog.chinaunix.net/uid-9622484-id-3392992.html TCP/IP是什么? TCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层. ...

随机推荐

  1. 『Python底层原理』--GIL对多线程的影响

    在 Python 多线程编程中,全局解释器锁(Global Interpreter Lock,简称 GIL)是一个绕不开的话题. GIL是CPython解释器的一个机制,它限制了同一时刻只有一个线程可 ...

  2. netcore后台服务慎用BackgroundService

    在 .NET Core 开发中,BackgroundService 是一个非常方便的后台任务运行方式,但它并不适用于所有场景. BackgroundService 一时爽,并发火葬场. Backgro ...

  3. 搭建个人多机器ssh连接平台

    最近新配了个主机,有了多个设备,ssh连接的功能可以优化很多体验,便又开始鼓捣.以前都是windows连各种linux,比较方便:这次是在windows之间,还是小查了好一会儿,留个记录 SSH连接的 ...

  4. Windows编程----内核对象竟然如此简单?

    什么是内核对象 内核对象本质上就是内存中的一块内存 ,这块内存由操作系统进行管理和分配,任何应用程序都无法直接操作这块内存区域.至于内核对象的作用,我们暂且不说,这里只需要直到它是内存中的一块内存. ...

  5. Golang 入门 : 字符串及底层字符类型

    字符串 基本使用 在 Go 语言中,字符串是一种基本类型,默认是通过 UTF-8 编码的字符序列,当字符为 ASCII 码时则占用 1 个字节,其它字符根据需要占用 2-4 个字节,比如中文编码通常需 ...

  6. 因为Apifox不支持离线,我果断选择了Apipost!

    要说国内最有名的两款API开发工具不是Apipost就是Apifox,因为曾经遭遇到一件事,导致我坚定的选择了Apipost. 有一年春节我攒了足够的年假,提前开开心心的过年回家,路上我的领导给我打电 ...

  7. 资料推荐-一个神奇的网站educative.io

    前言 算法和数据结构一直是笔者心中的痛,笔者曾经阅读过两个材料,但都收效不好,尝试总结下这两个材料: 极客时间的数据结构和算法的课程 优点:适合用于去理解数据结构和算法的基本概念 缺点:不包含题目(这 ...

  8. 【大数据】HBase 集群部署:全流程详细步骤解析

    [大数据]HBase 集群部署:全流程详细步骤解析 前言 本文帮助你从零搭建一个三台机器(虚拟机)的HBase集群,适用于大数据专业或者用到HBase的同学查看,由于操作步骤过多,特此记录,完整操作过 ...

  9. 《机器人SLAM导航核心技术与实战》前言

    <机器人SLAM导航核心技术与实战>前言 温馨提示: 本篇文章是我最新出版的书籍<机器人SLAM导航核心技术与实战>的前言部分,感兴趣的读者可以购买纸质书籍来进行更加深入和系统 ...

  10. Lua中获取第二天凌晨的剩余时间

    在时间这个问题上,lua提供两大方法来供开发者使用,一个是os.time(),一个是os.date(),这两大方法可以满足日常开发的需求. 那么我们如何准确运用这两大方法呢. 在这一文章中我们先讲os ...