The application is a basic chat client.
I got a Thread for getting data from the server.
I want to get every response from the server separately.
It prints in the console only when the loop breaks (when i send "exit" using the other parts of the application).
So when "System.out.println" responds it prints the whole buffer at once.
How can i make it work and print every response separately?
Thank you!
EDIT!!
The server respond should include "\n" after each line,
it works for me in this way.
Without "\n" it just waits until the loop breaks.
Is there a better way to do this without the "\n" issue?
class ServerThread implements Runnable {
#Override
public void run(){
BufferedReader in = null;
Socket socket;
try
{
if (Thread.currentThread().isAlive()) {
sendString("exit");
Thread.currentThread().interrupt();}
InetAddress serverAddress = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddress, SERVER_PORT);
outr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String serverResponse;
while((serverResponse = in.readLine()) != null)
{
System.out.println(serverResponse);
}
in.close();
outr.close();
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
You're using a BufferedReader and read it with in.readLine(), which, surprise surprise, will return the next line in the response. A line is a string terminated by a newline character, so your BufferedReader will have to wait until it sees a newline until it can return your line. If you don't want to use newlines in your response, don't use readLine(), use one of the other read() methods instead.
Related
Method to send message to peer:
public static void writeLineToPeer(Peer peer, String message) throws IOException
{
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(peer.getSocket().getOutputStream(), StandardCharsets.UTF_8));
writer.write(message + "\n");
writer.flush();
}
Reading the response:
public class PeersResponse extends Response<Peer>
{
public PeersResponse(InputStream stream) throws InvalidMessageException, IOException
{
super(stream);
parseResponse();
getNextElement();
}
#Override
protected void parseResponse() throws InvalidMessageException, IOException
{
BufferedReader reader = new BufferedReader(new InputStreamReader(this.stream, "UTF-8"));
setVersion(reader.readLine());
setAmount(reader.readLine());
//Fine until here
}
#Override
public Peer getNextElement() throws InvalidMessageException, IOException
{
BufferedReader reader = new BufferedReader(new InputStreamReader(this.stream, "UTF-8"));
String ip = reader.readLine();
//Socket exception: Socket is closed
if (NetworkHelper.isValidIPAddress(ip))
{
throw new InvalidMessageException();
}
String port = reader.readLine();
String typeOfPeer = reader.readLine();
if (typeOfPeer.length() != 1)
{
throw new InvalidMessageException();
}
try
{
return PeerFactory.getPeer(typeOfPeer.charAt(0), ip, Integer.parseInt(port));
}
catch (Exception ex)
{
throw new InvalidMessageException(ex);
}
}
}
As you can see I get a Socket exception: Socket is closed when trying to read from another instance of a
BufferedReader with the same InputStream.
The message that is being sent is fine and fits the structure of this class.
What's the cause of this? How can I fix this?
The first time you call reader.ReadLine() inside of parseResponse() the BufferedReader reads a chunk of data from the stream. It reads more than just one line, because it does not yet know where the end of line is. The only way for it to read (and remove) just one line from the socket would be to read characters one-by-one and stop when it sees the new line. But that would defeat the purpose of using BufferedReader in the first place.
The second time you call reader.ReadLine() inside of parseResponse(), it does not read from the underlying socket at all. It just parses the data already stored inside BufferedReader and returns the next line.
At the time parseResponse() exits, there is still data stored inside BufferedReader. As the reader variable goes out of scope, that data is lost. It cannot be read from the socket, because it has already been read from the socket.
TLDR;
You can step through parseResponse() in the debugger and look inside the reader instance (examine JDK's internal data structure). You will see your entire message there. And you will see how the remainder of your message gets lost when parseResponse() returns.
My team is building a basic HTTP server from scratch in Java, but our reader threads block once they run out of request text to read from the socket's input stream.
A number of points unique to our situation that don't match up with questions asked previously:
We want to keep the socket open while we process the request and produce a response to send back
We don't parse the data at first, but rather, we first read it off the socket and chuck the entire thing into a recovery file. Then we begin to parse and validate from the file, to ensure that we don't lose the request in case of disaster.
The basic code:
public void readSocket() {
receivedTime = System.currentTimeMillis();
requestFile = new File("recovery/" + receivedTime + ".txt");
try(
FileWriter fw = new FileWriter(requestFile);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(fw);
)
{
String line;
while((line = in.readLine()) != null){ //TODO: this is where it blocks after reading past the last line of the request.
out.write(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
readLine() returns null only if "the end of the stream has been reached", ie the socket has been closed by the other party. When readLine() reads a line break with no preceding data, it returns a non-null String that has a length of 0. So you need to fix you while loop accordingly:
public void readSocket() {
receivedTime = System.currentTimeMillis();
requestFile = new File("recovery/" + receivedTime + ".txt");
try(
FileWriter fw = new FileWriter(requestFile);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(fw);
)
{
String line;
// read request headers...
do {
line = in.readLine();
if (line == null) return; // socket closed
out.write(line);
out.NewLine();
out.flush();
if (line.isEmpty()) break; // end of headers reached
// process line as needed...
}
while (true);
// check received headers for presence of a message
// body, and read it if needed. Refer to RFC 2616
// Section 4.4 for details...
// process request as needed...
} catch (IOException e) {
e.printStackTrace();
}
}
Also see:
While reading from socket how to detect when the client is done sending the request?
Server Side:
try {
ServerSocket server_socket=new ServerSocket(port_number);
Socket client_socket= server_socket.accept();
PrintWriter output = new PrintWriter(client_socket.getOutputStream(),true);
BufferedReader input = new BufferedReader(new InputStreamReader(client_socket.getInputStream()));
BufferedReader stdIn=new BufferedReader(new InputStreamReader(System.in));
String userInput, clientOutput;
while ((userInput=stdIn.readLine())!="EXIT") {
if ((clientOutput=input.readLine())!=null) {
System.out.println("Client: "+clientOutput);
} if (userInput!=null) {
output.println(userInput);
output.flush();
}
}
}
Client Side:
try {
Socket client_socket= new Socket(hostname,port_number);
PrintWriter output = new PrintWriter(client_socket.getOutputStream(),true);
BufferedReader input = new BufferedReader(new InputStreamReader(client_socket.getInputStream()));
BufferedReader stdIn=new BufferedReader(new InputStreamReader(System.in));
String userInput,serverOutput;
while ((userInput=stdIn.readLine())!="EXIT") {
if ((serverOutput=input.readLine())!=null) {
System.out.println("Server: "+serverOutput);
} if (userInput!=null) {
output.println(userInput);
output.flush();
}
}
}
The code in my case makes sense to me, I cant seem to figure out why an enter still needs to be pressed, does it have something to do with .readLine()?
I checked out the following post Server Client in Java only displays message when I press enter, however the solution provided does not fix the situation.
Note: Initially there were no if statements in the while loop. The way I saw this to be an issue was that the while loop may get stuck on one of the lines, waiting for user/server input. Therefore implementing if statements allowed it to skip the waiting portion and re-run the loop.
Turns out I mixed my variables up.
The while loops should be:
while ((userInput=input.readLine())!="EXIT") {
It fixed it, but there are some other issues still present
does it have something to do with .getLine()?
Yes. If you look at the Javadoc for BufferedReader#readLine(), it clearly states that an end of line character terminates the String to be read:
Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.
I am building a server in Java, and the input feed is giving me trouble - its current setup cannot read more than one line, and it cannot read anything without "\n" at the end. Here is the current input loop:
BufferedReader input = new BufferedReader(new InputStreamReader(serverConnection.getInputStream()));
if(input.ready()){
StringBuilder text = new StringBuilder();
String line;
while((line = input.readLine()) != null){
text.append(line);
System.out.println(line);
}
sentData = text.toString();
return true;
}
My current loop using a BufferedReader cannot read more than one line of incoming data, and if there is no newline character, a timeout exception is thrown (I programmed it to do that), and the data is not read at all. It is, of course, unacceptable to have a listener that can only see one line of data, and stalls when the sent data is not formatted properly.
So I am looking for a method that allows the program to read any number of lines, and for the program to stop reading when it has reached the end of the data stream (even without a new line).
Any help is appreciated.
You're throwing away every odd-numbered line. Remove the readLine() inside the loop.
You can read from the InputStream directly into the StringBuilder. readLine() of BufferedReader will wait for \r or \n character. This looks like stalling.
int ch;
StringBuilder text = new StringBuilder();
while((ch = serverConnection.getInputStream().read())!= -1) { // -1 will be read at EOS
text.append((char)ch);
}
sentData = text.toString();
return true;
Update
The following piece of code is to demonstrate the difference between usage of BufferedReader and InputStream to read bytes and what is available to the user during read operation. BufferedReader will always give you lines which are either terminated by line breaks or by EOS. Whereas InputStream will make the available bytes to the user.
In scenarios where it is NOT necessary to close the streams, and the bytes transferred has it's own way to mark start and end of packets/messages, you will be using InputStream to read bytes. If you try using BufferedReader for these applications, the last line of the message will be made available once the server receives the next packet/message, unless you send each line with a line-break.
public static void main(String[] args) throws Exception {
new Thread(new BufferedReaderServer()).start();
new Thread(new InputStreamServer()).start();
final String requestString = "Line#1\nLine#2";
System.out.println("\nSending to BufferedReaderServer");
Socket clientSocket1 = new Socket(InetAddress.getLocalHost()
.getHostAddress(), 8003);
OutputStream outputStream1 = clientSocket1.getOutputStream();
outputStream1.write(requestString.getBytes());
Thread.sleep(6000);
outputStream1.close();
clientSocket1.close();
Thread.sleep(1000);
System.out.println("\nSending to InputStreamServer");
Socket clientSocket2 = new Socket(InetAddress.getLocalHost()
.getHostAddress(), 8004);
OutputStream outputStream2 = clientSocket2.getOutputStream();
outputStream2.write(requestString.getBytes());
Thread.sleep(6000);
outputStream2.close();
clientSocket2.close();
}
static class BufferedReaderServer implements Runnable {
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8003);
Socket socket = serverSocket.accept();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String s = null;
System.out.println("BufferedReaderServer read START");
while ((s = bufferedReader.readLine()) != null) {
System.out.println(s);
}
System.out.println("BufferedReaderServer read END");
socket.getInputStream().close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
static class InputStreamServer implements Runnable {
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8004);
Socket socket = serverSocket.accept();
System.out.println("InputStreamServer read START");
int ch;
while ((ch = socket.getInputStream().read()) != -1) {
System.out.print((char) ch);
}
System.out.println("\nInputStreamServer read END");
socket.getInputStream().close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
The issue what is being faced here could be due to non-closing of client socket. Depends on the user's application
I have a server that communicates with a client.
The server is multithreaded, and this thread is created with the socket and a bufferedreader connected to the socket, when the first line read from the socket is "request":
public class scriptComm implements Runnable {
private Socket sock;
private Socket sock2;
private Connection connection;
private BufferedReader reader;
#Override
public void run() {
try {
String name = reader.readLine();
String password = reader.readLine();
String line;
connection = methods.connectToDatabase();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
if (connection != null && name != null && password != null) {
try {
ResultSet rs = connection.createStatement().executeQuery(
"SELECT name, password, doupdate FROM accounts "
+ "WHERE name = '" + name + "' AND doupdate = 'yes'"
+ " AND password = '" + password + "'");
if (rs.next()) {
methods.log("worked");
bw.write("accept");
bw.flush();
bw.close();
reader = new BufferedReader(new InputStreamReader(sock2.getInputStream()));
if ((line = reader.readLine()) != null) {
mainFrame.jTextArea1.append("line \n");
connection.createStatement().executeUpdate(
"UPDATE accounts SET updatetext = '" + line + "' "
+ "WHERE name = '" + name + "'");
}else{
mainFrame.jTextArea1.append("No text received \n");
}
} else {
bw.write("decline");
bw.flush();
}
bw.close();
rs.close();
} catch (SQLException ex) {
methods.log("Error when executing statement in scriptComm");
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
} else {
methods.log("missing values in scriptComm");
}
} catch (IOException ex) {
}
}
public scriptComm(Socket sock, BufferedReader reader) {
this.sock = sock;
this.sock2 = sock;
this.reader = reader;
}}
You may notice that I close the bw stream after it writes "accept".
This is due to the client simply hanging there, as if it doesn't receive any input, when the stream is not closed.
The client:
try{
String line;
Socket sock = new Socket("myipaddresshere",portnumber);
PrintWriter writer = new PrintWriter(sock.getOutputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
writer.println("script");
writer.flush();
writer.println(jTextField1.getText());
writer.flush();
writer.println(jTextField2.getText());
writer.flush();
if ((reader.readLine()).equals("accept")) {
writer.write("testing123");
writer.flush();
writer.close();
} else {
jTextArea1.append("fail");
}
reader.close();
writer.close();
}catch(IOException e){
jTextArea1.append("Server not available. Please try again later.");
}
When the stream is not closed after writing "accept" from the server, it's as if the client just sits at the if(reader.readLine().equals("accept")) boolean check ( and yes, the stream is flushed server-side ).
However, when the stream is also closed server-side, it passes the boolean check and continues on to write the line "testing123" to the stream. The server can obviously not read this line as the socket stream was closed when the BufferedReader closed. As you may notice, I tried replicating the socket by simply creating another variable called sock2, but it seems this connection closes as well (makes sense).
Note: when connecting with a wrong user/pass (i.e. when rs.next() returns false), it does write "decline" to the stream and the client gets this.
Really confused about this one..
Thanks,
Mike.
Note, a write doesn't write a newline, and you are trying to read whole lines. You need to write a newline character before you flush.
Edither use BufferedWriter.newLine() or append "\n" to the strings that you write.
I'll leave this retracted with a piece of advice:
When you want to write characters to a stream, you should always use an OutputStreamWriter and InputStreamReader with an explicit character encoding. I recommend "UTF-8".
As written, your code will both write and read with the platform-default encoding. Which will work, right up until the time you have someone in China running the client on Windows, with someone in the US running the server on Linux (and depending on what you're sending, it could break much sooner).