猴头蘑菇 2022-01-19 18:02 采纳率: 0%
浏览 73
已结题

Netty网络通信报HTTP/1.1 400!

问题遇到的现象和发生背景

img

需要跟别的公司进行网络通讯,对方通过C++的Socket发来电文,我们需要解析进行数据处理,还需要针对收到的电文给他们一个应答电文,Netty服务端部署在服务器上,再通过客户端请求就报上图的400,导致对方收不到正确应答电文。但是将Netty服务端部署到本地就没有问题。

问题相关代码

GeneratedNumberUtil 是我们本地工具类,实际就是SimpleDateFormat解析日期

客户端:

/**
 * netty 客户端类
 */
@Configuration
public class NettyClient {

//    @Value("${netty.remoteAddr}")
   private static String host = "127.0.0.1";
//    @Value("${netty.remotePort}")
    private static Integer port = 9001;


    public static void main(String[] args) {
        System.out.println("客户端启动!ip:"+host+",post:"+port);
        //客户端只需要创建一个线程就足够了
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //客户端启动类
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)//设置线程组
                    .channel(NioSocketChannel.class)//设置通道类型
                    .remoteAddress(new InetSocketAddress(host, port))//设置IP和端口
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast("encoder", new StringEncoder());
                            socketChannel.pipeline().addLast("decoder", new StringDecoder());
                            socketChannel.pipeline().addLast(new ClientHandler());
                        }
                    });
            //阻塞通道
            ChannelFuture channelFuture = bootstrap.connect().sync();
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {

        } finally {
            try {
                group.shutdownGracefully().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}

客户端处理器:

/**
 * 客户端逻辑处理类
 */
public class ClientHandler extends SimpleChannelInboundHandler<String> {

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

    /**
     * 连接成功后,发送给服务端的消息
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        byte[] bs = new byte[30];
        // 结束符
        byte[] bytes = {0x0a};
        StringBuffer sb = new StringBuffer();
        //         电文长度        电文号              电文发送日期
        sb.append("0030").append("999999").append(GeneratedNumberUtil.sdf.format(new Date())).
                //        电文发送时间                                     发送端描述码   接收端描述码      传送功能码
                append(GeneratedNumberUtil.sdfhms.format(new Date())).append("LS").append("CX").append("C");
        byte[] bytes1 = sb.toString().getBytes(CharsetUtil.UTF_8);
        for (int i = 0; i < bytes1.length; i++) {
            bs[i] = bytes1[i];
        }
        bs[29] = bytes[0];
        String string = new String(bs);
        logger.info("发送的数据:{}",string);
//        ctx.writeAndFlush(string);
        ctx.write(string);
        ctx.write(bs);
        ctx.flush();
    }


    /**
     * 回调方法,接收服务器发送的消息
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
//        System.out.println("--------消息:"+ msg.toString(CharsetUtil.UTF_8) + "-----------");
        logger.info("Client accept : {}" ,msg);
    }

    /**
     * 在处理过程中引发异常时被调用
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

服务端代码:

/**
 * Netty
 * 服务端
 */
@Configuration
public class NettyServer {

    private final Integer port = 9001;

    //四个处理请求的逻辑类
    @Autowired
    ServerInboundHandler serverInboundHandler;

    @Autowired
    ServerInboundGetTimeHandler serverInboundGetTimeHandler;

    @Autowired
    ServerLastOutboundHandler serverLastOutboundHandler;

    @Autowired
    ServerOutboundHandler serverOutboundHandler;

    public void startServer() {
        System.out.println("服务端启动成功");
        //创建两个线程组,用于接收客户端的请求任务,创建两个线程组是因为netty采用的是反应器设计模式
        //反应器设计模式中bossGroup线程组用于接收
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //workerGroup线程组用于处理任务
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        //创建netty的启动类
        ServerBootstrap bootstrap = new ServerBootstrap();
        //创建一个通道
        ChannelFuture f;
        try {
            bootstrap.group(bossGroup, workerGroup) //设置线程组
                    .channel(NioServerSocketChannel.class) //设置通道为非阻塞IO
                    .option(ChannelOption.SO_BACKLOG, 128) //设置日志
                    .option(ChannelOption.SO_RCVBUF, 32 * 1024)  //接收缓存
                    .childOption(ChannelOption.SO_KEEPALIVE, true)//是否保持连接
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        //设置处理请求的逻辑处理类
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //ChannelPipeline是handler的任务组,里面有多个handler
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast("decoder", new StringDecoder());
                            pipeline.addLast("encoder", new StringEncoder());
                            //逻辑处理类
//                            pipeline.addLast(serverLastOutboundHandler);
//                            pipeline.addLast(serverOutboundHandler);
                            pipeline.addLast(serverInboundHandler);
//                            pipeline.addLast(serverInboundGetTimeHandler);
                        }
                    });

            f = bootstrap.bind(port).sync();//阻塞端口号,以及同步策略
            f.channel().closeFuture().sync();//关闭通道
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //优雅退出
            try {
                bossGroup.shutdownGracefully().sync();
                workerGroup.shutdownGracefully().sync();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }


}

服务端处理器:

/**
 * Inbound处理类,是用来处理客户端发送过来的信息
 * Sharable 所有通道都能使用的handler
 */
@Configuration
@ChannelHandler.Sharable
public class ServerInboundHandler extends ChannelInboundHandlerAdapter {

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

    /**
     * 获取客户端的内容类
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //将传递过来的内容转换为ByteBuf对象
        String s = (String) msg;
        logger.info("服务端接收到的信息为: {}", s);

        byte[] bs = new byte[110];
        byte[] bytes = {0x0a};
        // 拼接应答电文
        StringBuffer sb = new StringBuffer();
        String msgNum = "CXLS01";  // 电文号
        if (StringUtils.isNotEmpty(s)){
            msgNum = s.substring(4,10);
        }
        logger.info("接收到应用电文的电文号:{}",msgNum);
        String transmissionCode = "A";  // 默认为A 表示ACK
        String controlDomain = "                                                                                ";// 控制域 默认为空格,搭配ACK使用,长度80byte
        if (StringUtils.isEmpty(s)){
            logger.info("进入NACK...");
            transmissionCode = "B";     // 否则为N 表示错误应答 NACK
            controlDomain = "                                                                                ";// 如果出错,控制域使用西文字符指定出错位置,暂不设置
        }
        //         电文长度        电文号              电文发送日期
        sb.append("0110").append(msgNum).append(GeneratedNumberUtil.sdf.format(new Date())).
                //        电文发送时间                                            发送端描述码   接收端描述码       传送功能码
                        append(GeneratedNumberUtil.sdfhms.format(new Date())).append("LS").append("CX").append(transmissionCode).
                //          控制域
                        append(controlDomain);
        byte[] bytes1 = sb.toString().getBytes(CharsetUtil.UTF_8);
        for (int i = 0; i < bytes1.length; i++) {
            bs[i] = bytes1[i];
        }
        bs[109] = bytes[0];
        String string = new String(bs);
        logger.info("服务端反馈的数据:{}",string);
//        ctx.writeAndFlush(string);
        ctx.write(string);
        ctx.write(bs);
        ctx.flush();
    }

    /**
     * 刷新后才将数据发出到SocketChannel
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    /**
     * 关闭
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        logger.info("报错啦!错误信息:{}",cause.getMessage());
        cause.printStackTrace();
        ctx.close();
    }
}

我的解答思路和尝试过的方法

一开始以为是nginx代理的问题,但这个部署在专门做接口对接的服务,发现并没有涉及nginx。
也试过原生的Socket写服务端,但是一旦部署在服务器上时,本地的客户端请求收不到任何响应,连报错也没有
问过很多人了,也百度很多次了,都没有解决方法,只能网上寻求大佬解决了。网络通讯的通道是建立了,但是由于返回的是报错信息,导致对方无法收到正确格式的电文,所以就没有后续了。

我想要达到的结果

客户端在请求服务端时,需要收到正确的数据。

  • 写回答

1条回答 默认 最新

  • 有问必答小助手 2022-01-21 10:33
    关注

    你好,我是有问必答小助手,非常抱歉,本次您提出的有问必答问题,技术专家团超时未为您做出解答


    本次提问扣除的有问必答次数,将会以问答VIP体验卡(1次有问必答机会、商城购买实体图书享受95折优惠)的形式为您补发到账户。


    因为有问必答VIP体验卡有效期仅有1天,您在需要使用的时候【私信】联系我,我会为您补发。

    评论

报告相同问题?

问题事件

  • 系统已结题 1月27日
  • 创建了问题 1月19日

悬赏问题

  • ¥30 python代码,帮调试
  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建
  • ¥15 数据可视化Python
  • ¥15 要给毕业设计添加扫码登录的功能!!有偿
  • ¥15 kafka 分区副本增加会导致消息丢失或者不可用吗?
  • ¥15 微信公众号自制会员卡没有收款渠道啊
  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条