Reputation: 53
Whenever I call .flush()
on any of the writers in the title (who are wrapping an OutputStreamWriter), the flushed data is not sent; however, when .close()
is called on the writer, it flushes and the server can read the data. I don't know if I am calling .write()
or .readLine()
incorrectly, or if, since the read operation has already blocked, that is the problem? I need to find a way to flush the data without closing the socket (I'll be using this in another program). In both of the SSCCE's I have, there are System.out.println()
's for debugging. In the client, it will go to "check 4" and loop on nothing (it does more read and writing in the actual program, just can't have it close in the example). In the server, it gets to "check 2" and blocks at reader.readLine()
. I've read around on SO, but all I've come up with is that readLine()
isn't a good idea for network programs, and that I should implement my own protocol; however none of the posts point to a good tutorial site, or anything else with good network coding tutorials. Here are the SSCCEs:
Client SSCCE
package testClient;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class Client {
public static void main(String[] args) {
try {
Socket s = new Socket("127.0.0.1",48878);
System.out.println("check 1");
PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"));
System.out.println("check 2");
pw.write("Hello StackOverFlow.");
System.out.println("check 3");
pw.flush();
System.out.println("check 4");
while(true){}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Server SSCCE
package testServer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(48878);
Socket client = ss.accept();
System.out.println("check 1");
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(),"UTF-8"));
System.out.println("check 2");
byte[] buffer = new byte[20];
int i = 0;;
int x;
while((x=reader.read())!=-1) {
buffer[i] += (byte)x;
i = i++;
}
String text = new String(buffer,"UTF-8");
System.out.println("check 3");
System.out.println(text);
client.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Upvotes: 1
Views: 3323
Reputation: 328594
The "bug" is in the loop which you use to read the data. EOF is only sent when you close the stream on the other side. So the loop seems to hang despite the fact that is has probably added N bytes to the array already.
What you need to do is to send a hint to the server about the length of data that the client is about to send. That can be the number of bytes/characters or a termination character (line a line feed).
In the sender, send the data+hint and then flush.
In the receiver, read just as much data as you are allowed and not a single byte more. That way, the receiver will not block.
In your case, reader.readLine()
should work as long as you use println()
+ flush on the sender.
Upvotes: 2
Reputation: 46841
Try with auto flush property of PrintWriter that flush the data once new line methods are calle. There is no need to call flush after writing any data in the stream.
Unlike the
PrintStream
class, if automatic flushing is enabled it will be done only when one of theprintln
,printf
, orformat
methods is invoked, rather than whenever a newline character happens to be output.
Sample code:
Client:
PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"),true);
pw.println("Hello StackOverFlow.");
Server:
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(),"UTF-8"));
System.out.println(reader.readLine());
Upvotes: 2