I'm having the following problem in java: I am developing and app using java.net.Socket. It looks like that: There is a server with a thread which accepts and adds new client, and another thread which reads data from sockets and does "something" with it. Next to it there are clients. Client has data reader thread as well as a separate thread. I send the data as simple as:
socket.getOutputStream().write((content+"\n").getBytes());
on the client side and read it on the server like:
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String received;
while(true) {
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
received = reader.readLine();
if(received == null) {
break;
}
System.out.println("SERVER " + received);
increaseReceivedCounter(1);
} catch(SocketException e) {
break;
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
System.out.println("SERVER RECEIVED "+ getReceivedCounter() + " MESSAGES!");
}
Now I just set the client to send some amount of messages like this:
try {
int n = 1000;
System.out.println("sending "+ n +" messages to " + client);
for(int i=0 ; i<n ; ++i) {
socket.getOutputStream().write((content+"\n").getBytes());
}
System.out.println("done sending " + n + " messages");
} catch (IOException e) {
e.printStackTrace();
}
The problem is that not all of the messages are transferred to a server. I have been looking for some solution for this but didn't manage to achieve 100% reliability. Is it even possible? I also tried with read instead of readLine but the result is the same: sometimes even 90% data loss. I think while server is working on the received data it ignores incoming packets and they're just lost.
Edit
Sockets initializations:
serverSocket = new ServerSocket(Server.PORT);//PORT = 9876, whatever
for the data reader on server side:
socket = serverSocket.accept();
on the client:
socket = new Socket("127.0.0.1", Server.PORT)
This is not an 'efficiency issue'. It is a bug in your code.
The problem is that not all of the messages are transferred to a server.
No, the problem is that you are losing data at the server. This is because you keep recreating BufferedReaders. You should create it once for the life of the socket.
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Remove this line.
The way you have it, you will lose data every time the prior BufferedReader has, err, buffered.
You also need to close the socket.
Related
I've edited the code to explain that better.
I've got Android application, which is client and Java server. I'm trying to send info from client to server, process that information and send the result back to client.
I'm using BufferedReader, InputStreamReader and DataOutputStream to send and receive messages.
So my Client.java has this code:
try {
//Sending message to server
DataOutputStream outToServer = new DataOutputStream(sock.getOutputStream());
outToServer.writeBytes(messageString + '\n');
outToServer.flush();
} catch (IOException e) {
System.err.print(e);
}
try {
System.out.println("This line is showing");
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String res;
System.out.println("And this line is showing");
res=inFromServer.readLine();
System.out.println("But this never is");
System.out.println("Received: " + res); //This line is never printed in console
}catch (IOException e) {
System.out.println(e);
}
And my Server.java has this:
try{
System.out.println("Creating InputStream");
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String message = inFromClient.readLine();
System.out.println("Received: " + message); //correct string received
} catch (Exception ex) {
System.out.println("Creating InputStream failed");
System.err.print(ex);
}
try{
String response = "Response from server"
DataOutputStream outToClient = new DataOutputStream(clientSocket.getOutputStream());
outToClient.writeBytes(response + '\n');
outToClient.flush();
System.out.println("Sent to client: " + response); //correct string is showing in console
} catch(Exception ex) {
System.out.print("Error! " + ex);
}
The thing is that my server gets the message correctly, as understandable string. It shows in console what it's sending to client and that also is understandable string.
But when I'm trying to get the message at client it does nothing.
inFromServer.readline() isn't throwing any exception to console and I don't know why it's not working.
I tried inFromServer.toString(), and then I received something, but it definitely wasn't the string sent from server. It was something like:
java.io.BufferedReader#b3d109a0
I don't know what I'm doing wrong. The sending/receiving function is called from login function, which is called from onPostExecute. I don't know how can do this from doInBackground.
BufferedReader.readLine() isn't working
Oh yes it is. Your error is in trying to convert the reader into a string, instead of using the line that was read.
Yo should remove the ready() test. It is pointless.
You should also use symmetrical streams. If you use Readersat one end you should use Writers at the other, such as BufferedWriter. Not DataOutputStream.
I suggest that this isn't the real code, and that there isn't a \n on the end of the sent message, which would explain readLine() blocking until the non-existent line terminator arrives, but you should redo this using BufferedWriter instead of DataOutputStream as mentioned above.
I wanted to send/receive continuous stream of data from one endpoint to another(peer2peer) with push and pull 'able asynchronously
So to first solve communication , I started with jax-ws soap binding webservice since it has an endpoint and ws-addressing for push mechanism but it seems to be a lot of overhead (heavy as per the docs and since unfamiliar with ws-*, I haven't implemented it , as I need multiple clients listening to the stream at a later point and the stream is 24/7 I wanted thread manageable sockets).
Then I took jax-rs but it does not include ws-addressing in it.(jax-rs 2.0)
I also looked at websockets but it required an app server but I want a jvm supportable code
So, Now I am trying to use basic sockets but the problem I am having is streaming the data through socket at server and client receiving it continuously.
It is working for the first read but no further.
Secondly, how can I make it asynchronous?
public class sSocket {
public static void main(String args[]) throws IOException{
int i = 15000;
ServerSocket ss;
Socket socket = null;
ss = new ServerSocket(i);
try
{
socket = ss.accept();
socket.setKeepAlive(true);
int iii = 0;
System.out.println("New connection accepted " + socket.getInetAddress() + ":" + socket.getPort());
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter output = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
while(iii<9)
{
Thread.sleep(2000);
output.write("good" + iii + "\n");
//System.out.print(input.readLine().toString());
output.flush();
iii++;
}
//socket.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
public class cSocket {
public static void main(String args[]) throws InterruptedException, IOException{
Socket client = new Socket("127.0.0.1", 15000);
try{
client.setKeepAlive(true);
DataOutputStream out = new DataOutputStream(client.getOutputStream());
out.writeBytes("Hi Server! I'm " + client.getLocalSocketAddress() + "\n" );
BufferedReader input = new BufferedReader(new InputStreamReader(client.getInputStream()));
String s;
while(true){
if((s = input.readLine()) != null)
{
System.out.println("Message from Server: " + s);
}}
//client.close();
}
catch(Exception e){
e.printStackTrace();
}
}
}
[toString() unavailable - no suspended threads] I see this halting the code in eclipse.
The problem seems to be essentially rooted in the input.readLine() in client: error is connection reset : which I assume is because readLine() has reached "EOF"
Don't keep creating new streams. Use the same ones for the life of the socket, at both ends. You're losing data in the buffers.
You don't need to keep calling setKeepalive(). Once is enough.
I'm building a Java client application which needs to send a message to a server and receive a response afterwards. I can send the message successfully, the problem is that I can't get the response because I get an IO exception ("Socked is closed") when trying to read the 'BufferedReader'.
This is my code, so far:
public class MyClass {
/**
* #param args the command line arguments
*/
#SuppressWarnings("empty-statement")
public static void main(String[] args) {
JSONObject j = new JSONObject();
try {
j.put("comando", 1);
j.put("versao", 1);
j.put("senha", "c4ca4238a0b923820dcc509a6f75849b");
j.put("usuario", "1");
j.put("deviceId", "1");
} catch (JSONException ex) {
System.out.println("JSON Exception reached");
}
String LoginString = "{comando':1,'versao':1,'senha':'c4ca4238a0b923820dcc509a6f75849b','usuario':'1','deviceId':'1'}";
try {
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
Socket clientSocket = new Socket("10.1.1.12", 3333);
System.out.println("Connected to the server successfully");
PrintWriter outToServer = new PrintWriter(clientSocket.getOutputStream(),true);
outToServer.println(j.toString());
outToServer.close();
System.out.println("TO SERVER: " + j.toString());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String resposta = inFromServer.readLine();
System.out.println("FROM SERVER: " + resposta);
clientSocket.close();
} catch (UnknownHostException ex) {
System.out.println("Could not connect to the server [Unknown exception]");
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
I know that the socket is being closed because of the OutToServer.close() but closing the stream is the only way to send the message. How should I approach this situation?
flush() is not the case when it comes with new PrintWriter(, true).
The real problem is that you are closing the PrintWriter outToServer which wraps the underlying InputStream, again, came from the Socket.
When you close the outToServer you're closing the whole socket.
You have to use Socket#shutdownOutput().
You don't even have to close the output if you want to keep the socket's in/out channels for further communications.
flush() when you are done with any writeXXX. Those writeXXX practically don't mean you sent those bytes and characters to other side of the socket.
You may have to close the output, and output only, to signal the server that you sent all you had to send. This is really a matter of the server-side socket's desire.
final Socket socket = new Socket(...);
try {
final PrintStream out = new PrintStream(socket.getOutputStream());
// write here
out.flush(); // this is important.
socket.shutdownOutput(); // half closing
// socket is still alive
// read input here
} finally {
socket.close();
}
Try to call outToServer.flush()
That will try to flush the data from the buffer, although it still not guarantees that it will be sent.
I got to implement a chat in my application. Connection to a server is made using sockets. I should register to that server and the server will aknowledge that with a reply.
I have implemented this in a single method where I send the command using a BufferedWriter, and then start reading from the input stream until it tells me there is no more data.
I read properly the server reply. However, I never get the negative value from the second in.read call and thus my method stays blocked in the while loop (in the conditionnal statement where I make that call).
How should this be done with sockets? I usually do that with files or other input streams without problem.
If I should read only the bytes I am supposed to read, does that mean that I either have to:
Know in advance the length of the server response?
or make the server send a code to notify it has finished to send its response?
Currently I am doing the following:
private String sendSocketRequest(String request, boolean skipResponse) throws ChatException {
if (!isConnected()) openConnection();
try {
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()), 2048);
out.append(request);
out.flush();
out = null;
} catch (IOException e) {
LogHelper.error("Unable to send socket request: " + request, e);
throw new ChatException("Unable to send socket request: " + request, e);
}
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()), 2048);
StringBuffer response = new StringBuffer();
char[] buffer = new char[2048];
int charsRead = -1;
// >>>>>>>> This is where it gets blocked <<<<<<<<<
while ((charsRead = in.read(buffer)) >= 0) {
if (charsRead > 0) response.append(new String(buffer, 0, charsRead));
}
return response.toString();
} catch (IOException e) {
LogHelper.error("Unable to read socket response: " + request, e);
throw new ChatException("Unable to read socket response: " + request, e);
}
}
Connection to the server is made with the following method:
public synchronized void openConnection() throws ChatException {
try {
socket = new Socket(Constants.API_CHAT_SERVER_ADDRESS, Constants.API_CHAT_SERVER_PORT);
socket.setKeepAlive(true);
LogHelper.debug("CHAT >> Connected to the chat server: " + Constants.API_CHAT_SERVER_ADDRESS);
} catch (UnknownHostException e) {
LogHelper.error("Unable to open chat connection", e);
throw new ChatException("Unable to open chat connection", e);
} catch (IOException e) {
LogHelper.error("Unable to open chat connection", e);
throw new ChatException("Unable to open chat connection", e);
}
}
The amount of data to be sent/received over a socket based connection is protocol dependend and not known to the TCP/IP stack, but only to the application layer.
The protocol used is developer dependend ... ;-) so coming to your questions:
If I should read only the bytes I am supposed to read, does that mean that I either have to:
Know in advance the length of the server response?
Yes, this is one possibility.
or make the server send a code to notify it has finished to send its response?
Also yes, as this is another possibility. Common markers are \n or \r\n. The NUL/'\0' character also might make sense.
A third option is to prefix each data chunk with a constant number of bytes describing the amount of bytes to come.
Instead of dealing with bytes, maybe it's simpler handling instances of ad-hoc classes, like - for instance - a Message class:
The server:
// Streams
protected ObjectInputStream fromBuffer = null;
protected ObjectOutputStream toBuffer = null;
// Listening for a new connection
ServerSocket serverConn = new ServerSocket(TCP_PORT);
socket = serverConn.accept();
toBuffer = new ObjectOutputStream(socket.getOutputStream());
fromBuffer = new ObjectInputStream(socket.getInputStream());
// Receiving a new Message object
Message data = (Message)fromBuffer.readObject();
The client then sends a message by simply:
// Sending a message
Message data = new Message("Hello");
toBuffer.writeObject(data);
Message can be as complex as needed as long as its members implement Serializable interface.
I have a server/client chat room. When the client connects to the server, and sends a message, the client program prints out the message that it sent, but on another client program that is connected to the server, it does not print out until the user presses the 'enter' key.
On the client side:
try {
//Strings to hold messages in and out:
String userinput, serverinput;
//Getting input from the user:
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
//Messages from the server will be printed to the console, messages from console will be sent to the socket:
while(true) {
userinput = input.readLine();
serverout.println(username + "> " + userinput);
serverinput = clientin.readLine();
System.out.println(serverinput);
}
}
On the server side:
public void run() {
PrintWriter output = null;
BufferedReader input = null;
String message;
SchoolRoomServer server = new SchoolRoomServer();;
try {
//i/o for clients:
output = new PrintWriter(socket.getOutputStream());
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException ioe) {
System.err.println(ioe);
System.exit(1);
}
try {
while((message = input.readLine()) != null) {
server.showAll(message, output);
}
} catch (IOException ioe) {
System.err.println(ioe);
System.err.println("Damn errors.");
System.exit(1);
}
}
By the way- the server.showAll(message, output); method is this:
public void showAll(String msg, PrintWriter printwriter) {
for(int i = 0; i < listWriters.size(); i++) {
if(listWriters.get(i) != printwriter) {
listWriters.get(i).println(msg);
}
}
}
listWriters is an Arraylist of PrintWriters, which gets a PrintWriter associated with a client each time a new thread is made for that client.
So: any ideas on how to immediately print out messages?
Thank you for any help.
You are having the same problem as here. System.in doesn't return anything until the user pressed enter. Then you get the whole line to read.
Read on Socket & ServerSocket
Basically you need to establish a client socket which connects to a server socket then you need to pass the i/o streams between the two to print messages from the client to the server & vice-versa.