Reading multiple lines from server - java

I'm open for other ways to do this, but this is my code:
public class Client {
public static void main (String [] args) {
try(Socket socket = new Socket("localhost", 7789)) {
BufferedReader incoming = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter outgoing = new PrintWriter(socket.getOutputStream(),true);
StringBuilder sb = new StringBuilder();
Scanner scanner = new Scanner(System.in);
String send = "";
String response = "";
while (!send.equals("logout")){
System.out.println("Enter Command: ");
send = scanner.nextLine();
outgoing.println(send);
while ((response = incoming.readLine()) != null) {
System.out.println(response);
sb.append(response);
sb.append('\n');
}
}
} catch (IOException e) {
System.out.println("Client Error: "+ e.getMessage());
}
}
}
I do get response from the server, but the program is getting stuck in the inner while loop while ((response = incoming.readLine()) != null), so i can't enter a second command. how do i break the loop if the incoming response is done ?

The problem is that incoming.readLine() will only return null if the socket is closed, otherwise it will block and wait for more input from the server.
If you can change the server, you could add some marking that the request was fully processed and then check it like this while ((response = incoming.readLine()) != "--finished--").
If you cannot, try this:
while(response.isEmpty()){
if(incoming.ready()){ //check if there is stuff to read
while ((response = incoming.readLine()) != null){
System.out.println(response);
sb.append(response);
sb.append('\n');
}
}
}

Related

How to 'clean' InputStream without closing it?

Client code snippet. Basically it reads from standard input and sends message to the server.
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 1200)) {
OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.US_ASCII);
Scanner scanner = new Scanner(System.in);
for (String msg = scanner.nextLine(); !msg.equals("end"); msg = scanner.nextLine()) {
writer.write(msg + "\n");
writer.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Server code snippet. Prints a message from stream.
public void run() {
try (InputStreamReader reader = new InputStreamReader(this.socket.getInputStream(), StandardCharsets
.US_ASCII)) {
StringBuilder builder = new StringBuilder();
for (int c = reader.read(); c != -1; c = reader.read()) {
builder.append((char) c);
if ((char) c == '\n')
System.out.print(builder);
}
} catch (IOException e) {
e.printStackTrace();
}
}
Input from client:
Text1
Text2
Server output:
Text1
Text1
Text2
The problem I am facing that server prints not just received message but also all messages before it.
Question: How can I reset 'clean' InputStream without closing it. And if that is impossible what is preferred solution?
You don't need to 'clean' the stream--you just need to reset the buffer after every line. Try something like the following using StringBuilder.setLength:
if (c == '\n') {
System.out.print(builder.toString());
builder.setLength(0);
}
On the other hand, I'd strongly encourage not manually reading lines like that. Consider using a Scanner like you do in the client code or alternatively a BufferedReader.
try (final BufferedReader reader
= new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.US_ASCII))) {
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
System.out.println(line);
}
} catch (final IOException ex) {
ex.printStackTrace();
}

Why is the network Input stream not working more than once?

The network input stream works correctly in version 1 of the code below in that it continues to receive data messages from the server.
However, in version 2, only the first message is received and then nothing.
Why doesn't it work? Is there an alternative?
Version 1
public void run(){
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
int c;
while ((c = in.read()) != -1) {
System.out.print((char) c);
}
}catch (IOException e){
e.printStackTrace();
}
}
Version 2
public void run(){
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(true){
String msg = in.readLine();
System.out.println(msg);
}
}catch (IOException e){
e.printStackTrace();
}
}
Your second version won't work because you're not checking for end of stream. readLine() returns null at that point. It should be:
while ((line = in.readLine()) != null)
{
// ...
}
... and it will only return a line when it reads a line, including a line terminator. If you don't send lines it can't read lines.

Would there be a cleaner/better way to write this

