【问题标题】:Sending java string as c/c++ bytes将 java 字符串作为 c/c++ 字节发送
【发布时间】:2014-02-02 06:24:16
【问题描述】:

我正在开发一个充当 TCP 服务器/客户端的 Android 应用程序,我想将数据从应用程序发送到用 c/c++(使用 boost 库制作)编写的服务器/客户端。我有一个普通的 Java 函数,它调用本机 c 函数将字符串转换为字节:

函数定义如下(原生函数是Convert String:

// Send buffer, the method can be used by both client and server objects.
public void SendBuffer(String Buffer){

    try {
        // Convert char to string to byte
        byte[] Temp = new byte[10];

        String Teststring = "AAAAAAAABB";
        Temp = ConvertString(Teststring);

        //byte[] Temp = new String(Buffer).getBytes();

        // Get socket output stream
        OutputStream OutputBuffer = ClientSocket.getOutputStream();

        //Write byte data to outputstream
        OutputBuffer.write(Temp);  

        // Neatly flush and close the outputbuffer
        OutputBuffer.flush();
        OutputBuffer.close();
    } 
    catch (IOException e) {
        Log.e("TCPIPCommunicator: ", "Client: Failed to send", e);
        e.printStackTrace();
    }  
}

函数ConvertString是一个将Java字符串转换为C/C++字符串并以Java字节返回的native函数,定义如下:

JNIEXPORT jbyteArray JNICALL Java_com_example_communicationmoduleTCPIP_communicationmoduleTCPIP_ConvertString(
        JNIEnv * env, jobject,
        jstring Buffer)
{
        // Array to fill with data
        jbyteArray Array;

        // Init  java byte array
        Array = env->NewByteArray(10);

        const char* NewBuffer = env->GetStringUTFChars(Buffer, 0);


        // Set byte array region with the size of the SendData CommStruct.
        // Now we can send the data back.
        env->SetByteArrayRegion(Array, 0, 10, (jbyte*)NewBuffer);

        env->ReleaseStringUTFChars(Buffer, NewBuffer);


        // Return java array
        return Array;
    }

}

当我运行程序时,我在 c 端得到两个“AAAA”,但不是整个数组(所以没有“AAAAAAADD”)。我认为问题在于服务器一次发送 2 个“AAAA”而不是整个阵列。客户端崩溃并出现以下错误:

'boost::exception_detail::clone_impl >' what(): 读取:文件结束

java服务器发错数据了吗?谁能给我一个建议?欢迎所有反馈!

【问题讨论】:

    标签: java android c++ boost tcp


    【解决方案1】:

    您愿意发送数据还是让 JNI 工作正常? 在前一种情况下,使用 Java 将字符串转换为 UTF-8(英文为 ASCII)。

    文本 byte[] -> byte[] 的转换并不是你所需要的,但你会明白的:

    //byte[] result;
    //byte[] source;
    String s = new String(source,"UTF-8");
    result = s.getBytes("UTF-16LE");
    

    对于第二种情况,我可以分享一部分工作代码;它调用 Java 将一种编码转换为另一种编码

    // it returns NULL in the case of an exception
    // the returned memory is calloc()'d; it's the caller's responsibility to free() it.
    char* changeEncoding(const char*source, int len, int direction)
    {
        JNIEnv* env = threadUnsafeInfo.env;
        jobject obj = threadUnsafeInfo.obj;
    
        if (!source) {
        JNU_ThrowByName(env, "java/lang/NullPointerException", 0);
        return NULL;
        }
        jbyteArray srcArray = env->NewByteArray(len);
    
        jclass cls = env->FindClass("com/xyz/MyClass");
        jmethodID mid = env->GetMethodID(cls, "convert", "([BI)[B");
    
        if (mid != NULL && srcArray != NULL) {
        env->SetByteArrayRegion(srcArray, 0, len, (jbyte*)source);
        env->ExceptionClear();
    
        //jbyteArray resArray = (jbyteArray)env->CallStaticObjectMethod(cls, mid, srcArray, direction);
        jbyteArray resArray = (jbyteArray)env->CallObjectMethod(obj, mid, srcArray, direction);
        if(env->ExceptionOccurred()) {
            DLOG("exception in convert ([BI)[B");
            env->ExceptionDescribe();
            //env->ExceptionClear(); // ??
            return NULL;
        }
    
        int resultLen = env->GetArrayLength(resArray);
        char* result = (char*)calloc(2 + resultLen,1); // why 2: a bit of healthy paranoia ain't gonna hurt anyone
        if (result == 0) {
            JNU_ThrowByName(env, "java/lang/OutOfMemoryError", 0);
            return NULL;
        }
        env->GetByteArrayRegion(resArray, 0, resultLen, (jbyte *)result);
        env->DeleteLocalRef(cls);
        env->DeleteLocalRef(resArray);
        env->DeleteLocalRef(srcArray);
        return result;
        } else {
        JNU_ThrowByName(env, "java/lang/NullPointerException", 0);
        myassert(("method id = 0",0));
        }
        return NULL;
    }
    

    在我手头的代码中 我没有使用 jstrings,更喜欢字节数组。

    【讨论】:

    • 您好,感谢您的回答!我想让 JNI 的东西工作,字符串数据的发送实际上是我主要目标的垫脚石。即发送一个 Opencv Mat(native format) variabele form android 到我的 TCP 客户端进行查看。你有什么建议吗?
    • 谢谢!,是Mat变量问题的第二种情况的代码吗?还是我的原始问题?
    • 该代码是工作代码,但它不能解决您的问题。它只是一段使用 SetByteArrayRegion() 和 GetByteArrayRegion() 的工作代码。 changeEncoding() JNI 函数调用将文本从一种编码转换为另一种编码的 java 函数。它可能对你有用,也可能没用。
    • 无论如何,我认为最好先让 TCP 工作,然后让 JNI 工作。反之亦然,但不要同时调试两者。
    • 感谢我的 TCP 工作正常,我发现我确实在发送后关闭了连接,所以第二次发送操作会失败。你知道是否有办法将 java bytebuffer 转换为 native char buffer 以便我可以提取整数数据?
    猜你喜欢
    • 2010-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-05
    • 2010-10-15
    • 1970-01-01
    相关资源
    最近更新 更多