Springboot使用Netty连接Tcp接口(c语言二进制字节码转java字符串)

这篇具有很好参考价值的文章主要介绍了Springboot使用Netty连接Tcp接口(c语言二进制字节码转java字符串)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

   **使用java编码的springboot项目在调用C语言等其他语言编写的Tcp接口时,使用netty框架可以实现数据双向持续交互处理。
   注:在交互过程中,c语言生成的二进制字节码转java字符串时往往出现乱码,请看后面处理方式(netty处理类中的代码)。**

一、引入netty的jar包

io.netty
netty-all

二、使用netty框架
1、创建客户端
package com.iflytek.digtal.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**

  • netty客户端
    */
    public class NettyClient {

    /**

    • 连接tcp服务端初始化

    • @throws InterruptedException
      */
      public static void init() throws InterruptedException {
      //客户端需要一个事件循环组
      NioEventLoopGroup group = new NioEventLoopGroup();

      try {
      //创建客户端启动对象
      //注意客户端使用的不是SocketBootstrap而是Bootstrap
      Bootstrap bootstrap = new Bootstrap();

       // 设置相关参数
       bootstrap.group(group) //设置线程组
               .channel(NioSocketChannel.class)// 使用NioSocketChannel作为客户端的通道实现
               .handler(new ChannelInitializer<SocketChannel>() {
                   @Override
                   protected void initChannel(SocketChannel ch) throws Exception {
                       ch.pipeline().addLast(new NettyClientHandler());
                   }
               });
      
       System.out.println("netty client start..");
       ChannelFuture cf = bootstrap.connect("127.0.0.1", 6000).sync();
      
       cf.channel().closeFuture().sync();
      

      }finally {
      group.shutdownGracefully();
      }
      }

    public static void main(String[] args) throws InterruptedException {
    //客户端需要一个事件循环组
    NioEventLoopGroup group = new NioEventLoopGroup();

     try {
         //创建客户端启动对象
         //注意客户端使用的不是SocketBootstrap而是Bootstrap
         Bootstrap bootstrap = new Bootstrap();
    
         // 设置相关参数
         bootstrap.group(group) //设置线程组
                 .channel(NioSocketChannel.class)// 使用NioSocketChannel作为客户端的通道实现
                 .handler(new ChannelInitializer<SocketChannel>() {
                     @Override
                     protected void initChannel(SocketChannel ch) throws Exception {
                         ch.pipeline().addLast(new NettyClientHandler());
                     }
                 });
    
         System.out.println("netty client start..");
         ChannelFuture cf = bootstrap.connect("127.0.0.1", 6000).sync();
    
         cf.channel().closeFuture().sync();
     }finally {
         group.shutdownGracefully();
     }
    

    }

}
2、创建服务端
package com.iflytek.digtal.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class NettyServer {

public static void main(String[] args) throws InterruptedException {
    //创建两个线程组bossGroup和workerGroup,含有的子线程NioEventLoop的个数默认是CPU的两倍
    //bossGroup只是处理连接请求,真正的和客户端业务处理,会交给workerGroup完成
    EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    EventLoopGroup workerGroup = new NioEventLoopGroup(1);

    try {
        //创建服务器端的启动对象
        ServerBootstrap bootstrap = new ServerBootstrap();
        //使用链式编程来配置参数
        bootstrap.group(bossGroup, workerGroup)//设置两个线程组
                .channel(NioServerSocketChannel.class)//使用NioServerSocketChannel作为服务器的通道实现
                //初始化服务器连接队列大小,服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接
                //多个客户端同时来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理
                .option(ChannelOption.SO_BACKLOG, 1024)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel channel) throws Exception {
                        //对workerGroup的SocketChannel设置处理器
                        channel.pipeline().addLast(new NettyServerHandler());
                    }
                });

        System.out.println("netty server start..");

        //绑定一个端口并且同步生成一个ChannelFuture异步对象,通过isDone()等方法可以判断异步事件的执行情况
        //启动服务器(并绑定的端口),bind是异步操作,sync方法是等待异步操作执行完毕
        ChannelFuture cf = bootstrap.bind(9000).sync();

        //给cf注册监听器,监听我们关心的事件
        cf.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (cf.isSuccess()) {
                    System.out.println("监听端口9000成功");
                } else {
                    System.out.println("监听端口9000失败");
                }
            }
        });
        //等待服务端监听端口关闭,closeFuture是异步操作
        //通过sync方法同步等待通道关闭处理完毕,这里会阻塞等待通道关闭完成,内部调用的是Object的wait()方法
        cf.channel().closeFuture().sync();

    } finally {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }

}

}
3、编写处理类
package com.iflytek.digtal.netty2;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;

