tags:

views:

517

answers:

7

A third party programm allows me to ask data from his ip:port. I ask the stuff via this classic code. Here is the constructor of my connection class:

public TcpConnection(String adress, Integer port) {
    this.adress = adress;
    this.port = port;
    try {
        socket = new Socket(adress, port);
    System.out.println("Opening connection");
        out = new PrintWriter(socket.getOutputStream(), true);
        InputStream r = new DataInputStream(socket.getInputStream());
        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    } catch (UnknownHostException e) {
        // TODO: handle exception
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Then I read my socket with in.read() in a while loop.

It allows me to read the socket int by int,but I need a finner granularity. (Some info in the answer are encoded in 2 bytes, some in bit, some in 64 bytes ....). So i need to read 2 byte, then a bit. then another bit, then 1 byte and inspect each bit of this byte.

First I was thinking : "Fine, I convert the int I get in a String Binary representation", ( via Integer.toBinaryString(whatIget) ) buts it's just stupid and error prone.

I'm sure I'm missing something to address this casual problem. Some idea ?

Edit2 : i remove the "when i read a int, i read 32 bit ( 4 bytes )" , because it's wrong and not the point of the question. Thus, Reader.read() read a int, if this method only read a byte, she's reading a 1/4 int ??!?

+2  A: 

No. read() reads 8 bits / 1 byte at a time.

You can get byte, word, int, long, utf-8 string etc. from DataInputStream if you use a DataInputStream typed reference further on. Have

DataInputStream r = new DataInputStream(socket.getInputStream());
r.readLong();
r.readShort();

instead of

InputStream r = new DataInputStream(socket.getInputStream());

However, for words, int and long the the 'Endiannes' of the data matters. DataInputStream combines bytes in Big endian format where as you might have your data in little endian format. You might need to swap the bytes in the short/int/long after you read from the DIS. This is where Integer.reverseBytes() and its friends come in handy.

If you need bit sized data retrieval (for example read 6 bits, then 4, then 12, etc) you might want to check out the answers to this recent question.

Edit: Removed the 8 bits as it is misleading in this context.

Edit 2: Rephrased my 3rd sentence.

kd304
The DataInputStream is the only clean solution, imho.
furtelwart
True. Edited my answer.
kd304
Thanks for the link to the recent question. That's totally what i whant, read number, and sometime theire on 1 byte. sometime on 1 byte, sometime on 8 bytes ( dont ask why... legacy system, can't modify anything )
Antoine Claval
The difficulty was : i read "3", wich is 11 in binary, but sould i add 6 zero ( 00000011 ) or more ( 0000000000000011 for exemple ). Now that i cant read bit by bit, it's easy.
Antoine Claval
Last question and i go to bed, how can i detect the "endiannes" of a bit flow ?
Antoine Claval
I think you need to observe the bit flow and the values you extract. For example the bit flow contains 011 it could mean 3 (msb-lsb direction) or it could mean 6 (lsb-msb direction).
kd304
+1  A: 

you can read int by int and the extract information via bitwise operators

dfa
Riiight. I totaly forget that. I will read a byte. Then explode it into 8 bit with mask. Any better way ?
Antoine Claval
+1  A: 

You should be using a BufferedInputStream to do your reading. The BufferedReader is for text data.

read() reads one byte at a time.

You don't have to worry about it.

Each call to read() will return one byte.

See the Javadocs for the read() method for InputStream.

Reads the next byte of data from the input stream.

jjnguy
A: 

You cannot read single bits from an InputStream. It's not possible, as you can see in the API definition of InputStream.read().

So encapsulate the answer in an DataInputStream and you will read every single peace of information out of it, as kd304 provided.

furtelwart
He is using a reader, that is the root cause of the problem.
jjnguy
Maybe he wants to decode strings some time during the data retrieval.
kd304
A: 

From the javadoc

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.

You can use your DataInputStream.readByte() to just get a byte.

Clint
the problem is, his read is from a reader...so its reading characters
jjnguy
He has two Objects on his InputStream, one of which is a DataInputStream.
Clint
his problem is coming w/ in.read(). Nor the datareader (r)
jjnguy
i want a bit. 1 or 0. Not a byte.
Antoine Claval
+1  A: 

You should not use a Reader (you have a BufferedReader) for this sort of data. From a DataInputStream (that you already use) you can get Bytes, Ints or many other types (with methods named readByte etc.). Single bits you cannot get, the data in streams is always at least a byte. That's no restriction special to Java, in other languages you are also restricted to read at least bytes from Sockets an files. If you need single bits from this, you need logical operations to extract them from bytes you have read.

Mnementh
thanks, your response was perfect. i choose kd304 over you because of the sweet link he provide to another thread.
Antoine Claval
+2  A: 

You can not read only a bit: socket/TCP/IP work with byte as the smallest unit.
You'll have to read the byte containing the bit and use some bit shifting/masking to get the value of one bit:

int byte = r.read();
boolean bit1 = (byte && 0x01) != 0;  // first bit (least significatn)
boolean bit2 = (byte && 0x02) != 0;  // second bit
boolean bit3 = (byte && 0x04) != 0;  // thrid bit
...
Carlos Heuberger