Отправка Java UUID в C ++ в виде байтов и обратно по TCP - PullRequest
3 голосов
/ 28 июня 2009

Я пытаюсь отправить Java UUID на C ++, где он будет использоваться в качестве GUID, затем отправить его обратно и увидеть его как UUID, и я надеюсь отправить его всего 16 байтами.

Какие-нибудь предложения по простому способу сделать это?

У меня есть сложный способ сделать это, отправив из Java в C ++, где я спрашиваю UUID о его наименее и наиболее значимых битах, записываю это в ByteBuffer, а затем считываю как байты.

Вот мой глупо сложный способ получить 2 длинных из UUID и отправить их в C ++:

Java

public static byte[] asByteArray(UUID uuid) 
 {
    long msb = uuid.getMostSignificantBits();
    long lsb = uuid.getLeastSignificantBits();
    byte[] buffer = new byte[16];

    for (int i = 0; i < 8; i++) {
            buffer[i] = (byte) (msb >>> 8 * (7 - i));
    }
    for (int i = 8; i < 16; i++) {
            buffer[i] = (byte) (lsb >>> 8 * (7 - i));
    }

    return buffer;

}




    byte[] bytesOriginal = asByteArray(uuid);
    byte[] bytes = new byte[16];

    // Reverse the first 4 bytes
    bytes[0] = bytesOriginal[3];
    bytes[1] = bytesOriginal[2];
    bytes[2] = bytesOriginal[1];
    bytes[3] = bytesOriginal[0];
    // Reverse 6th and 7th
    bytes[4] = bytesOriginal[5];
    bytes[5] = bytesOriginal[4];
    // Reverse 8th and 9th
    bytes[6] = bytesOriginal[7];
    bytes[7] = bytesOriginal[6];                                 
    // Copy the rest straight up        
    for ( int i = 8; i < 16; i++ )
    {
        bytes[i] = bytesOriginal[i];
    }    

    // Use a ByteBuffer to switch our ENDIAN-ness
    java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(16);
    buffer.order(java.nio.ByteOrder.BIG_ENDIAN);
    buffer.put(bytes);
    buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
    buffer.position(0);

    UUIDComponents x = new UUIDComponents();

    x.id1 = buffer.getLong();
    x.id2 = buffer.getLong();

C ++

    google::protobuf::int64 id1 = id.id1();
    google::protobuf::int64 id2 = id.id2();

    char* pGuid = (char*) &guid;
    char* pGuidLast8Bytes = pGuid + 8;
    memcpy(pGuid, &id1, 8);
    memcpy(pGuidLast8Bytes, &id2, 8);

Это работает, но кажется слишком сложным, и я пока не могу заставить его работать в другом направлении.

(я использую буферы протокола Google для отправки двух длин и обратно)

  • Alex

Ответы [ 5 ]

2 голосов
/ 29 июня 2009

У меня что-то работает.

Вместо того, чтобы передавать его как два long, я отправляю его как байты, вот код Java:

public static UUID fromBytes( ByteString byteString)
{
    byte[] bytesOriginal = byteString.toByteArray();
    byte[] bytes = new byte[16];

    // Reverse the first 4 bytes
    bytes[0] = bytesOriginal[3];
    bytes[1] = bytesOriginal[2];
    bytes[2] = bytesOriginal[1];
    bytes[3] = bytesOriginal[0];
    // Reverse 6th and 7th
    bytes[4] = bytesOriginal[5];
    bytes[5] = bytesOriginal[4];
    // Reverse 8th and 9th
    bytes[6] = bytesOriginal[7];
    bytes[7] = bytesOriginal[6];                                 
    // Copy the rest straight up        
    for ( int i = 8; i < 16; i++ )
    {
        bytes[i] = bytesOriginal[i];
    }    

    return toUUID(bytes);
}