The code is suppose to read information from a file, create a object using that information, and then adding it to an ArrayList called servers.
try {
BufferedReader br = new BufferedReader(new InputStreamReader(openFileInput(MainActivity.FILE_SERVERS)));
String line = "";
while ((line = br.readLine()) != null) {
String name = "";
String ip = "";
String port = "";
String checkFrequency = "";
int counter = 1;
boolean alert = true;
for (String value : line.split(",")){
if (counter == 1){
name = value;
}else if (counter == 2){
ip = value;
}else if (counter == 3){
port = value;
}else if (counter == 4){
checkFrequency = value;
}else if (counter == 5){
alert = Boolean.parseBoolean(value);
}
counter++;
}
MCServer server = new MCServer(name, ip, port, checkFrequency, alert);
servers.add(server);
}
br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Example line of what is stored in file:
Name,199.99.99.99,80,60,true
Would there be a better way to retrieve that information to be able to store it in the correct variable without using a loop with a counter the way shown above?
What about:
try (BufferedReader br = new BufferedReader(
new InputStreamReader(openFileInput(MainActivity.FILE_SERVERS)))) {
String line = null; // start with null in case there is no line
while ((line = br.readLine()) != null) {
String[] tokens = line.split(",");
MCServer server =
new MCServer(tokens[0], tokens[1], tokens[2], tokens[3],
Boolean.parseBoolean(tokens[4]));
servers.add(server);
}
}
You can just ignore the counter and use directly the tokens, but you should at least be sure there are enough tokens:
try
{
BufferedReader br = new BufferedReader(new InputStreamReader());
String line = null;
String[] tokens;
while ((line = br.readLine()) != null) {
tokens = line.split(",");
MCServer test = new MCServer(tokens[0],tokens[1],tokens[2],tokens[3],Boolean.valueOf(tokens[4]));
}
}
catch (IndexOutOfBoundsException e) { // <- be sure to catch this
// not enough elements in array
}
In addition you are passing strings as IP addresses and port, they are string but they should be checked against being convertible, so you could have Integer.valueOf(tokens[2]) for example just to raise a NumberFormatException in case.
Try this
try {
BufferedReader br = new BufferedReader(new InputStreamReader(openFileInput(MainActivity.FILE_SERVERS)));
String line = "";
while ((line = br.readLine()) != null) {
String name = "";
String ip = "";
String port = "";
String checkFrequency = "";
int counter = 1;
boolean alert = true;
String s[] = line.split(",");
name = s[0];
ip = s[1];
port = s[2];
checkFrequency= s[3];
alert = s[4];
MCServer server = new MCServer(name, ip, port, checkFrequency, alert);
servers.add(server);
}
br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
I've revised your code a bit:
try {
BufferedReader br = new BufferedReader(new InputStreamReader(openFileInput(MainActivity.FILE_SERVERS)));
String line;
while ((line = br.readLine()) != null) {
String[] lineSplitted = line.split(",");
String name = lineSplitted[0];
String ip = lineSplitted[1];
String port = lineSplitted[2];
String checkFrequency = lineSplitted[3];
boolean alert = Boolean.parseBoolean(lineSplitted[4]);
MCServer server = new MCServer(name, ip, port, checkFrequency, alert);
servers.add(server);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
Changes:
initialising the variables and then setting them is redundant, you never access them without setting them beforehand, so if you have your line splitted in the the first place you can initialise them with the values right away
for cycle is unnecessary if you're working with a single array each time, just access the correct elements of the array
catch blocks can be collapsed; IOException covers FileNotFoundException

double enter needed. why?

I'm facing a problem with a need to double "enter" in order for the program to proceed, can someone enlighten me?
public void run() {
try {
out.write("Enter message to encrypt: \n");
out.flush();
while (true) {
entry = in.readLine();
result = caesarCipher(entry);
out.write("The encrypted message is " + result);
out.write("\tType q to end else type another message to encrypt");
out.flush();
}
} catch (IOException e) {
System.out.println(e);
}
}
this is over at the client side
public EncryptClient() throws IOException {
Socket cSock = new Socket("LocalHost", portNumber);
Reader iRead = new InputStreamReader(cSock.getInputStream());
input = new BufferedReader(iRead);
userTerminal = new BufferedReader(new InputStreamReader(System.in));
output = new OutputStreamWriter(cSock.getOutputStream());
while (true) {
String line = input.readLine();
System.out.println(line);
line = userTerminal.readLine();
if (line.equals("q")) {
break;
}
output.write(line + "\n");
output.flush();
}
}
when my client class is connect to the server class, i will need to enter a message for encryption, but a double enter is needed to show the result. can someone enlighten me?
ReadLine will halt the control of flow.
In your code, they were two readLine
.readLine(); // (line string is overrided twice)duplicated. Remove it. You will be fine.

Java two- way socket connection (server/ client)

what I'm trying to do is to send some JSON from an Android phone to a Java server, which works fine. The Android/ client side looks like this:
Socket s = new Socket("192.168.0.36", 12390);
s.setSoTimeout(1500);
JSONObject json = new JSONObject();
json.put("emergency", false);
json.put("imei", imei);
json.put("lat", l.getLatitude());
json.put("lon", l.getLongitude());
json.put("acc", l.getAccuracy());
json.put("time", l.getTime());
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
out.write(json.toString());
out.flush();
s.close();
The server side is this:
try {
s = new ServerSocket(port);
}
catch (IOException e) {
System.out.println("Could not listen on port: " + port);
System.exit(-1);
}
Socket c = null;
while (true) {
try {
c = s.accept();
} catch (IOException e) {
System.out.println("Accept failed: " + port);
System.exit(-1);
}
try {
BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream()));
String inputLine = null;
String result = "";
while ((inputLine = in.readLine()) != null) {
result = result.concat(inputLine);
}
System.out.println(result);
As I said, all of that works. Now I want to send a message back from the server to the client after it received the message from the client.
I extended the code like this, Android/ client side:
Socket s = new Socket("192.168.0.36", 12390);
s.setSoTimeout(1500);
JSONObject json = new JSONObject();
json.put("emergency", false);
json.put("imei", imei);
json.put("lat", l.getLatitude());
json.put("lon", l.getLongitude());
json.put("acc", l.getAccuracy());
json.put("time", l.getTime());
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
out.write(json.toString());
out.flush();
String inputLine = null;
String result = "";
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
while ((inputLine = in.readLine()) != null) {
Log.d(TAG, in.readLine());
result = result.concat(inputLine);
}
And the server side:
try {
s = new ServerSocket(port);
}
catch (IOException e) {
System.out.println("Could not listen on port: " + port);
System.exit(-1);
}
Socket c = null;
while (true) {
try {
c = s.accept();
} catch (IOException e) {
System.out.println("Accept failed: " + port);
System.exit(-1);
}
try {
BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream()));
String inputLine = null;
String result = "";
while ((inputLine = in.readLine()) != null) {
result = result.concat(inputLine);
}
System.out.println(result);
PrintWriter out = new PrintWriter(c.getOutputStream());
out.write("Hello phone");
out.flush();
out.close();
On the client side, nothing ever comes in, it hangs on
while ((inputLine = in.readLine()) != null) {
Log.d(TAG, in.readLine());
result = result.concat(inputLine);
}
until the socket times out (never enters the loop). I thought it might be a timing problem, for example the server sending out its reply too early and therefore the client never receiving anything, but i tried to put the out.write("Hello phone"); pretty much anywhere in the code, always the same result. Can it have to do with the socket being obtained from ServerSocket and not being able to send out data? What am I missing here, this is bugging me all day ...
Edit: After Nikolais answer, I tried this (client):
out.write(json.toString());
out.newLine();
out.write("###");
out.flush();
String inputLine = null;
String result = "";
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
while ((inputLine = in.readLine()) != null) {
if (inputLine.contains("###")) {
break;
}
Log.d(TAG, in.readLine());
result = result.concat(inputLine);
}
s.close();
and server:
while ((inputLine = in.readLine()) != null) {
result = result.concat(inputLine);
if (inputLine.contains("###")) {
System.out.println("received ###");
out.println("Hello phone");
out.println("###");
out.flush();
break;
}
}
The idea was to send out the message from the server before the client closes the socket. Still doesnt work ... any hints?
On the server side you never get to sending your "Hello phone". Not until client closes the socket, but at that point it's useless. This is because in.readLine() blocks until either data is available or EOF, i.e. socket closed.
You need a way to get out of the reading loop - invent (or adopt) some application-level protocol that would tell you that a whole message is received. Common options are fixed length messages, length prefix, delimited, etc.

Categories

Resources