I am building a client/server application and I am trying to send a String to the client from a server thread using a PrintWriter. I construct my PrintWriter like this:
// Instantiate a PrintWriterwith a correctly implemented
// client socket parameter, and autoflush set to true
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
Assume, further, that the client is reading from the input stream with a BufferedReader, that is instantiated as such:
BufferedReader in = new BufferedReader(new InputStreamReader(client.server.getInputStream()));
and the client gets messages from the server with:
String serverMessage = in.readLine();
As you can see, I've set autoflushing to true. Let's say, now, that I want to send a simple message to a client. If I execute the statement:
out.println("Message to client");
Then the message is successfully sent. However, if I execute the statement:
out.print("Message to client");
then the message is not sent. Also:
out.print("Message to client");
out.flush();
does not work either.
This is a problem because I need to send a message to a client in a terminal and have them be able to respond on the same line. How do I send a message, using a PrintWriter, so that it gets flushed/sent to the client, but it does not send a newline character?
In your case it seems like you are using BufferedReader#readLine() which will read characters until a newline character or the end of stream is reached, blocking in the meantime. As such, you'll need your server to write that new line character.
An alternative is to read bytes directly instead of relying on BufferedReader#readLine().
why doesn't using a carriage return work?
The newline character is system-dependent. On Windows it is \r\n. On linux it is \n. You can get that with
System.getProperty("line.separator")
but you will need to get the server's.
Related
I have a problem with a Java-Python Socket. My objective is to send a Json object from java application to python script via socket tcp and receive a response but the socket is blocked after Json sending. In the following there is my code:
try {
Socket socket = new Socket(dstAddress, dstPort);
is = new DataInputStream(socket.getInputStream());
os = new DataOutputStream(socket.getOutputStream());
PrintWriter pw = new PrintWriter(os, true);
pw.println(jsonObject.toString());
System.out.println("Send to the socket jsonObject.");
BufferedReader in = new BufferedReader(new InputStreamReader(is));
String response = in.readLine();
System.out.println("Response: " + response);
is.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
In the following lines the python code:
HOST = "192.168.1.101" #localhost
PORT = 7011
s = socket(AF_INET, SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
while (1):
print("\n\nAttending for client.....\n\n")
conn, addr = s.accept()
print("Connected by: " , addr)
data = ""
while 1:
temp = conn.recv(1024).decode()
if not temp:
break
data = data + temp
print("JSON Received!!!!!")
imageJson = {}
imageJson = json.loads(data)
# responding to the client
response = DbImages[elem[0]]
resp = "Prova"
conn.send(resp.encode())
If I terminate the java code (ctrl+C) the socket exit from block and json arrive to python. What is the problem? The problem seems to be in.readLine (). If I delete that statement then the socket works without blocks.
Your Python code is waiting for the Java side to finish and send EOF before responding (that’s what it means to recv until you get an empty bytes).
Your Java code is waiting for the Python side to respond before closing the socket.
So, they’re both waiting for each other.
Removing the readLine means the Java code is no longer waiting for anything, so it just hangs up on the Python code as soon as it’s done sending, which does make the problem go away—but it isn’t much of a solution if you actually needed a response.
So, what should they be doing? Well, there are a few different options.
Use a framed protocol, where the Java side either sends a “message-done” delimiter after each message or sends a header (with, e.g., the byte length of the message) before each one. So, the Python code can read until it has a complete message, instead of until EOF.
If you encode your JSON in compact format with everything but printable ASCII escaped, then the delimiter can just be a newline (at which point you’re using JSONlines as your protocol), and the Python code can use makefile on the socket and call readline instead of looping over recv.
Cheat and use JSON as if it were a framed protocol. It isn’t, but as long as the only top-level values you ever send are objects and arrays, it works. Then the Python code can use raw_decode (see the json module docs) after each receive until it succeeds.
If you’re only ever going to send a single message, you can just half-shutdown the socket (close the write end) from Java, and then Python will get its EOF and respond on the still-open other side of the socket. (This may sound hacky, but it’s actually perfectly common—it’s how web browsers traditionally work, although HTTP 1.1 made things a bit more complicated.)
Your response is not a line, as it doesn't seem to contain a line ending.
That means it readLine will read forever.
Try adding a newline to your response to make readLine happy:
resp = "Prova\n"
I have a made a socket connection between client and server. Everything is working good if i introduce the first comand on client, receiving the message i want from the server.
#server
public PrintWriter out;
out.println(res);
#client
public BufferedReader in = null;
String line;
line = in.readLine();
At the second time i run it won't show the message i send from server cause it will read \n so it will be an empty string. If i change this:
#server
out.println("\n"+res);
The first time i run now it will jump a line, printing just the \n. And the second time i run it will show the right message.
If i change now to:
out.println("\n\n"+res);
It will just show when i introduce something to send to the server and receive back after the 3rd time (the first 2 times it prints \n).
Don't know what to do to show always the message i send from the server. Any advice?
is there a way of knowing when or whether the flush() method of a BufferedOutputStream thread has finished successfully? In my case I'm using it for sending a simple string through a java.net.Socket. In the following code, the flush() method is run in parallel with the BufferedReader.read() method and the socket output is immediately blocked by the input read resulting in something that resembles a deadlock. What I would like to do is wait for the output to end, and then start reading the input.
Socket sk = new Socket("192.168.0.112", 3000);
BufferedOutputStream bo = new BufferedOutputStream(sk.getOutputStream());
bo.write(message.getBytes());
bo.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
String line = br.readLine();
if (line.equals("ack")) {
System.out.println("ack");
}
sk.close();
Update
ServerSocket:
ServerSocket ss = new ServerSocket(3000);
System.out.println("server socket open");
while (true) {
Socket sk = ss.accept();
System.out.println("new connection");
BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
String line = br.readLine();
System.out.println("received line: " + line);
BufferedOutputStream bo = new BufferedOutputStream(sk.getOutputStream());
bo.write("ack".getBytes()); bo.flush();
sk.close();
}
Update:
#Global Variable - the reason that read was blocking the socket is that it was waiting for the \n, indeed. Using
bo.write("ack\n".getBytes());
instead of
bo.write("ack".getBytes());
made it work.
Regarding the initial question, is there a way of knowing if flush() method has finished successfully, #Stephen C provided the answer:
there is no way to know that based on the Socket or OutputStream APIs.
The normal way to get that sort of assurance is to have the remote
application send an "reply" in response, and read it in the local
side.
This "reply" is implemented in the code sample and it works.
Is there a way of knowing when or whether the flush() method of a BufferedOutputStream thread has finished successfully?
It depends on what you mean by "finished successfully".
The flush() method ensures that all unsent data in the pipeline has been pushed as far as the operating system network stack. When that is done, then you could say that flush() has finished successfully. The way that you know that that has happened is that the flush() call returns.
On the other hand, if you want some assurance that the data has (all) been delivered to the remote machine, or that the remote application has read it (all) ... there is no way to know that based on the Socket or OutputStream APIs. The normal way to get that sort of assurance is to have the remote application send an "reply" in response, and read it in the local side.
In the following code, the flush() method is run in parallel with the BufferedReader.read() method and the socket output is immediately blocked by the input read resulting in something that resembles a deadlock.
The code that you are talking about is basically the correct approach. The way to wait for the response is to read it like that.
If it is not working, then you need to compare what the client and server side are doing:
Is the server waiting for the client to send something more? Maybe an end of line sequence?
Did the server sends the response?
Did it flush() the response?
A mismatch between what the client and server are doing can lead to a form or deadlock, but the solution is to fix the mismatch. Waiting for some kind of hypothetical confirmation of the flush() is not the answer.
UPDATE
The problem is indeed a mismatch. For example, the server writes "ack" but the client expects "ack\n". The same happens in the client -> server case ... unless message always ends with a newline.
Your code is reading reader.readLine() . Are your writing \n when writing? You may want to append \n to the string your are writing.
I tried to reproduce your problem. First, I ran in to some kind of blocking state too, until I realized, I was using readLine at Server-side, too. But the message I was sending did not have a concluding \n. Therefore, the serversocket was still waiting at its InputStream without sending the client the ACK through its OutputStream. I think, #Global Variable is right.
I am trying to learn socket programming. I wrote client using InputStreamReader and with BufferedReader I read the msg sent from server.
For server if I write PrintWriter with print method it works and with write method it's not, why?
And OutputStreamReader is not at all useful as it does not have print method and with write, I am not getting messages in client side.
Client:
Socket c=new Socket("143.22.165.27",6000);
InputStreamReader isr=new InputStreamReader(c.getInputStream());
BufferedReader br=new BufferedReader(isr);
String s=br.readLine();
System.out.println(s);
Server
Socket sock=s.accept();
OutputStreamWriter out =
new OutputStreamWriter(sock.getOutputStream());
out.write("...........");
I assume you are using the readLine() method on the client's BufferedReader. So my guess would be that you aren't writing any newline characters when you use the write() methods on the server. Thus, the client never reaches the end of a line. A PrintStream or a PrintWriter adds the newline characters for you whenever you call a println() method.
Of course, without any code or even a description of the problem, it's hard to say for sure.
You must use out.flush() every time when you want to sent portion of data via out.write(msg).
I'm writing a Java client/server application. It should allow clients to send text data to the server. This kind of communication should be repeatable many times using the same connection.
I write it like this:
// On a server:
ServerSocket serverSocket = new ServerSocket(port);
Socket socket = serverSocket.accept();
socket.setKeepAlive(true);
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
if (reader.ready()) {
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
// do something with line
}
}
// On a client:
Socket socket = new Socket(host, port);
socket.setKeepAlive(true);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("Some data from client to server");
writer.flush();
The problem is: I can't read on a server before I close OutputStream on a client. Or I can't open OutputStream on a client again, if it was already closed. How can I do continuous sending and reading of data?
You need two threads at both ends, one for reading data and other one for writing data.
The problem is: I can't read on a server before I close OutputStream on a client.
Yes you can. You just can't get to the case where readLine() returns null. It isn't the same thing.
Or I can't open OutputStream on a client again, if it was already closed.
Of course not. You have to create a new Socket.
How can I do continuous sending and receiving of data?
I don't understand the question. The code you posted doesn't attempt that.
If your goal is to send many mesages over the same socket connection, these messages will have to be delimited by an application-level protocol. In other words, you won't be able to rely on any system calls like reader.ready() or reader.readLine() == null to detect the end of the message on te server.
One way to achieve this is to begin each message with its length in characters. The server will then read exactly that number of charecters, and then stop and wait for a new message. Another is to define a special character sequence which concludes each message. The server will react to reading that particular sequence by ending the reading of the current message and returning to the "wait for new message" state. You must ensure that this sequence never appears in the message itself.