문제

I have a requirement to send data from native program written in C through Sockets, namely the winsock interface. That data is then received by a java program. The Java program receives a packet of data of which it know the order and makes some processing. It takes the int received from the socket.Read() like client_socket.getInputStream().read()

A processing of that int data returned from the Read() is parsed to get the data types expected. Basically it is a slicing of the bulk data received. I can only assume that the read() functions reads 4 bytes at a time (the 32 bit java int size). So I proceed to separate that 4 bytes(8 bits not the Java type) into 4 Java shorts so i can correctly represent the unsigned values they represent. After i have the 4 shorts if i know i want eg a uint16, i just concatenate the 2 shorts

The problem is somewhere i am doing some wrong bit manipulation that is not working out as i thought it would. The C code and the Java code is below and its really simple even though it does not work. The output is something which i can't understand why it is the way it is.

0 0   0 0    0 1     0 0     0 2     0 0     0 3     0 0     0 4 {...}

The C code redacted the initialization part:

uint16_t buffer[255] = {};
uint16_t *current_pointer = buffer;
for(uint16_t index = 0; index < 255; index++) {
    *current_pointer = index;
    current_pointer++;
}
Write(client_socket, (char *)buffer, sizeof(buffer));

The java code also redacted:

public final short[] JavaIntToUint8Array(int unsigned_int) {
    return new short[] { (short)((unsigned_int & 0xFF000000L) >> 24),
                (short)((unsigned_int & 0x00FF0000L) >> 16),
                (short)((unsigned_int & 0x0000FF00L) >> 8),
                (short)((unsigned_int & 0x000000FFL))};
}
public final int[] JavaIntToUint16(int unsigned_int) {
    short uint8_array[] = JavaIntToUint8Array(unsigned_int);
    return new int[] { (int)(uint8_array[0] << 8) | (int)uint8_array[1],            
        (int)(uint8_array[2] << 8) | (int)(uint8_array[3]) };
}

...

while (index < 255) {
        read_data = data_input.read();
        System.out.print(" ");
        System.out.print(JavaIntToUint16(read_data)[0]);
        System.out.print(" ");
        System.out.print(JavaIntToUint16(read_data)[1]);
        System.out.print("\t");
        index++;

}
도움이 되었습니까?

해결책

The simplest approach to reading unsigned short numbers is to use DataInput.readUnsignedShort().

DataInputStream dis = new DataInputStream(data_input);
int num = dis.readUnsignedShort();

This uses big-endian or network endian. If you are using little endian (e.g. on an x86/x64 processor) you can change the byte order yourself or using ByteBuffer to do it.

// using NIO
SocketChannel sc = SocketChannel.open(new InetSocketAddress("localhost", 12345));
ByteBuffer bb = ByteBuffer.allocateDirect(32*1024).order(ByteBuffer.LITTE_ENDIAN));
while(sc.read(bb) >= 0) {
    bb.flip();
    while(bb.remaining() > 1) {
       int num = bb.getShort() & 0xFFFF;
    }
    bb.compact();
}

Do you really need to send a stream of unsigned short values? A more often used stream is a unsigned bytes and these are simpler.

다른 팁

I can only assume that the read() functions reads 4 bytes at a time (the 32 bit java int size)

No, you can't assume that. The documentation for InputStream.read() says :

public abstract int read() throws IOException

Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to 255. If no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.

A subclass must provide an implementation of this method.

Returns:
    the next byte of data, or -1 if the end of the stream is reached.
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top