0

I'm working on a Android app that acts as TCP server/client i want to send data from the app to a server/client that is written in c/c++(made with the boost libraray). I have a normal Java function that calls a native c function for string converstion to bytes:

The function is defined as followed (the native function is 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();
    }  
}

The function ConvertString is a native function that converts the Java string to a C/C++ string and returns it as Java bytes, it is defined as followed:

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;
    }

}

When i run the program i get two 'AAAA' on the c side but not as a whole array ( so no 'AAAAAAAADD). I think the problem is that the server sends 2 'AAAA' and not the whole array at once. The client crashes with the following error:

'boost::exception_detail::clone_impl >' what(): read: End of file

Does the java server sends the data wrong? can anyone give me a suggestion? all feedback is welcome!

Roy08
  • 253
  • 2
  • 7
  • 21

1 Answers1

1

Are you willing to send the data or to make the JNI stuff work? In the former case, use Java to convert a string into UTF-8 (which will be ASCII for English.)

Conversion of text byte[] -> byte[] is not exactly what you need, but you'll get the idea:

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

For the 2nd case, I can share a portion of working code; it calls Java to convert from one encoding to another

// 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;
}

In the code that I have at hand I did not use jstrings, preferring the byte arrays.

18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
  • Hi, thanks for your answer! I want to make the JNI stuff work, the sending of string data is actually a stepping stone to my main goal. That is to send a Opencv Mat(native format) variabele form android to my TCP client for viewing. Do you have any suggestions? – Roy08 Jan 14 '14 at 09:34
  • Thank you!, is the code of the second case for the Mat variable problem? or my Original question? – Roy08 Jan 14 '14 at 10:46
  • The code is working code, but it does not solve your problem. It is just a piece of working code that uses SetByteArrayRegion() and GetByteArrayRegion(). The changeEncoding() JNI functions calls a java function that converts text from one encoding to another. It may be or not be useful for you. – 18446744073709551615 Jan 14 '14 at 11:13
  • Anyway, I think it is better to first get the TCP stuff working, then make the JNI stuff working. Or vice versa, but do not debug both at the same time. – 18446744073709551615 Jan 14 '14 at 11:21
  • Thanks i got the TCP working, tuns out that i did close the connection right after sending, so a second send operation would fail. Do you know if there is a way to convert a java bytebuffer to a native char buffer so that i can extract integer data? – Roy08 Jan 14 '14 at 11:26
  • _jbyte_ is _signed char_; _(mytype*)(void*)myPointer_ if gcc reports an error for _(mytype*)myPointer_ (at least that used to work a while ago) – 18446744073709551615 Jan 14 '14 at 11:38