public static ByteString toBytes( UUID uuid )
{
    byte[] bytesOriginal = asByteArray(uuid);
    byte[] bytes = new byte[16];

    // Reverse the first 4 bytes
    bytes[0] = bytesOriginal[3];
    bytes[1] = bytesOriginal[2];
    bytes[2] = bytesOriginal[1];
    bytes[3] = bytesOriginal[0];
    // Reverse 6th and 7th
    bytes[4] = bytesOriginal[5];
    bytes[5] = bytesOriginal[4];
    // Reverse 8th and 9th
    bytes[6] = bytesOriginal[7];
    bytes[7] = bytesOriginal[6];                                 
    // Copy the rest straight up        
    for ( int i = 8; i < 16; i++ )
    {
        bytes[i] = bytesOriginal[i];
    }    

    return ByteString.copyFrom(bytes);
}


private static byte[] asByteArray(UUID uuid) 
 {
    long msb = uuid.getMostSignificantBits();
    long lsb = uuid.getLeastSignificantBits();
    byte[] buffer = new byte[16];

    for (int i = 0; i < 8; i++) {
            buffer[i] = (byte) (msb >>> 8 * (7 - i));
    }
    for (int i = 8; i < 16; i++) {
            buffer[i] = (byte) (lsb >>> 8 * (7 - i));
    }

    return buffer;

}

private static UUID toUUID(byte[] byteArray) {

    long msb = 0;
    long lsb = 0;
    for (int i = 0; i < 8; i++)
            msb = (msb << 8) | (byteArray[i] & 0xff);
    for (int i = 8; i < 16; i++)
            lsb = (lsb << 8) | (byteArray[i] & 0xff);
    UUID result = new UUID(msb, lsb);

    return result;
}

Делая это таким образом, байты можно использовать прямо на стороне C ++. Я полагаю, что переключение порядка байтов может быть сделано на или end.

C ++

    memcpy(&guid, data, 16);
1 голос
/ 10 февраля 2010

Вот что я делаю, чтобы преобразовать GUID C ++ в UUID Java. На стороне C ++ структура GUID просто конвертируется в байты. Преобразование в C ++ может затем идти в том же духе.

public static UUID cppGuidBytesToUuid(byte[] cppGuid) {
    ByteBuffer b = ByteBuffer.wrap(cppGuid);
    b.order(ByteOrder.LITTLE_ENDIAN);
    java.nio.ByteBuffer out = java.nio.ByteBuffer.allocate(16);
    out.order(ByteOrder.BIG_ENDIAN);
    out.putInt(b.getInt());
    out.putShort(b.getShort());
    out.putShort(b.getShort());
    out.put(b);
    out.position(0);
    return new UUID(out.getLong(), out.getLong());
}


// Here is the JNI code ;-)
jbyteArray GUID2ByteArray(JNIEnv *env,GUID* guid)
{
    if (guid == NULL)
    return NULL;
    jbyteArray jGUID = env->NewByteArray(sizeof(GUID));
    if (jGUID == NULL)
    return NULL;
    env->SetByteArrayRegion(jGUID,0,sizeof(GUID),(signed char*)(guid));
    if (env->ExceptionOccurred() != NULL)
    return NULL;
    return jGUID;
}
1 голос
/ 28 июня 2009

Ваш нынешний способ в порядке, нет ничего плохого в том, чтобы делать это таким образом. Другой подход - вы просто общаетесь со строковым представлением uuid, отправляете строку, анализируете ее в c ++.

Кстати, байты не имеют порядка байтов, если вы не приводите массив байтов / символов или не аналогичны целочисленным типам, вы просто определяете порядок байтов, присваивая байты обратно в порядке аппрейта.

1 голос
/ 28 июня 2009

Возможно, проще всего использовать getMostSignificantBits и getLeastSignificant биты, чтобы получить long значения и отправить их. Аналогичным образом вы можете восстановить UUID из этих двух длин, используя соответствующий конструктор.

Жаль, что нет пары методов toByteArray / fromByteArray: (

0 голосов
/ 28 июня 2009

Возможно, вы могли бы объяснить, почему вы не просто делаете.

UUID uuid = 
x.id1 = uuid.getMostSignificantBits();
x.id2 = uuid.getLeastSignificantBits();

P.S. Читая пост @Jon Skeet, я думаю, что это почти тот же совет. ;)

...