Reputation: 171
I have a client and a server, a classic example where trying to simulate in very simple way the http protocol. Firstly the client sends data while server prints the data and then the opposite. In the following code, either the server or client blocks, for an unknown reason. The client sends to the server data, the server receive the data and prints it. But it just blocks after prints the data. If i close the outputstream of the client (out.close()) the client should get the server's data but instead throws IOException with the message: Socket closed.
My question is why is it blocking? Do i have to trigger the output with EOS?
CLIENT
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
import java.io.IOException;
import java.io.*;
public class block_client_webclient
{
public static void main(String [] args)
{
try{
Socket s = new Socket("localhost", 8080);
OutputStreamWriter out = new OutputStreamWriter(s.getOutputStream());
InputStreamReader in = new InputStreamReader(s.getInputStream());
//WRITE
out.write("GET / HTTP/1.1\r\nUser-agent: Agent 2.0 Browser\r\nAccept: */*\r\nAccept-Language: en-US,en;q=0.5\r\nConnection: keep-alive\r\n\r\n");
out.flush();
out.close();
if (s.isConnected()==true && s.isClosed()==false) System.out.println("OPEN");
else System.out.println("CLOSED");
char[] bin = new char[400];
int r=0;
//READ
while((r=in.read(bin))!=-1) { System.out.println("Input data: "+r+" bytes"); System.out.print(bin); bin= new char[400]; };
System.out.println(r);
s.close();
}
catch (IOException ex) {System.out.println(ex.getMessage());}
}
}
SERVER
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import java.util.*;
import java.io.IOException;
import java.io.*;
public class block_server_webserver
{
public static void main(String [] args)
{
while(true)
{
try{
ServerSocket server = new ServerSocket(8080);
Socket connection = server.accept();
try{
OutputStreamWriter out = new OutputStreamWriter( connection.getOutputStream());
InputStreamReader in = new InputStreamReader( connection.getInputStream());
char[] bin = new char[400];
int r=0;
int readsofar=0;
//READ
while((r=in.read(bin))!=-1) { System.out.print(bin); bin= new char[400]; };
System.out.println("END");
//WRITE
out.write("Server: BlockServer 1.0\r\nHost: 192.168.1.1\r\n\r\n");
out.flush();
System.out.println("Just written data to "+connection.getRemoteSocketAddress());
connection.close();
} catch (IOException ex) { connection.close();}
}catch (IOException ex) {}
}
}
}
Upvotes: 1
Views: 1533
Reputation: 3537
Doing out.close() results in a socket closed exception because when you close an input/output stream, the socket related to it also gets closed. That means that in your client program, you won't be able to read in after closing the socket.
First, take out out.close() Instead of checking for -1, try creating an "exit"string. If the server reads the exit string, recognize that it needs to stop being in the while loop and just break; (can be done with a simple if statement). Also, usually I would use a buffered reader, String x and readLine() instead of a char array + read().
while (true) {
in.read(bin);
if (bin[0] == '^') { // or something like that
break;
}
System.out.print(bin);
bin = new char[400];
}
Only close() streams when you are finished with the socket entirely.
Upvotes: 2
Reputation: 40508
The server should not wait for the socket to get closed (because, once that happens, it won't be able to write back).
Instead of reading until it returns -1 (closed), it should read to the end of request (two new lines in case of http headers), and start sending output as soon as that happens, then, possibly, close the connection to inform the client that there is no more data (in http, the connection usually stays open for a while, the client knows to stop reading after enough bytes have been received according to Content-length header).
Upvotes: 2