/**

  • 处理类
    */
    @Slf4j
    public class NettyClientHandler2 extends ChannelInboundHandlerAdapter {

    /**

    • 客户端连接标识
    • @param ctx
    • @throws Exception
      */
      @Override
      public void channelActive(ChannelHandlerContext ctx) throws Exception {
      ByteBuf buf = Unpooled.copiedBuffer(“HelloServer”.getBytes(Charset.forName(“GBK”)));
      ctx.writeAndFlush(buf);
      }

    //当通道建立后有事件时会触发,即服务端发送数据给客户端
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

     ByteBuf buf = (ByteBuf) msg;
     log.info("哈哈哈:{}",msg);
     // 复制内容到字节数组bytes
     byte[] bytes = new byte[buf.readableBytes()];
     buf.readBytes(bytes);
     log.info("收到的数据为:{}", bytes);
    
     int[] lengthArr = {4,4,4,4,4,4,56,24,56,24,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,56,32,8};
     String[] strArr = {"int","int","int","int","int","int","char","char","char","char",
             "float","float","int","int","float","float","float","float","int","int","int","int",
             "int","int","int","int","char","char","systime"};
    
     String[] strs = new String[29];
     int offset = 0;
     for(int i =0;i<29;i++){
         byte[] bytes1 = new byte[lengthArr[i]];
         System.arraycopy(bytes, offset, bytes1, 0, lengthArr[i]);
         offset = offset + lengthArr[i];
         if("int".equals(strArr[i])){
             strs[i] = String.valueOf(bytesToInt(bytes1,0));
         }else if("char".equals(strArr[i])){
             strs[i] = bytesToChar(bytes1);
         }else if("float".equals(strArr[i])){
             strs[i] = String.valueOf(byteToFloat(bytes1,0));
         }else if("systime".equals(strArr[i])){
             strs[i] = bytesToChar(bytes1);
         }
     }
     System.out.println("二进制数据转化后的结果:"+ Arrays.toString(strs));
    
     // 前六个int数值
     String[] str = new String[6];
     for(int i =0,j=0;j<24;i++){
         str[i] = String.valueOf(bytesToInt(bytes,j));
         j = j+4;
     }
     System.out.println("str:"+ Arrays.toString(str));
    
     //第七个试验名称
     byte[] bytes1 = new byte[56];
     System.arraycopy(bytes, 24, bytes1, 0, 56);
    

// for(int i=0;i<56;i++){
// bytes1[i] = bytes[20+i];
// }
log.info(“试验名称字节数组为:{}”, bytes1);
String str1 = bytesToChar(bytes1);
System.out.println(“试验名称str1:”+str1);

    //第八个通道名称
    byte[] bytes2 = new byte[24];
    System.arraycopy(bytes, 80, bytes2, 0, 24);

// for(int i=0;i<56;i++){
// bytes1[i] = bytes[20+i];
// }
log.info(“通道名称字节数组为:{}”, bytes2);
String str2 = bytesToChar(bytes2);
System.out.println(“通道名称str2:”+str2);

    //第九个采集名称
    byte[] bytes3 = new byte[56];
    System.arraycopy(bytes, 104, bytes3, 0, 56);

// for(int i=0;i<56;i++){
// bytes1[i] = bytes[20+i];
// }
log.info(“采集名称字节数组为:{}”, bytes3);
String str3 = bytesToChar(bytes3);
System.out.println(“采集名称str3:”+str3);

    System.out.println("服务端地址是:" + ctx.channel().remoteAddress());

}

