I've a test which fails because reading bytes from an InputStreamReader is going into infinite loop.
#Test
public void testSingleRequest() throws IOException {
Server server = new Server(9000, 100);
new Thread(server).start();
Socket clientSocket = new Socket("localhost", 9000);
OutputStream out = clientSocket.getOutputStream();
InputStream in = clientSocket.getInputStream();
String payload = "a";
byte[] load = buildPushPayload(payload);
out.write(load);
byte[] response = IOUtils.toByteArray(in);
server.stop();
assertEquals(0, response[0]);
}
This is the code that writes to the InputStream
byte[] resp = buildPushResponse();
output.write(resp);
private byte[] buildPushResponse() throws UnsupportedEncodingException {
ByteBuffer buffer = ByteBuffer.allocate(1);
buffer.order(ByteOrder.BIG_ENDIAN);
buffer.putInt(0);
return buffer.array();
}
Both the server and the client are write to the clientSocket Input Output stream.
I can't seem to understand why the infinite loop then?
What you are missing here is how to know when to stop reading. You are calling IOUtils.toByteArray(in) which will read until End Of File, which never happens (unless the other side closes their end of the socket).
There are a few schemes you can use to know how many bytes to read from the socket as a message packet before processing the complete message packet. For example, you could say that all packets are 8 bytes (in which case your read call would specify to read 8 bytes), you could say that the first byte is the count of bytes in the packet, you could say that a packet is variable length, and is terminated with a carriage return byte.
Once you have read a packet, you would normally process the packet and then go back to read another packet or close the socket if you're all done.
Here is a good example of socket programming: https://www.geeksforgeeks.org/socket-programming-in-java/
In that case, they are terminating a packet or message with an End Of Line mark - they are reading one line of text at a time with DataInputStream.readUTF(socket).
server = new ServerSocket(port);
socket = server.accept();
// Create a DataInputStream object that takes input from the socket
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
String message = "";
// reads messages from client and prints them
// The loop exits if the message "Over" is received.
try
{
while (!"Over".equals(message))
{
message = in.readUTF();
System.out.println(message);
}
}
catch(IOException i)
{
// handle error
}
// close connection
socket.close();
in.close();
I am trying to implement a client-server application by myself. Its working so far, except the fact, that when I am accessing the port via another application (e.g. Web-Browser) the server application is blocking.
Is there any easy way/good practice to check, if the connecting application is the "client application"?
Here is an short example for a socket listening to port 8080. The socket awaits 2 Strings. If you now connect with the browser (localhost:8080) the connection gets established, but is waiting for the first UTF8.
public class MainSocket {
public static void main(String[] args) {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(8080);
while (true) {
try {
Socket clientSocket = serverSocket.accept();
System.out.println("Connection established");
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
System.out.println(in.readUTF());
System.out.println(in.readUTF());
in.close();
clientSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
You're calling DataInputStream.readUTF8. That expects data like this:
First, two bytes are read and used to construct an unsigned 16-bit integer in exactly the manner of the readUnsignedShort method . This integer value is called the UTF length and specifies the number of additional bytes to be read. These bytes are then converted to characters by considering them in groups. The length of each group is computed from the value of the first byte of the group. The byte following a group, if any, is the first byte of the next group.
(etc)
In other words, this isn't just UTF-8. It's a slight variation on UTF-8 with a length prefix. That's not what a browser is going to write to the connection. Basically, DataInput and DataOutput are symmetric but not entirely general-purpose - they're usually used together, with one side reading via DataInput what the other side has written with DataOutput.
If you just want to read lines of UTF-8, you can use:
try (Reader inputReader = new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(inputReader)) {
System.out.println(read.readLine());
System.out.println(read.readLine());
}
(Now it's not at all clear that you should expect a browser to write UTF-8 to the socket either, but the above is more likely to get you to the next step, I'd say...)
I have created a server by using ServerSocket. After that, I have created Client using Socket, and connect to this server.
After that, I do "some stuff" with InputStream and OutputStream is taken from Socket Object. But, I don't really understand inputStream and outputStream so much. Here is my simple code :
private Socket sock = null;
private InputStream sockInput = null;
private OutputStream sockOutput = null;
...
String msg = "Hello World";
byte[] buffer = null;
try {
sockOutput.write(msg.getBytes(), 0, test.length());
sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());
buffer = new byte[test.length()];
sockInput.read(buffer, 0, test.length());
System.out.println(new String(buffer));
sockInput.read(buffer, 0, test.length());
System.out.println(new String(buffer));
} catch (IOException e1) {
e1.printStackTrace();
}
The result will be : "Hello World" and "Hello StackOverFlow".
Here is server side code :
private int serverPort = 0;
private ServerSocket serverSock = null;
public VerySimpleServer(int serverPort) {
this.serverPort = serverPort;
try {
serverSock = new ServerSocket(this.serverPort);
}
catch (IOException e){
e.printStackTrace(System.err);
}
}
// All this method does is wait for some bytes from the
// connection, read them, then write them back again, until the
// socket is closed from the other side.
public void handleConnection(InputStream sockInput, OutputStream sockOutput) {
while(true) {
byte[] buf=new byte[1024];
int bytes_read = 0;
try {
// This call to read() will wait forever, until the
// program on the other side either sends some data,
// or closes the socket.
bytes_read = sockInput.read(buf, 0, buf.length);
// If the socket is closed, sockInput.read() will return -1.
if(bytes_read < 0) {
System.err.println("Server: Tried to read from socket, read() returned < 0, Closing socket.");
return;
}
System.err.println("Server: Received "+bytes_read
+" bytes, sending them back to client, data="
+(new String(buf, 0, bytes_read)));
sockOutput.write(buf, 0, bytes_read);
// This call to flush() is optional - we're saying go
// ahead and send the data now instead of buffering
// it.
sockOutput.flush();
}
catch (Exception e){
System.err.println("Exception reading from/writing to socket, e="+e);
e.printStackTrace(System.err);
return;
}
}
}
public void waitForConnections() {
Socket sock = null;
InputStream sockInput = null;
OutputStream sockOutput = null;
while (true) {
try {
// This method call, accept(), blocks and waits
// (forever if necessary) until some other program
// opens a socket connection to our server. When some
// other program opens a connection to our server,
// accept() creates a new socket to represent that
// connection and returns.
sock = serverSock.accept();
System.err.println("Server : Have accepted new socket.");
// From this point on, no new socket connections can
// be made to our server until we call accept() again.
sockInput = sock.getInputStream();
sockOutput = sock.getOutputStream();
}
catch (IOException e){
e.printStackTrace(System.err);
}
// Do something with the socket - read bytes from the
// socket and write them back to the socket until the
// other side closes the connection.
handleConnection(sockInput, sockOutput);
// Now we close the socket.
try {
System.err.println("Closing socket.");
sock.close();
}
catch (Exception e){
System.err.println("Exception while closing socket.");
e.printStackTrace(System.err);
}
System.err.println("Finished with socket, waiting for next connection.");
}
}
public static void main(String argv[]) {
int port = 54321;
VerySimpleServer server = new VerySimpleServer(port);
server.waitForConnections();
}
My question is :
When I use sockOutput.write and I can get back those message back by sockInput.read. So, those message has been saved, right? If this true, does it saved on Server I have created or just saved in some other thing such as Socket Object.
If I have written to socket String A1, A2,... An so I will receive A1, A2, ... An String respectively, right?
A socket is an abstraction that you use to talk to something across the network. See diagram below...
In Java, to send data via the socket, you get an OutputStream (1) from it, and write to the OutputStream (you output some data).
To read data from the socket, you get its InputStream, and read input from this second stream.
You can think of the streams as a pair of one-way pipes connected to a socket on the wall. What happens on the other side of the wall is not your problem!
In your case, the server has another socket (the other end of the connection) and another pair of streams. It uses its InputStream (2) to read from the network, and its OutputStream (3) to write the same data back across the network to your client, which reads it again via its InputStream (4) completing the round trip.
Client Server
1. OutputStream -->\ /--> 2. InputStream -->
Socket <--> network <--> ServerSocket |
4. InputStream <--/ \<--3. OutputStream <--
Updated: in reply to comment:
Note that the streams and sockets just send raw bytes; they have no notion of a "message" at this level of abstraction. So if you send X bytes and another X bytes, then read X bytes and read another X bytes, then your system behaves as if there are two messages, because that's how you've divided up the bytes.
If you send X bytes, and another X bytes, then read a reply of length 2X, then you might be able to read a single combined "message", but as you've noticed, the underlying implementation of the streams can choose when to deliver chunks of bytes, so it might return X bytes, then X bytes, later, or 2X at once, or 0.5X four times...
InputStream and OutputStream are two completely separate streams. What you write into one has no a priori relation to what you read from the other. The InputStream gives you whatever data the server decides to send to you. I would also like to comment on this piece of your code:
sockOutput.write(msg.getBytes(), 0, test.length());
sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());
You use the length of a string test (not shown in your code), which has nothing to do with the byte array you are passing as the first argument. This can cause an ArrayIndexOutOfBoundsException or truncation of your intended message.
Additional comments to your updated question
Reviewing your server-side code, it is not quite correctly written. You need to have try { handleConnection(...); } finally { socket.close(); } to ensure proper cleanup after an error, as well as when completing normally. Your code never closes anything on the server side.
Finally, and most critically, your entire code is written in a way that can result in a deadlock. Normally you need a separate thread to read and to write; otherwise the following may happen:
You attempt to write some data to the output;
The server reads it and tries to respond with data in your input;
But, since the buffers are too small, you don't manage to send everything because the server wants to first send something to you, then receive the rest; but you don't get to the receiving part before you have sent everything you've got.
I am sending data to a server in two steps:
1) Length of what I will send using byte[4]
2) Data.
The server listens to the exact length of the data (shipped first) and then replies.
So I listen to the InputStream and try to get the data.
My Problem:
Whatever I am doing I am getting only the stream I send, but the server definatly sends a new string.
It seems I cannot wait for a -1 (end of string), as the program would time out and I am sure the server does not send anything alike.
Therefore I am using inputStream.available() to find out how many bytes are left in the buffer.
Once I am sending inputStream.read() after reading all the data it will time out with "Network idle timeout".
But I need to listen to the inputStream to make sure I am not missing information.
Why am I only receiving the information I send and not what is send by the server?
How can I listen to the connection for new items coming in?
Here is my code:
private void sendData (byte[] sendBytes){
try {
os.write(sendBytes);
os.flush();
} catch (IOException ex) {
}
}
Please help
THD
This is how you normally read all data from a reader (until the other end closes):
//BufferedReader is
StringBuilder data = new StringBuilder();
char[] buffer = new char[1024 * 32];
int len = 0;
while ((len = is.read(buffer)) != -1) {
data.append(buffer, 0, len);
}
//data will on this line contain all code received from the server
I have an Android application where I'm trying to send a picture to a server. I did this using Base64 encoding and it worked quite well, but it took too much memory (and time) to encode the picture before sending it.
I'm trying to strip the Android application down to where it just simply sends the byte array and doesn't fiddle around with any kind of encoding scheme so it'll save as much memory and CPU cycles as possible.
This is what I would like the Android code to look like:
public String sendPicture(byte[] picture, String address) {
try {
Socket clientSocket = new Socket(address, 8000);
OutputStream out = clientSocket.getOutputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
out.write(picture);
return in.readLine();
}
catch(IOException ioe) {
Log.v("test", ioe.getMessage());
}
return " ";
}
The server is written in Java. How do I write the server code so I can properly retrieve the exact same byte array? My goal is to save as many CPU cycles on the Android as possible.
So far, all the methods I've tried resulted in corrupt data or a thrown exception.
Any help will be appreciated.
Try something like this:
public byte[] getPicture(InputStream in) {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int data;
while ((data = in.read())>=0) {
out.write(data);
}
return out.toByteArray();
} catch(IOException ioe) {
//handle it
}
return new byte[]{};
}
Based on Robert's and Zaki's comment, here is the modified code that should perform better.
public byte[] getPicture(InputStream in) {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int length = 0;
while ((length = in.read(data))!=-1) {
out.write(data,0,length);
}
return out.toByteArray();
} catch(IOException ioe) {
//handle it
}
return null;
}
If you want bi-directional communication, the server must know when you're ready - you should prepend a 4 byte length field to your sender side indicating the number of bytes to come.
On the server side you read the length and then stay listening until everything has arrived. Then you can reply your acknowledge string.
If it is enough to send only the picture, you can simply send the data and then close the connection. The server side is implemented as shown by #thejh.