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.
Related
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?
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.
I am trying to invoke the following method inside a while loop. First time, it invokes fine but on 2nd loop execution, it throws an IOException
public String getInputString(String prompt){
System.out.print(prompt);
String inputLine = null;
try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))){
inputLine = br.readLine();
if(inputLine.length() == 0){
return null;
}
}
catch(IOException e){
e.printStackTrace();
}
return inputLine;
}
I am getting this IOException:
java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:162)
at java.io.BufferedInputStream.read(BufferedInputStream.java:325)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at ch5.GameHelper.getInputString(GameHelper.java:14)
at ch5.SimpleDotComTestDrive.main(SimpleDotComTestDrive.java:19)
On the other hand, it is working fine when i try to execute it as follows:
try{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
inputLine = br.readLine();
if(inputLine.length() == 0){
return null;
}
}
catch(IOException e){
e.printStackTrace();
}
What is the reason for such a behaviour?
I suspect you're calling getInputString more than once.
The first time, it should work fine - but then you're closing System.in (by closing the BufferedReader wrapping InputStreamReader wrapping System.in)... which means the next time you try to read from System.in, you won't be able to.
If you remove the try-with-resources statement, you could still have problems, because you'll be creating multiple readers around the same stream - if one of those reads more input than you actually use, it won't be available later on.
I suggest you create a BufferedReader wrapping an InputStreamReader wrapping System.in once, at the start of your program, and use that BufferedReader instance everywhere.
I have a servlet in which the from InputStream I am getting the my form data in XML format. I am able to get retrieve the form data in XML format and able to write the same in file. If I open the file I am able to see my form data.
Now the issue is, When i try to append the form data to the string buffer it is not happening. I tried buffer.append(). After that method When I try to print the string buffer value nothing is showing/printing in the console.
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("html/text");
PrintWriter out = response.getWriter();
out.println("doPost Method is excecuting");
DataInputStream in = new DataInputStream (request.getInputStream());
StringBuffer buffer = new StringBuffer();
File file = new File("reqOutput.txt");
file.createNewFile();
FileWriter writer = new FileWriter(file);
int value;
while ((value=in.read()) != -1) {
buffer.append(value);
writer.write(value);
}
System.out.println("Value is : "+ buffer.toString()); // Nothing is printing
writer.flush();
writer.close();
}
What's wrong with my code.Any suggestions please.
Here is your code modified to read from a file:
public static void main(final String[] args) throws Exception {
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader("test"));
final StringBuilder sb = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
sb.append(line);
}
System.out.println("Value is : " + sb.toString());
} finally {
if (in != null) {
in.close();
}
}
}
I added a BufferedReader around the FileReader to optimize the reading.
I switched from reading one character at a time to reading line by line.
This also gives you the results as String so you don't have to convert the int.
Furthermore I added resource handling (pre-7 style and without exception handling) and switched to StringBuilder.
Output:
hello world! -> Value is : hello world!
I think there is another problem, not in this part of your code.
Additional comments on your code (not related to the question):
StringBuffer is a thread-safe implementation. If you have no need for this (like in your servlet example) you'd better use StringBuilder.
Don't close resources within the code block, use a try-finally (or since Java 7 try-with-resources) to guarantee resources are always closed, even when exceptions occur in the block somewhere.
For class I am creating a simple client/server. The client opens a jframe, where the user enters the host and port number. If a connection is made, another jframe is opened that has a keylistener. What is typed on the client's side is displayed in the server's jtextarea. I am able to make the connection between client and server, but after this I run into null pointer exception right after. I assume I should be using something else than bufferedreader in my server, or if I could stop the server from reading in until something is actually entered? Or am I doing something else completely wrong? Any help would be appreciated, and the relevant code is below.
public class TypeServer extends JPanel {
BufferedReader lnr;
public TypeServer(Socket soc) throws IOException {
InputStream inStream = soc.getInputStream();
InputStreamReader isr = new InputStreamReader(inStream);
BufferedReader lnr = new BufferedReader(isr);
}
//below is in the main function
try {
ServerSocket srv = new ServerSocket(5555);
Socket soc=srv.accept();
while (true) {
// Create server
TypeServer tc = new TypeServer(soc);
String line=tc.lnr.readLine();
textArea.append(line);
srv.close();
soc.close();
}
}
EDIT: I apologize for not including this before, but the
String line=tc.lnr.readLine();
line hits the null pointer exception
In your main you are using the instance variable
String line=tc.lnr.readLine(); //lnr is not initialized
You have to change the following
BufferedReader lnr = new BufferedReader(isr); //initializing the local variable
to
this.lnr = new BufferedReader(isr);