public  int combine(byte b[])
{
    int t1=(b[3]&0xff)<<24;
    int t2=(b[2]&0xff)<<16;
    int t3=(b[1]&0xff)<<8;
    int t4=b[0]&0xff;
    //System.out.println(b[1]&0xff);//输出的是一个整形数据
    //在java中,设计int和比int位数来的小的类型b,如byte,char等,都是先把小类型扩展成int再来运算,
    //return( t1<<24)+(t2<<16)+(t3<<8)+t4;//必须加括号
    return t1+t2+t3+t4;
}

private char[] getChars (byte[] bytes) {

    Charset cs = Charset.forName ("GBK");

    ByteBuffer bb = ByteBuffer.allocate (bytes.length);

    bb.put (bytes);

    bb.flip ();

    CharBuffer cb = cs.decode (bb);

    return cb.array();

}

/**
 * byte转int
 * @Title: bytesToInt
 *
 * @param: @param src 源数组
 * @param: @param offset 起始偏移量
 * @return: int
 */
public int bytesToInt(byte[] src, int offset) {
    int value;
    value = src[offset] & 0xFF;
    value |= ((long) (src[offset + 1] & 0xFF) << 8);
    value |= ((long) (src[offset + 2] & 0xFF) << 16);
    value |= ((long) (src[offset + 3] & 0xFF) << 24);
    return value;
}

public String bytesToChar(byte[] bytes){
    char[] chars = new char[bytes.length];
    for (int i = 0; i < bytes.length; i++) {
        chars[i] = (char) (bytes[i] & 0xFF); // 使用位运算将字节转换为字符
    }

// for(int i =0;i<chars.length;i++){
// System.out.println(“char数组:”+chars[i]);
// }
String str = new String(chars);
// System.out.println(“转换后的字符数组:” + str);
return str;
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    log.info("关闭通道");
    cause.printStackTrace();
    ctx.close();
}

/**
 * byte转long
 * @Title: bytesToLong
 *
 * @param: @param src 源数组
 * @param: @param offset 起始偏移量
 * @return: long
 */
public static long bytesToLong(byte[] src, int offset) {
    long value = 0;
    for(int i = 0; i < 8; i++) {
        value |= ((long) (src[offset + i] & 0xFF) << (8 * i));
    }

    return value;
}
/**
 * byte转float
 * @Title: byteToFloat
 *
 * @param: @param src 源数组
 * @param: @param offset 起始偏移量
 * @return: float
 */
public static float byteToFloat(byte[] src, int offset) {
    int value;
    value = src[offset + 0] & 0xFF;
    value |= ((long) (src[offset + 1] & 0xFF) << 8);
    value |= ((long) (src[offset + 2] & 0xFF) << 16);
    value |= ((long) (src[offset + 3] & 0xFF) << 24);
    return Float.intBitsToFloat(value);
}

/**
 * byte转double
 * @Title: byteToDouble
 *
 * @param: @param src 源数组
 * @param: @param offset 起始偏移量
 * @return: double
 */
public static double byteToDouble(byte[] src, int offset) {
    long value = 0;
    for (int i = 0; i < 8; i++) {
        value |= ((long) (src[offset + i] & 0xff)) << (8 * i);
    }
    return Double.longBitsToDouble(value);
}


public static void main(String[] args){
    File file = new File("C:\\Users\\Administrator\\Desktop\\test.txt"); // 要读取的文件名
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "GBK"))) {
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

    try{
        String str = "hello";
        byte[] bytes = str.getBytes("GBK"); // 将字符串转换为字节数组
        String newStr = new String(bytes, "GBK"); // 将字节数组转换为字符串
        System.out.println("源字符串:"+str);
    }catch (Exception e){
        e.printStackTrace();
    }

}

}
注:其中c语言二进制字节码int、double、float型通过位运算皆可;
而string类型转换的时候存在乱码,此时我是通过通配符替换掉乱码的,就是除了中文、数字、特殊字符一律替换为空;
另外还有一个问题,就是netty的channel循环接收时,上一轮的字节数的最后不是字符的最后一位,这样下一轮的开头其实是一个字符剩下的部分,这时拼接转写也会出现为空的情况,这时java小端字节码编码方式造成的,只要规避即可。文章来源地址https://www.toymoban.com/news/detail-831142.html

