BufferedReader in Socket Programming - java

When i am trying to send an input from a client, if i don't concat "\r\n" at the end of the string, my inputstream waits forever. I have seen various similar posts but couldn't find a proper solution. My code is as follows:
public void run() {
PrintWriter out = null;
BufferedReader in = null;
try {
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String line;
if (in.ready()) {
if ((line = in.readLine()) != null) {
System.out.println("Received from client: " + line);
out.write("Echoing: " + line);
out.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
out.close();
try {
in.close();
clientSocket.close();
System.out.println("Closing connection from " + socketAddress + ", #" + connectionId);
} catch (IOException e) {
e.printStackTrace();
}
}
}

If you only want to read some of the data that was sent, use the read(char[]) method instead of the readLine method. This method returns the number of characters it read as an int. Example:
char[] buffer = new char[2000];
int read;
if ((read = in.read(buffer)) != -1) {
String line = new String(buffer, 0, read);
System.out.println("Received from client: " + line);
out.write("Echoing: " + line);
out.flush();
}
What you'll see happen next is that this code sometimes fails to read the entire message you send from PHP, or that two or more messages are read as one.
If you want to fix that:
This will never work, and it's not because of PHP or Java. You're using TCP, a stream oriented protocol. There is no guarantee that the message you write to the socket from the PHP program will arrive in one piece to the receiver. The message may be broken up and you need multiple socket function calls to read it. Or it may go the other direction, and a single call to read returns more than one message.
The solution is to add some kind of framing for the messages so that the receiver knows when it has a complete message. Always ending a message with a line break serves as framing, if messages themselves are single lines. Another solution is to ditch TCP and use a message oriented protocol (like UDP) instead, but that will come with its own complications.

Related

Datainputstream and readUTF have data lost

I'm using java and received some json string from a server. I received json strings with readUTF but there is some data lost. I didn't received first two character of the every json packet.
Another problem is there is delay to received json strings. For example server sent one json string and client could not received it until approximately 50 json strings sent by server and client shows all the json strings suddenly.
What is the main problems?
public void run() {
System.out.println("hi from thread" + id);
try {
clientSocket = new Socket("192.168.1.22", id);
output = new PrintStream(clientSocket.getOutputStream());
input = new DataInputStream(clientSocket.getInputStream());
inputLine = new DataInputStream(new BufferedInputStream(System.in));
}
catch( IOException e){
System.out.println(e);
}
String responseLine;
try{
while(true){
output.println( id + " ");
System.out.println("sent:" + id + " ");
responseLine = input.readUTF();
System.out.println("received: " + responseLine);
}
}
catch (IOException e) {
System.out.println(e);
}
}
Because of server send data with UTF format, so I cannot receive them with Bufferedreader
I've had this problem before with applications like this, the main cause is DataInputStream which expects input to be in a certain format which I assume is not being conformed to by the server, try using BufferedReader instead as so:
BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
Then whenever you wish to read data just use
some_string_here = input.readLine();
Note this requires each data value sent to end with a end line character "\n" or "\r".

Java: client socket does not read the second line and remains open after the terminator line

Having read tens of examples online, I am still stuck with the problem.
I am sending a message from my client in Java to a server in C++. After receiving the hand-shake message, the server sends back the following data:
"0000:1111:2222:3333:4444
END_CONNECT_DATA"
As soon as the last line (terminator) is read by the client, it should close the connection.
This is how I do it:
Socket socket = null;
String terminator = "END_CONNECT_DATA";
try
{
int serverPort = 7767;
String ip = "192.168.1.10";
String messageOut = "HAND-SHAKE MESSAGE";
socket = new Socket(ip, serverPort);
DataInputStream input = new DataInputStream( socket.getInputStream());
DataOutputStream output = new DataOutputStream( socket.getOutputStream());
//Send message
output.writeBytes(messageOut);
//Read Response
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
StringBuffer sb = new StringBuffer();
String s = "";
while((s = br.readLine()) != null)
{
System.out.println("CHECK !!!");
System.out.println(s);
sb.append(s);
if(s.contains(terminator))
{
System.out.println("CHECK TERMINATOR");
break;
}
}
socket.close();
String data = sb.toString();
System.out.println("FULL DATA:\n");
System.out.println(data);
}
catch (UnknownHostException e)
{
System.out.println("Sock:"+e.getMessage());
}
catch (EOFException e)
{
System.out.println("EOF:"+e.getMessage());
}
catch (IOException e)
{
System.out.println("IO:"+e.getMessage());
}
finally
{
if(socket!=null)
{
try
{
socket.close();
}
catch (IOException e)
{
}
}
}
}
What I get back from the server is only the first line. The cursor goes to the next line and continues blinking. The socket connection is not closed. Looks like the client is not reading the terminator (the second line of the message) at all.
Any ideas?
Thanks a lot!
As documented, the loop fails to read in the second line as it's not terminated with \r or \n. Therefore, returning only the result up till then, which is the first line as described.
You'll need to either add in a \r or \n right after the terminator or use BufferedReader.read() instead and check manually or adopt another strategy to read in the message
Clearly the peer is neither sending a line terminator after the last line nor closing the socket. Ergo using readLine() to read those messages is not correct. If you can adjust the peer, do so.

Having trouble sending String from client socket to server socket, and vice versa

I am trying to create an application that will count the amount of times a button has been clicked. This client would connect to a server, and when the user clicks the button, it should increment the counter on the server. The server should then send back the current amount of clicks to the client. But that's where I'm having a bit of problems.
This is the relevant client-sided code.
public void actionPerformed(ActionEvent arg0) {
try {
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
String target = "";
bw.write("increment" + "\n");
bw.flush();
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String id = br.readLine();
System.out.println("test: " + id);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
The client stops at:
String id = br.readLine();
I just want to get the output from the server.
This is the relevant server-sided code.
public void run() {
try {
while (true) {
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is); //Create the input Streams
BufferedReader br = new BufferedReader(isr);
String input = br.readLine();
System.out.println("got input");
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
System.out.println("wrote to out");
if(input.equals("increment" + "\n")) {
totalBets++;
System.out.println("inif");
bw.write(totalBets);
System.out.println("wrote");
bw.flush();
System.out.println("flushed");
System.out.println("Total Bets: " + totalBets);
}
}
} catch (IOException e) {
log("Error handling client# " + clientNumber + ": " + e);
} finally {
try {
socket.close();
} catch (IOException e) {
log("Couldn't close a socket, what's going on?");
}
log("Connection with client# " + clientNumber + " closed");
}
}
I found that it also stops here:
String input = br.readLine();
I'm just trying to get the bw.write("imcrement") from the client, so the server can increment the counter, and send back the total clicks.
Any help?
Thank you.
You are writing the totalBets value using BufferedWriter.write(int).
This interprets the value as a single character. So, for example, if totalBets is 65, it writes the character 'A'!
Moreover, it does not add a newline. So the client reads that 'A' but tries to read more characters as it is trying to read a whole line. Remember that you have to write lines to read lines.
Thus, you should replace the part that writes totalBets with:
bw.write(String.valueOf(totalBets));
bw.newLine();
Also remember, as I pointed in a comment, that you have to write a line with a \n (or preferably BufferedWriter.newLine()), but when you read the line on the other side, the line separator is stripped away, so you should compare the string you expect without a \n.
You need to set TCP_NODELAY on the client's socket. The default is for data to be buffered until it will fill an entire packet. When the buffer is full, a packet is sent. However, for this protocol you want the data to be sent immediately so that the server can respond.
I frequently use wireshark when testing and debugging my networking code. It will show exactly what packets are sent and received. (note, however, that on Windows you can not capture from the loopback interface; this is a limitation of Windows and does not apply to other systems)

Java socket timing out: Broken pipe

I'm writing a simple server in Java, and I'm able to retrieve incoming data from the client on the server side, but not on the client side due to a 2000ms timeout. Anyone know why this times out?
This is the server's code:
private static void listen() throws IOException {
while(true) {
Socket clientSocket = serverSocket.accept();
StringBuilder bufferedStringInput = new StringBuilder();
CharBuffer cbuf = CharBuffer.allocate(4096);
try {
InputStream is = clientSocket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF8"));
int noCharsLeft = 0;
while ((noCharsLeft = br.read(cbuf)) != -1) {
char[] arr = new char[noCharsLeft];
cbuf.rewind();
cbuf.get(arr);
bufferedStringInput.append(arr);
cbuf.clear();
}
System.out.println(bufferedStringInput.toString());
} catch (IOException e) {
System.out.println("Error received client data: " + e.getMessage());
}
String message = "Hello client";
try {
PrintWriter out = new PrintWriter(clientSocket.getOutputStream());
out.print(message);
} catch (IOException e) {
System.out.println("Error getting output stream from client: " + e.getMessage());
}
clientSocket.close();
}
}
You're reading the input until end of stream, which only happens when the peer closes the connection, then you're trying to write to it, so of course you get a broken pipe. Doesn't make sense. You should just read the input until you have one entire request, whatever that means in your protocol.
There are other problems lurking here:
If the client code uses readLine(), you're not sending a line terminator: use println(), not print(), and close the PrintWriter, not just the client socket.
cbuf.rewind()/get()/clear() should be cbuf.flip()/get()/compact().
But it would make more sense to read directly into a char[] cbuf = new char[8192]; array, then bufferedStringInput.append(cbuf, 0, noCharsLeft), and forget about the CharBuffer altogether. Too much data copying at present.
noCharsLeft is a poor name for that variable. It is a read count.

Ascii on TCP socket

Anyone could pass me an example of sending Ascii msg over TCP?(couldnt find example on the net)
thanks,
ray.
Here's an example of writing to and reading from an echoing server.
A simplified excerpt:
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
echoSocket = new Socket("taranis", 7);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: taranis.");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for "
+ "the connection to: taranis.");
System.exit(1);
}
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(System.in));
String userInput;
while ((userInput = stdIn.readLine()) != null) {
out.println(userInput);
System.out.println("echo: " + in.readLine());
}
Not sure, I think this should work:
try (DataOutputStream outToClient = new DataOutputStream(socket.getOutputStream())) {
outToClient.write(stringMessage.getBytes("US-ASCII"));
} catch (IOException e) {}
Not stated in the original question is whether ASCII control codes have to handled.
While the accepted answer works for printable ASCII characters I've had problems (on Windows 7 Enterprise SP1) using it for strings containing ASCII control codes, especially strings containing any of the java newline "characters", e.g. VT, CR, LF, etc. A workaround is to send the string as bytes and convert it back to a string at the far end.
See my answer to this question for how to handle that situation.
Reading Lines and byte[] from input stream
and my closely related question and it's accepted answer:
Need TCPIP client that blocks until a specific character sequence is received

Categories

Resources