I have a TCP Server and Client in Java. The Server can send commands to the Client, the Client will then execute the command, for example: send an image to the Server.
Im sending the data with a bytearray and thats working.
But lets imagine, I want to send an image and a file separately. How would the Server supposed to know which is the right bytearray? Or if I want to make a VoiceChat (which needs to be sending bytearrays continously) and separately sending an image?
Thats my code send bytes:
Client.java
public void writeBytes(byte[] bytes, Socket socket) throws IOException {
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.write(bytes);
out.flush();
}
Thats my code to receive and convert them to an Image:
Server.java
public BufferedImage writeScreenshot(Socket socket, int length) throws IOException {
DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
byte[] buffer = new byte[length];
in.readFully(buffer);
return ImageIO.read(new ByteArrayInputStream(buffer));
}
You need to design a "protocol" for the communication. A protocol defines what are the messages that can be exchanged and how they are represented in the lower level data stream.
A quick and easy protocol is where you first send the length of the data you are going to send, and then the data:
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeInt(bytes.length);
out.write(bytes);
out.flush();
The receiver now has to read the length field:
DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
int length = in.readInt()
byte[] buffer = new byte[length];
in.readFully(buffer);
When you get to applications like voice chat, the protocol has to get more complex. Each message has to have metadata, like what type of data it contains: image or voice or something else. Also you would likely not want to design this protocol from scratch, but use something that already exists - for example the real-time streaming protocol (RTSP).
Related
I have a small J2ME app that should send some bytes to a socket and read response. However, when I close OutputStrean, the socket closes too, and I can't read response. I thought I could try OutputStream.flush();, but it does nothing.
Here is my readAll() method that should read data from OutputStream:
public final static String readAll(InputStream d) throws IOException {
ByteArrayOutputStream res = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int length;
while ((length = d.read(bytes)) != -1){
res.write(bytes, 0, length);
}
return new String(res.toByteArray(), "UTF-8");
}
You'll typically want to have a thread running in the background that handles actually sending and receiving data.
The data that is received should provide some way of determining when that particular chunk of data terminates. For example, the server might send back:
(long)length+(byte[])data
So from the stream you would read in take 8 bytes + whatever the length is, then you would use that data to construct an object that represents that message and your other thread would read in that data to decide what data it wants to send out.
In order to send data out you would effectively do the reverse, with a separate thread consuming objects that represent messages to be sent.
These are called message queues and you can read more about them here: https://en.wikipedia.org/wiki/Message_queue
I want to connect Android Device to external device via Socket. Socket Connect to external device successfully.
Now if any data require from external device then send request of byte packet data to socket below order. if external device receive data correct then send byte data in response.
Parameters : methodname(1 byte), payloadlength(2 byte), payload(2 byte).
Now My Code is...
Socket socket = new Socket("local exteranl device ip", 5000);
if(socket.isConnected()) {
int methodname = 5;
int payload = 2151;
int payloadLength = 2;
ByteBuffer buffer = ByteBuffer.allocate(3 + payloadLength); // 3 = for method name + length
buffer.order(ByteOrder.BIG_ENDIAN); // Just to be explicit
buffer.put((byte) methodname);
buffer.putShort((short) payloadLength);
buffer.putShort((short) payload);
buffer.rewind();
byte[] result = new byte[buffer.capacity()]; // Could also use result = buffer.array();
buffer.get(result);
DataOutputStream classOUTstream = new DataOutputStream(socket.getOutputStream());
// socket is already connected
classOUTstream.write(result);
classOUTstream.flush();
InputStream stream = socket.getInputStream();
byte[] data = new byte[100];
int count = stream.read(data);
}
Above Code is Android, i knowing only basic concept of java. i am getting -1 result in count.
can any one please suggest me or tell me my mistake?
You're doing this the hard way. Get rid of the ByteBuffer altogether and use all the methods of DataOutputStream. They are all big-endian. I can't see any mistake but clearly you must be sending something the peer didn't understand so he is closing the connection instead of sending a reply.
Note: Socket.isConnected() cannot possibly be false at the point you're testing it.
My client receive raw HTTP headers (including GET, POST, Multipart POST, etc.) and I want to send them to a server and get output.
But I don't want to parse whole request manually, then set all that parsed stuff to HttpClient...
Does an elegant way to do this (even something like code below)?
AGoodHttpClient response = new AGoodHttpClient(host, port, myHeaders);
InputStream in = response.getInputStream();
// ...
Edited
Let's say I have this code. How do I recognize EOS (-1 isn't working for HTTP/1.1). Is there a guaranteed way how to cut the connection, when transfer is done? I want something what will care about cutting a connection (something like HttpClient), but with direct access to sending headers (like outToServer.write(myHeaders)).
Socket connectionToServer = new Socket(host, port);
OutputStream outToServer = connectionToServer.getOutputStream();
outToServer.write(myHeaders.getBytes());
InputStream inputFromServer = connectionToServer.getInputStream();
byte[] buff = new byte[1024];
int count;
while ((count = inputFromServer.read(buff)) != -1) {
System.out.write(buff, 0, count);
}
Thanks for help!
I am writing a socket client in which I am sending data to server (using getOutputStream()),below is my code
this.wr = this.socket.getOutputStream();
wr.write(hexStringToByteArray(messageBody));
wr.flush();
The above is successfull able to send the data.
1) but when I try to read the response using
this.in = new ObjectInputStream(this.socket.getInputStream());
As I dont know what format the server is returning. Getting error at this line
"java.io.StreamCorruptedException: invalid stream header" .
I am not sure why ? I know the values that I will recieve will be in the hex format i.e
say 600185 would be as in 60 01 86 ....
Could any one please help me, to over come this error.
2) Also in case if I dont receive any response after certain duration, how to close the socket connection.
Thanking you all in advance.
ObjectInputStream expects a header in the stream that is written by ObjectOutputStream. So If you use one, you need to use both.
As your sample doesn't really need ObjectOutputStream, you may just want to not use ObjectInputStream.
something like:
public void doWrite(Socket socket, String messageBody) {
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
byte[] data = hexStringToByteArray(messageBody);
dos.writeInt(data.length);
dos.write(data);
dos.flush();
}
public String doRead(Socket socket) throws IOException {
DataInputStream dis = new DataInputStream(socket.getInputStream());
int len = dis.readInt();
byte[] data = new byte[len];
dis.read(data);
return byteArrayToHexString(data);
}
my assignment includes sending an image file using UDP service (using java I implemented that successfully). My professor asked to include:
"The exchanged data messages must also have a header part for the sender to include 16-bit message sequence number for duplicate filtering at the receiver end"
How to do this?
I assume to create your UDP packet, you are using a ByteArrayOutputStream to generate the data. If that is the case, just Wrap a DataOutputStream on top of that ByteArrayOutputStream, and call writeInt(somesequenceNumber) before writing the image data to the stream.
on the receive side, do the opposite, wrap a DataInputStream around a ByteArrayInputStream, and call readInt() to get the sequence number. From there you can check whether you have already received this packet.
Something like
Write Side
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(sequenceNumber++);
dos.writeInt(imageDataLength);
dos.write(imageData);
dos.flush();
byte[] udpPacketBytes = baos.toByteArray();
Read Side
ByteArrayInputStream bais = new ByteArrayInputStream(udpPacketBytes);
DataInputStream dis = new DataInputStream(bais);
int sequenceNumber = dis.readInt();
if (seenSequenceNumbers.add(Integer.valueOf(sequenceNumber)))
{
int imageLength = dis.readInt();
byte[] imageData = new byte[imageLength];
dis.read(imageData);
}
where seenSequenceNumbers is some Set
For a 16-bit value I would use DataOutputStream.writeShort() and DataInputSTream readShort()/readUnsignedShort(). writeInt() and readInt() are for 32-bit values. If you want to avoid duplicates, a 32-bit value may be a better choice in any case. ;)