到了这里,关于Springboot使用Netty连接Tcp接口(c语言二进制字节码转java字符串)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言文本模式和二进制模式

    本篇文章介绍一下C语言的文本模式和二进制模式 从宏观上看,无论是文本文件还是二进制文件,文件中保存的都是 0和1的序列 ,因为磁盘只有这两种状态。不同的文件只是对0、1序列的解释不同, 如果文件内容是以字符编码的方式保存到文件中的 ,无论是以哪种编码方式,

    2024年02月05日
    浏览(28)
  • 【c语言】二进制文件的读写操作

    创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡𖥦)!! 主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 🔥c语言系列专栏:c语言之路重点知识整合 🔥 给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ 本文基

    2024年02月12日
    浏览(31)
  • C#蓝牙连接及传输数据的三种方式(蓝牙传输文件、二进制数据)

          先下载InTheHand.Net.Personal.dll并在C#中引用,这个需要在网上下载      先看界面            这种方式优点是稳定性较强,基本无错误,就是偶尔需要提前蓝牙配对。        这种方式直接与蓝牙设备进行配对的时候会报错,请求的地址无效,这时候需要在被检测的蓝牙

    2024年02月11日
    浏览(62)
  • 【C语言】求二进制位中一的个数

    原题链接:牛客网 题目内容: 写一个函数返回参数二进制中 1 的个数,负数使用补码表示。 比如: 15    0000 1111    4 个 1 方法一: NumberOf1函数的实现比较简单,它使用了一个循环,不断将n除以2,并判断余数是否为1。如果余数为1,则说明n的二进制表示中最低位为1,计

    2024年02月09日
    浏览(23)
  • C语言二进制数据和16进制字符串互转

    知识点:结构体中的“伸缩型数组成员”(C99新增) C99新增了一个特性:伸缩型数组成员(flexible array member),利用这项特性声明的结构,其最后一个数组成员具有一些特性。第1个特性是,该数组不会立即存在。第2个特性是,使用这个伸缩型数组成员可以编写合适的代码,就

    2024年02月13日
    浏览(33)
  • 【初阶C语言】操作符1--对二进制的操作

    前言:本节内容介绍的操作符,操作的对象是二进制位。所以前面先介绍整数的二进制位 1.二进制介绍 (1)整数的二进制表示形式有三种:原码、反码和补码。 (2)原码、反码和补码的长度有数据类型来决定,如整数,就是四个字节,转化后是三十二位比特位,所以一个整

    2024年02月09日
    浏览(30)
  • 实战篇之基于二进制思想的用户标签系统(Mysql+SpringBoot)

            一: 计算机中的二进制         计算机以二进制表示数据,以表示电路中的正反。在二进制下,一个位只有 0 和 1 。逢二进一 位。类似十进制下,一个位只有 0~9 。逢十进一位。          二: 进制常用运算 (位运算) 与运算():将两个二进制数的对应

    2024年02月12日
    浏览(27)
  • SpringBoot中使用Netty实现TCP通讯,服务器主动向客户端发送数据

    Springboot项目的web服务后台,web服务运行在9100端口。 后台使用netty实现了TCP服务,运行在8000端口。 启动截图如下: 启动类修改: 服务器查看当前所有连接的客户端  服务器获取到所有客户单的ip地址及端口号后,即可通过其给指定客户端发送数据  

    2024年02月11日
    浏览(33)
  • 【0到1的设计之路】从C语言到二进制程序

    C程序如何从源代码生成指令序列(二进制可执行文件) 预处理 - 编译 - 汇编 - 链接 - 执行 方法: 阅读工具的日志(查看是否支持verbose, log等选项) 通过man gcc并搜索-I选项可得知头文件搜索的顺序 好的编程习惯 - 总是用括号包围参数 好的编程习惯 - 一个参数尽量不要展开多次 上述

    2024年01月23日
    浏览(33)
  • C语言:二进制、八进制、十六进制整数的书写及输出

    目录 一、整型数据类型 二、二进制、八进制、十六进制的书写 1)二进制 以 0b / 0B 开头,不区分大小写(数字0,而非字母o,下同) 2)八进制 以数字 0 开头         3)十六进制 以 0x / 0X 开头, 三、二进制、八进制和十六进制的输出 八进制   (%o): 十六进制   (%x):

    2024年02月05日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包