Socket (C/Java) BufferedReader readLine() doesn't stop - java

I'm creating a forum with a Java interface and a C server.
I have trouble sending a message from C to Java....
I created a socket (named "socket") that works, like this :
socket = new Socket(adr, port);
//adr and port are defined before
But when doing this on the Java:
String str =null;
try {
BufferedReader br = new BufferedReader( new InputStreamReader(socket.getInputStream()) );
while ((str=br.readLine()) != null && str.length()>0)
{
System.out.println("str = " + str);
}
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
It just can't receive the message from the server.
It only shows the message when I brutally close the C server.
Here is how the server sends the message through the Socket :
write(client_sock,"0\0",strlen("0\0"));
I have no idea how to receive this "0" without closing the server. Any ideas ?

readLine() has read the send data, but blocks until a line feed or carriage return was read
If your client sees the data only if you are closing the server, than your server never sends a line feed or a carriage return.
Assuming, you want to send a file line by line to the client(example in java, it is my main language):
Socket client = server.accept();
OutputStream os = client.getOutputStream();
BufferedReader br = new BufferedReader( new InputStreamReader(Files.newInputStream(file.toPath())));
String str;
while ((str = br.readLine()) != null && str.length() > 0) {
os.write((str).getBytes());
}
br.close();
os.close();
As you can see, the server don't sends a line feed or carriage return. These were removed by readLine()!
So, the readLine() on your clientside is blocking until the socket will closed.
If you change the write instruction in that way:
os.write((str+"\n").getBytes());
your client is able to read the lines, even if the server is still writing the following lines.

You're looping until readLine() returns null or a blank line.
It returns null at end of stream. As you're reading from a socket, that only happens when the peer closes the connection.
It returns a blank line when the input contains a blank line.
Ergo the peer is neither closing the connection nor sending a blank line.

Related

Socket's PrintWriter doesn't send until closed

I have client code that looks like:
Socket s = new Socket(server.getHostName(), server.getPort());
PrintWriter p = new PrintWriter(s.getOutputStream());
p.println(message);
p.flush();
s.shutdownOutput();
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String newLine;
StringBuffer response = new StringBuffer();
while((newLine = br.readLine()) != null)
response.append(newLine);
System.out.println(response.toString());
p.close();
br.close();
and server code that looks like:
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String nextLine;
StringBuffer request = new StringBuffer();
System.out.println("Starting read....");
String nextline;
while((nextline = br.readLine()) != null){
System.out.println(nextline);
request.append(nextline);
}
System.out.println("Message recived!!");
System.out.println("Request: " + request);
PrintWriter p = new PrintWriter(s.getOutputStream());
p.println("Hello, fileclient!");
System.out.println("Message sent!!");
p.close();
br.close();
Before I put the line s.shutDownInput() the server code would hang at br.readLine(). The way I managed to fix that is to close the PrintWriter some how, either through p.close() or through the current way which doesn't
shutdown the socket like closing the PrintWriter through p.close() does. After that, the interaction between client and server is perfect.
Why does the PrintWriter or the BufferedReader not send/receive until the PrintWriter is closed somehow?
It doesn't have anything to do with PrintWriter. It is an application protocol error on your part.
The server is looping reading lines until end of stream.
The client is sending one line and then not closing the socket, so no end-of-stream got sent (until you added the shutdown).
The server is then responding.
The client is then reading.
So the client doesn't read anything until the server gets out of the loop, and the server doesn't get out of its loop because the client is reading not closing.
So make up your mind. Probably the server should only read one line.
Both sides are behaving exactly as you told them to do. In particular, you instruct the server specifically to read everything the client sends before dispatching any response:
String nextline;
while((nextline = br.readLine()) != null){
System.out.println(nextline);
request.append(nextline);
}
It is important to understand that that will not stop reading until an error or end of stream, where end of stream on a socket corresponds to the other end having been closed and all data having been read. In other words, your server waits for the end of the whole conversation, not the end of a single message, before dispatching a response.
Since that's apparently not what you want, you need to implement a different strategy at the server for determining when to process the data received so far and send a response. If you can be confident that your messages will not contain internal newlines, then that might be as simple as the server performing only one br.readLine() before sending each response.

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.

read socket data with java

i'm using websocket to send data, this is the code (javascript)
socket= new WebSocket('ws://localhost:10302/socket');
socket.onopen= function() {
socket.send('delete structure'+c);
}
in the server side i'm using java and this is the code
try {
standardiste = new ServerSocket(10302);
while(true) {
System.out.println("listening data from socket");
socket = standardiste.accept();
try {
BufferedReader entree = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(entree!=null)
{
System.out.println(entree.readLine());
}
}
catch(IOException exc) {
}
socket.close();
}
}
i want to read the data sended ?
What you need is
String line;
while((line = entree.readLine()) != null){
System.out.println(line);
}
What you were trying was to tie in the BufferedReader into the Socket, but never read anything from it. That's where the BufferedReader.readLine() method comes in, which reads a single line (until it reaches an endline character) from the buffer.
By comparing the current line to null (readLine() != null) you keep reading until it stops receiving the end of a transmission.
Edit:
I'm afraid the WebSocket protocol is different from the Java Socket protocol, hence it receives just the headers, but doesn't recognize any of the actual data that is being sent, simple because the protocols don't match up. Try using the Java WebSocket class. Here is a good tutorial.

BufferReader unexpected behavour

I'm trying to read data from socket using threading run method:
#Override
public void run() {
while(true){
try{
String o = "";
socketServer = new ServerSocket(port);
System.out.println("Waiting for connection on port "+port+".");
Socket socket = new Socket();
socket = socketServer.accept();
System.out.println("Connection got.");
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
int c;
while(( c = input.read()) != -1)
o += (char)c;
PrintWriter output = new PrintWriter(socket.getOutputStream());
output.println("ok");
output.flush();
output.close();
input.close();
socket.close();
socketServer.close();
textFieldMessage.setText("Сообщение от "+socket.getInetAddress().getCanonicalHostName()+":\n"+o);
}catch(Exception e){
e.printStackTrace();
System.exit(-1);
}
}
}
But it's stucked on while loop. Debugger told that there was no -1 value at the end.
What's wrong here?
Because you're reading from a Socket, you'll never reach the end of the stream unless the socket or stream has been closed. So the while loop will block on input.read() because it won't return -1 until the client closes the stream/socket.
Not really sure what it is you are reading from the socket, but you could try using the BufferedReader's readLine() method. You can either know how many lines you need to read ahead of time, or end the reading with a blank line (like HTTP).
read() method of InputStream blocks until the data is available.
It can return -1 only when the end of the stream is detected.(Though it shouldn't be the case with sockets) So while loop will block if the data is not available i.e your read call will wait for the data to be read.
Note :
But if the value is -1, your program should have exited. So what are you reading ?
The peer isn't closing the socket, so you are never getting the -1, so you are blocking in the read() invocation after the last character received. Your strategy is flawed. You are reading to EOS and then expecting to be able to write a reply. Unless the peer shuts down his socket for output and then reads, this is never going to work. You need to define your application protocol properly. At present you are expecting the peer to do write/close/read. Doesn't make sense.

Communication between Client and Server using Sockets

Okay this is a revised question from earlier today, I have included code to help explain the problem. I am sending two messages from the client to the server. The server then picks the messages up and processes them. The server finally attempts to send a message back to the client(please note in the server code "testmessage"), it is here I am having problems. Either I am not recieving the message at the client side or sending it incorrectly from the server side.
public class ClientConnection {
String address, language, message;
int portNumber;
Socket clientSocket = null;
public ClientConnection(String lan, String mes, String add, int pn) throws IOException{
address = add;
portNumber = pn;
language = lan;
message = mes;
}
public String createAndSend() throws IOException{
// Create and connect the socket
Socket clientSocket = null;
clientSocket = new Socket(address, portNumber);
PrintWriter pw = new PrintWriter(clientSocket.getOutputStream(),true);
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// Send first message - Message is being correctly received
pw.write(language+"\n");
pw.flush();
// Send off the data
// Send the second message - Message is being correctly received
pw.write(message);
pw.flush();
pw.close();
// Send off the data
// NOTE: Either I am not receiving the message correctly or I am not sending it from the server properly.
String translatedMessage = br.readLine();
br.close();
//Log.d("application_name",translatedMessage); Trying to check the contents begin returned from the server.
return translatedMessage;
}
Server Code:
public class ServerConnection {
public static void main(String[] args) throws Exception {
// Delete - Using while loop to keep connection open permanently.
boolean status = false;
while( !status){
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(1);
}
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
// Delete - Working as of here, connection is established and program runs awaiting connection on 4444
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String language = br.readLine();
String message = br.readLine();
// Test - Works
System.out.println(language);
// Test - Works
System.out.println(message);
// Delete - Working as of here, both messages are passed and applied. Messages are received as sent from client.
TranslateMessage tm = new TranslateMessage();
String translatedMessage = tm.translateMessage(language, message);
// NOTE: This seems to be where I am going wrong, either I am not sending the message correctly or I am not receiving it correctly..
// PrintWriter writer = new PrintWriter(new BufferedOutputStream(clientSocket.getOutputStream()));
PrintWriter pw = new PrintWriter(clientSocket.getOutputStream(),true);
// Send translation back
System.out.println(translatedMessage);
// pw.write(translatedMessage+"\n");
pw.write("Return test"); // Test message!
pw.flush();
// Send off the data
pw.close();
br.close();
clientSocket.close();
serverSocket.close();
}
}
}
The code is a bit of a mess and I can see a few duplicates, I have commented where I feel the problems occour.
Thanks for any help!
You are using BufferedReader.readLine() to read the response from the server, but in the test case you are sending a string that is not terminated with a \n or \r\n, so it will not get the line as far as I can tell from the docs...
public String readLine()
throws IOException
Read 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.
Returns:
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
An additional suggestion...
When writing request response protocols like this I would not rely on line endings to terminate the requests or responses. Typically I would use either a fully formatted JSON string, or my preference is for a binary protocol where all requests and response are prepended with a binary count (usually 4 bytes bigendian/network byte order). Then the client and server reads the 4 bytes then reads the number of bytes that follow. This handles the packet fragmentation that typically happens over network connections, also it helps avoid DOS attacks by malicious users sending long strings that never terminate.
In Java you can use ByteBuffer.order() to handle bigendian numbers.

Categories

Resources