【乱码】记一次C#调用Java乱码

项目是使用 C# 写的,传输数据使用对方给的Java加密解密算法。直接使用C#写算法要研究对方的算法,耗时较长。
因此直接将jar包转成dll进行调用。

前言

   使用IKVM工具将Java生成的Jar包转成dll,使用C#进行调用,可以正常调用,但是遇到中文就会乱码。
以下将从 如何使用 IKVM工具解决乱码 两个方面介绍。


IKVM使用

一、Jar包生成dll

1.1、环境准备

  • IKVM工具下载,最好使用 ikvm-8.1.5717.0 是对应 JDK 1.8的,如果下载的版本低的话,可能会报错。
  • 把IKVM配置到环境变量中
    在这里插入图片描述

1.2、生成jar包

注意命名空间,在C#中会使用到这个空间:cn.hsaf.common.utils.HseEncAndDecUtil
在这里插入图片描述

1.3、生成dll

打开cmd,打开到jar包所在文件夹,使用命令 ikvmc -out:ybEnc.dll(要生成dll的名字) ybEnc.jar(jar包的名字) 即可生成dll。
在这里插入图片描述

1.4、C#中使用

  • 引用生成的dll
  • 需要额外引用ikvm安装包中的一些dll(没有仔细研究引用哪些,按需应用吧。。)
  • 可以直接使用命名空间.方法名 调用方法 如: cn.hsaf.common.utils.HseEncAndDecUtil.HelloWorld 。
    在这里插入图片描述

排查问题

二、解决乱码的几种尝试

2.1 C#中接收的有问题

一开始出现的时候,感觉直接在C#端转一下就行(因为之前在C#中http请求获取第三方返回数据时,尝试过,结果解决了), 比如可能接收的是GBK 或者 UTF-8 等之类的,在C#中调用后返回的字符串使用UTF-8 to ISO之类的,在网上搜了一堆,逐一试了都不好使,有点投机取巧了,而且这样试太盲目了。。

在这里插入图片描述

2.2 Java传过来的有问题

C#端解决不了,换种思路,那么会不会是 Java 中传过来的 字符串 本身就是乱码呢,接着找到三方给的java工程demo,在main 方法里 把入参写死 直接调用方法 使用sout 打印出参在控制台,控制台输出的也是正常的,中文不是乱码,加密串也可以正常解析出来。不过此时也验证了一点:demo是没有问题的,应该demo里的算法跟对方用的是一个东西(因为之前遇到过给的demo都有问题的),入参包括密钥也是对的 。。

在这里插入图片描述
既然demo没问题,那么我是不是可以看看Java端返回的串,是什么编码格式的,在C#端解一下就行了,然后找到了这个方法:

   public static String getEncoding(String str) {
        String encode = "GB2312";
        try {
            if (str.equals(new String(str.getBytes(encode), encode))) { //判断是不是GB2312
                String s = encode;
                return s; //是的话,返回“GB2312“,以下代码同理
            }
        } catch (Exception exception) {
        }
        encode = "ISO-8859-1";
        try {
            if (str.equals(new String(str.getBytes(encode), encode))) { //判断是不是ISO-8859-1
                String s1 = encode;
                return s1;
            }
        } catch (Exception exception1) {
        }
        encode = "UTF-8";
        try {
            if (str.equals(new String(str.getBytes(encode), encode))) { //判断是不是UTF-8
                String s2 = encode;
                return s2;
            }
        } catch (Exception exception2) {
        }
        encode = "GBK";
        try {
            if (str.equals(new String(str.getBytes(encode), encode))) { //判断是不是GBK
                String s3 = encode;
                return s3;
            }
        } catch (Exception exception3) {
        }
        return ""; //如果都不是,说明输入的内容不属于常见的编码格式。
    }

通过测试,发现返回的是GB2312,喜出望外,赶紧在C#中以GB2312接收试试,结果还是乱码。。

会不会是搞复杂了,如果我直接把结果返回出去呢,是不是直接返回中文C#那边也会乱码,然后尝试了下,kao,没有乱码(验证了一点 IKVM方式调用 一般情况下是没啥问题的),那是为啥呢,通过方法返回就乱码,直接返回字符串不乱码。

 

2.3 增加日志记录调用过程中哪里出现的乱码

奇了怪了,两边都没有问题,那问题还能出在哪里呢,这时我甚至开始怀疑是不是IKVM有bug转成dll后 不兼容之类的,毕竟这种方式算是 暴力破解算法。然后开始各种找 IKVM的资料,到网上搜,官网上找,都没有找到相关的论坛,灵机一动,从github上找找呢,通过 description readme 等方式找(参照下方的高级搜索) 也未找到相关资料。

in:name JPA stars:>1000 forks:>
in:readme JPA
in:description JPA language:java pushed:>2022-01-01 stars:>1000

到这里基本已经不知道从哪查起了,迷茫了C#,Java,IKVM都堵死了,是不是可以放弃了,已经没啥思路了,要不搞个SpringBoot给C#调用Http请求呢。。。

休息一会后又从头捋了下,再来最后一次尝试,假设IKVM是没有问题的,肯定还是代码的问题,应该是转成dll后有啥不兼容的地方(因为java里也试了下,输出出来是没问题的),想起了平时解决问题的断点法,这种jar生成dll的东西无法调试 但是为了看到代码的走向,可以加日志在认为有问题的代码下面加上日志(java工程写日志的小例子如下)。

    public static void info(String msg) {
        PrintStream outFile = null;
        try {
            //指向日志文件。FileOutputStream中append参数为true时,创建对象不会覆盖源文件,继续在文件的末尾追加写数据。
            outFile = new PrintStream(new FileOutputStream("F:\\src\\log\\log.txt", true));
            //改变输出方向,默认情况我们用System.out.println是会打印到控制台上.但是用了System.setOut,就会打印到你的文件中。参数必须为FileOutputStream类型。并且输入内容更为灵活。
            System.setOut(outFile);
            //日期当前时间
            Date time = new Date();
            //格式化日期
            SimpleDateFormat sdfTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //转换格式
            String strTime = sdfTime.format(time);
            //内容输出到指定文件中
            System.out.println(strTime + ":" + msg);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

认为有问题的地方加上日志写到文件里
在这里插入图片描述
经过测试发现2 的是没有问题的,输出的是正常的没有乱码,然后改成输出2的形式,C#调用,成功返回!!

简要总结下:平时C#接触的较多一些,打算从这个方向突破,结果失败,只好现学了IKVM 方式的调用,IKVM学会后 多了些尝试的方式,最后通过加断点的形式解决。也验证了一点,java直接跑跟C#调用dll 还是有一些区别的。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值