If I execute the JUnit test below WITHOUT the line "inputStream.close()" (see below), more than 60000 requests can be processed (I killed the process then). WITH this line, I did not manage making more than 15000 requests, because of:
java.net.SocketException: No buffer space available (maximum connections reached?): connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:529)
at java.net.Socket.connect(Socket.java:478)
at java.net.Socket.<init>(Socket.java:375)
at java.net.Socket.<init>(Socket.java:189)
at SocketTest.callServer(SocketTest.java:60)
at SocketTest.testResourceConsumption(SocketTest.java:52)
I run it on Windows, before starting the test I wait for the netstat list to be back to normal.
Questions:
why is calling socketInputStream.close() on the client side harms in this case?
or what is wrong with the code?
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import junit.framework.TestCase;
public class SocketTest extends TestCase {
private static final int PORT = 12345;
private ServerSocket serverSocket;
public void setUp() throws Exception {
serverSocket = new ServerSocket(PORT);
new Thread(new Runnable() {
#Override
public void run() {
while(true) {
try {
final Socket socket = serverSocket.accept();
new Thread(new Runnable() {
#Override
public void run() {
try {
OutputStream outputStream = socket.getOutputStream();
for(int i = 0; i < 100; i++) {
outputStream.write(i);
}
outputStream.close();
// in fact the previous line calls this already:
// socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}).start();
}
public void testResourceConsumption() throws Exception {
for (int i=0; i<1000000; i++) {
callServer();
if (i % 1000 == 0) {
System.out.println(i);
}
}
}
private void callServer() throws Exception {
Socket clientSocket = new Socket("localhost", PORT);
InputStream inputStream = clientSocket.getInputStream();
for (int i = 0; i < 100; i++) {
assertEquals(i, inputStream.read());
}
///////////////// THIS LINE IS INTERESTING
inputStream.close();
// in fact the previous line calls this already:
// clientSocket.close();
}
public void tearDown() throws Exception {
serverSocket.close();
}
}
When you explicitly call inputStream.close() you change the order of TCP graceful connection release. In this case the client side of the connection is closed prior to receiving FIN packet from the server, thus leaving the socket in TIME_WAIT state. At some point all local ports for outgoing connections become occupied with these TIME_WAIT sockets, and no more outgoing connections can be made.
When you don't call inputStream.close(), the connections are shut down by the server side with outputStream.close() call. The client sockets have enough time to receive FIN from the server, and then at garbage collection time they get gracefully closed by the finalizer method.
There are two options to fix the procedure in your test:
Preferable way is to continue reading from inputStream until you receive -1, which means that the other side has initiated the connection shutdown (i.e. FIN is received). Just insert assertEquals(-1, inputStream.read()); before inputStream.close();
The second option is to force the abortive release by setting
clientSocket.setSoLinger(true, 0);
In this case inputStream.close() will force client to send RST and abort the connection.
More about orderly and abortive TCP connection release.
Related
In my main thread I have a while(listening) loop which calls accept() on my ServerSocket object, then starts a new client thread and adds it to a Collection when a new client is accepted.
I also have an Admin thread which I want to use to issue commands, like 'exit', which will cause all the client threads to be shut down, shut itself down, and shut down the main thread, by turning listening to false.
However, the accept() call in the while(listening) loop blocks, and there doesn't seem to be any way to interrupt it, so the while condition cannot be checked again and the program cannot exit!
Is there a better way to do this? Or some way to interrupt the blocking method?
You can call close() from another thread, and the accept() call will throw a SocketException.
Set timeout on accept(), then the call will timeout the blocking after specified time:
http://docs.oracle.com/javase/7/docs/api/java/net/SocketOptions.html#SO_TIMEOUT
Set a timeout on blocking Socket operations:
ServerSocket.accept();
SocketInputStream.read();
DatagramSocket.receive();
The option must be set prior to entering a blocking operation to take effect. If the timeout expires and the operation would continue to block, java.io.InterruptedIOException is raised. The Socket is not closed in this case.
Is calling close() on the ServerSocket an option?
http://java.sun.com/j2se/6/docs/api/java/net/ServerSocket.html#close%28%29
Closes this socket. Any thread currently blocked in accept() will throw a SocketException.
You can just create "void" socket for break serversocket.accept()
Server side
private static final byte END_WAITING = 66;
private static final byte CONNECT_REQUEST = 1;
while (true) {
Socket clientSock = serverSocket.accept();
int code = clientSock.getInputStream().read();
if (code == END_WAITING
/*&& clientSock.getInetAddress().getHostAddress().equals(myIp)*/) {
// End waiting clients code detected
break;
} else if (code == CONNECT_REQUEST) { // other action
// ...
}
}
Method for break server cycle
void acceptClients() {
try {
Socket s = new Socket(myIp, PORT);
s.getOutputStream().write(END_WAITING);
s.getOutputStream().flush();
s.close();
} catch (IOException e) {
}
}
The reason ServerSocket.close() throws an exception
is because you have an outputstream or an inputstream
attached to that socket.
You can avoid this exception safely by first closing the input and output streams.
Then try closing the ServerSocket.
Here is an example:
void closeServer() throws IOException {
try {
if (outputstream != null)
outputstream.close();
if (inputstream != null)
inputstream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
if (!serversock.isClosed())
serversock.close();
}
}
You can call this method to close any socket from anywhere without getting an exception.
Use serverSocket.setSoTimeout(timeoutInMillis).
OK, I got this working in a way that addresses the OP's question more directly.
Keep reading past the short answer for a Thread example of how I use this.
Short answer:
ServerSocket myServer;
Socket clientSocket;
try {
myServer = new ServerSocket(port)
myServer.setSoTimeout(2000);
//YOU MUST DO THIS ANYTIME TO ASSIGN new ServerSocket() to myServer‼!
clientSocket = myServer.accept();
//In this case, after 2 seconds the below interruption will be thrown
}
catch (java.io.InterruptedIOException e) {
/* This is where you handle the timeout. THIS WILL NOT stop
the running of your code unless you issue a break; so you
can do whatever you need to do here to handle whatever you
want to happen when the timeout occurs.
*/
}
Real world example:
In this example, I have a ServerSocket waiting for a connection inside a Thread. When I close the app, I want to shut down the thread (more specifically, the socket) in a clean manner before I let the app close, so I use the .setSoTimeout() on the ServerSocket then I use the interrupt that is thrown after the timeout to check and see if the parent is trying to shut down the thread. If so, then I set close the socket, then set a flag indicating that the thread is done, then I break out of the Threads loop which returns a null.
package MyServer;
import javafx.concurrent.Task;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import javafx.concurrent.Task;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
public class Server {
public Server (int port) {this.port = port;}
private boolean threadDone = false;
private boolean threadInterrupted = false;
private boolean threadRunning = false;
private ServerSocket myServer = null;
private Socket clientSocket = null;
private Thread serverThread = null;;
private int port;
private static final int SO_TIMEOUT = 5000; //5 seconds
public void startServer() {
if (!threadRunning) {
serverThread = new Thread(thisServerTask);
serverThread.setDaemon(true);
serverThread.start();
}
}
public void stopServer() {
if (threadRunning) {
threadInterrupted = true;
while (!threadDone) {
//We are just waiting for the timeout to exception happen
}
if (threadDone) {threadRunning = false;}
}
}
public boolean isRunning() {return threadRunning;}
private Task<Void> thisServerTask = new Task <Void>() {
#Override public Void call() throws InterruptedException {
threadRunning = true;
try {
myServer = new ServerSocket(port);
myServer.setSoTimeout(SO_TIMEOUT);
clientSocket = new Socket();
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
try {
clientSocket = myServer.accept();
}
catch (java.io.InterruptedIOException e) {
if (threadInterrupted) {
try { clientSocket.close(); } //This is the clean exit I'm after.
catch (IOException e1) { e1.printStackTrace(); }
threadDone = true;
break;
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
};
}
Then, in my Controller class ... (I will only show relevant code, massage it into your own code as needed)
public class Controller {
Server server = null;
private static final int port = 10000;
private void stopTheServer() {
server.stopServer();
while (server.isRunning() {
//We just wait for the server service to stop.
}
}
#FXML private void initialize() {
Platform.runLater(()-> {
server = new Server(port);
server.startServer();
Stage stage = (Stage) serverStatusLabel.getScene().getWindow();
stage.setOnCloseRequest(event->stopTheServer());
});
}
}
I hope this helps someone down the road.
Another thing you can try which is cleaner, is to check a flag in the accept loop, and then when your admin thread wants to kill the thread blocking on the accept, set the flag (make it thread safe) and then make a client socket connection to the listening socket.
The accept will stop blocking and return the new socket.
You can work out some simple protocol thing telling the listening thread to exit the thread cleanly.
And then close the socket on the client side.
No exceptions, much cleaner.
You can simply pass the timeout limit (milli seconds) as a parameter while calling accept function.
eg serverSocket.accept(1000);
automatically close the request after 1 sec
In my main thread I have a while(listening) loop which calls accept() on my ServerSocket object, then starts a new client thread and adds it to a Collection when a new client is accepted.
I also have an Admin thread which I want to use to issue commands, like 'exit', which will cause all the client threads to be shut down, shut itself down, and shut down the main thread, by turning listening to false.
However, the accept() call in the while(listening) loop blocks, and there doesn't seem to be any way to interrupt it, so the while condition cannot be checked again and the program cannot exit!
Is there a better way to do this? Or some way to interrupt the blocking method?
You can call close() from another thread, and the accept() call will throw a SocketException.
Set timeout on accept(), then the call will timeout the blocking after specified time:
http://docs.oracle.com/javase/7/docs/api/java/net/SocketOptions.html#SO_TIMEOUT
Set a timeout on blocking Socket operations:
ServerSocket.accept();
SocketInputStream.read();
DatagramSocket.receive();
The option must be set prior to entering a blocking operation to take effect. If the timeout expires and the operation would continue to block, java.io.InterruptedIOException is raised. The Socket is not closed in this case.
Is calling close() on the ServerSocket an option?
http://java.sun.com/j2se/6/docs/api/java/net/ServerSocket.html#close%28%29
Closes this socket. Any thread currently blocked in accept() will throw a SocketException.
You can just create "void" socket for break serversocket.accept()
Server side
private static final byte END_WAITING = 66;
private static final byte CONNECT_REQUEST = 1;
while (true) {
Socket clientSock = serverSocket.accept();
int code = clientSock.getInputStream().read();
if (code == END_WAITING
/*&& clientSock.getInetAddress().getHostAddress().equals(myIp)*/) {
// End waiting clients code detected
break;
} else if (code == CONNECT_REQUEST) { // other action
// ...
}
}
Method for break server cycle
void acceptClients() {
try {
Socket s = new Socket(myIp, PORT);
s.getOutputStream().write(END_WAITING);
s.getOutputStream().flush();
s.close();
} catch (IOException e) {
}
}
The reason ServerSocket.close() throws an exception
is because you have an outputstream or an inputstream
attached to that socket.
You can avoid this exception safely by first closing the input and output streams.
Then try closing the ServerSocket.
Here is an example:
void closeServer() throws IOException {
try {
if (outputstream != null)
outputstream.close();
if (inputstream != null)
inputstream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
if (!serversock.isClosed())
serversock.close();
}
}
You can call this method to close any socket from anywhere without getting an exception.
Use serverSocket.setSoTimeout(timeoutInMillis).
OK, I got this working in a way that addresses the OP's question more directly.
Keep reading past the short answer for a Thread example of how I use this.
Short answer:
ServerSocket myServer;
Socket clientSocket;
try {
myServer = new ServerSocket(port)
myServer.setSoTimeout(2000);
//YOU MUST DO THIS ANYTIME TO ASSIGN new ServerSocket() to myServer‼!
clientSocket = myServer.accept();
//In this case, after 2 seconds the below interruption will be thrown
}
catch (java.io.InterruptedIOException e) {
/* This is where you handle the timeout. THIS WILL NOT stop
the running of your code unless you issue a break; so you
can do whatever you need to do here to handle whatever you
want to happen when the timeout occurs.
*/
}
Real world example:
In this example, I have a ServerSocket waiting for a connection inside a Thread. When I close the app, I want to shut down the thread (more specifically, the socket) in a clean manner before I let the app close, so I use the .setSoTimeout() on the ServerSocket then I use the interrupt that is thrown after the timeout to check and see if the parent is trying to shut down the thread. If so, then I set close the socket, then set a flag indicating that the thread is done, then I break out of the Threads loop which returns a null.
package MyServer;
import javafx.concurrent.Task;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import javafx.concurrent.Task;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
public class Server {
public Server (int port) {this.port = port;}
private boolean threadDone = false;
private boolean threadInterrupted = false;
private boolean threadRunning = false;
private ServerSocket myServer = null;
private Socket clientSocket = null;
private Thread serverThread = null;;
private int port;
private static final int SO_TIMEOUT = 5000; //5 seconds
public void startServer() {
if (!threadRunning) {
serverThread = new Thread(thisServerTask);
serverThread.setDaemon(true);
serverThread.start();
}
}
public void stopServer() {
if (threadRunning) {
threadInterrupted = true;
while (!threadDone) {
//We are just waiting for the timeout to exception happen
}
if (threadDone) {threadRunning = false;}
}
}
public boolean isRunning() {return threadRunning;}
private Task<Void> thisServerTask = new Task <Void>() {
#Override public Void call() throws InterruptedException {
threadRunning = true;
try {
myServer = new ServerSocket(port);
myServer.setSoTimeout(SO_TIMEOUT);
clientSocket = new Socket();
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
try {
clientSocket = myServer.accept();
}
catch (java.io.InterruptedIOException e) {
if (threadInterrupted) {
try { clientSocket.close(); } //This is the clean exit I'm after.
catch (IOException e1) { e1.printStackTrace(); }
threadDone = true;
break;
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
};
}
Then, in my Controller class ... (I will only show relevant code, massage it into your own code as needed)
public class Controller {
Server server = null;
private static final int port = 10000;
private void stopTheServer() {
server.stopServer();
while (server.isRunning() {
//We just wait for the server service to stop.
}
}
#FXML private void initialize() {
Platform.runLater(()-> {
server = new Server(port);
server.startServer();
Stage stage = (Stage) serverStatusLabel.getScene().getWindow();
stage.setOnCloseRequest(event->stopTheServer());
});
}
}
I hope this helps someone down the road.
Another thing you can try which is cleaner, is to check a flag in the accept loop, and then when your admin thread wants to kill the thread blocking on the accept, set the flag (make it thread safe) and then make a client socket connection to the listening socket.
The accept will stop blocking and return the new socket.
You can work out some simple protocol thing telling the listening thread to exit the thread cleanly.
And then close the socket on the client side.
No exceptions, much cleaner.
You can simply pass the timeout limit (milli seconds) as a parameter while calling accept function.
eg serverSocket.accept(1000);
automatically close the request after 1 sec
I want to implement a Server which listens endless on a specific port to receive data from many clients (never in parallel, only serial). The first thing I tried is to run the server and then launch a few clients in serial (one after the other).
This sounded very easy to implement, but I actually got into the problem, that the code works only when I run it in debug mode with at least one breakpoint in the server code (but the same fault as when running it normally without a breakpoint), very strange to me.
However here is the server code:
public class TaskExecutionServer {
public TaskExecutionServer(final int port) {
new Thread() {
#Override
public void run() {
try {
int counter = 0;
ServerSocket serverSocket = new ServerSocket(port);
while(true) {
System.out.println("Waiting for client...");
Socket socket = serverSocket.accept();
System.out.println("Accepted");
InputStream inputStream = socket.getInputStream();
ObjectInputStream objectStream = new ObjectInputStream(inputStream);
while(inputStream.available() > 0 ) {
String to = (String)objectStream.readObject();
System.out.println(to);
System.out.println(++counter);
}
objectStream.close();
inputStream.close();
System.out.println("Closing socket");
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
public static void main(String args[]) {
new TaskExecutionServer(2003);
}
}
And here the client code:
public class TaskSenderClient {
public static void main(String args[]){
try{
Socket s = new Socket("localhost",2003);
OutputStream os = s.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject("test");
oos.close();
os.close();
s.close();
}catch(Exception e){
System.out.println("Client exception");
e.printStackTrace();
}
}
}
this is the console output when running in debug mode with breakpoint in the server code row System.out.println("Accepted");:
Waiting for client...
Accepted
test
1
Closing socket
Waiting for client...
Accepted
test
2
Closing socket
Waiting for client...
Accepted
test
3
Closing socket
Waiting for client...
And the output when running in normal mode / without breakpoints in debug-mode:
Waiting for client...
Accepted
test
1
Closing socket
Waiting for client...
Accepted
Closing socket
Waiting for client...
Accepted
Closing socket
Waiting for client...
I don't get any exception... Can someone help? It's my first attempt to re-use a socket connection in java.
EDIT: Checking inputStream.available returns different values
I just added a System.out.println(inputStream.available()); before the while in server code. This prints
always 7 in debug-mode with breakpoint
7 (in first run) and 0 (in all other attemps) afterwards in non-debug mode / without breakpoints
EDIT 2: First wait until inputStream.available != 0
This solution also works for me. However, I removed this code snippet here, because checking of available() seems not to be the correct way for that! -> see the solution!
EDIT 3: New server code, which uses NonEmptyInputStream which checks per PushbackInputStream for non-empty streams:
As this uses the EOFException it seems not to be an optimal solution to me, so I also removed this code snippet (instead see solution below). The usage of exceptions in "correct" code is discussed in the comments below...
InputStream.available() can return 0 if there is no data yet, meaning the client didn't send some yet or at least it is not arrived yet. If you add a breakpoint the client has more time to send the data.
You can either add logic like your client first sends how many objects it writes, the server reads the amount and then reads that many objects before it stops reading.
Another possibility would be to insert a PushbackInputStream between the ObjectInputStream and the InputStream and then do a read() on the PushbackInputStream, check the result for -1 which means end-of-stream and if it was not -1, use unread() to push the read byte back into the stream before using the ObjectInputStream methods.
Here you have an example of your originally posted class rewritten with the last pattern:
public class TaskExecutionServer {
public TaskExecutionServer(final int port) {
new Thread() {
#Override
public void run() {
try {
int counter = 0;
ServerSocket serverSocket = new ServerSocket(port);
while(true) {
System.out.println("Waiting for client...");
Socket socket = serverSocket.accept();
System.out.println("Accepted");
InputStream inputStream = socket.getInputStream();
PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
ObjectInputStream objectStream = new ObjectInputStream(pushbackInputStream);
for(int i; (i = pushbackInputStream.read()) != -1;) {
pushbackInputStream.unread(i);
String to = (String) objectStream.readObject();
System.out.println(to);
System.out.println(++counter);
}
objectStream.close();
pushbackInputStream.close();
inputStream.close();
System.out.println("Closing socket");
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
public static void main(String args[]) {
new TaskExecutionServer(2003);
}
}
or here again with try-with-resources which is preferable over manually closing AutoClosables.
public class TaskExecutionServer {
public TaskExecutionServer(final int port) {
new Thread() {
#Override
public void run() {
try (ServerSocket serverSocket = new ServerSocket(port)) {
int counter = 0;
while(true) {
System.out.println("Waiting for client...");
try (Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
ObjectInputStream objectStream = new ObjectInputStream(pushbackInputStream)) {
System.out.println("Accepted");
for(int i; (i = pushbackInputStream.read()) != -1;) {
pushbackInputStream.unread(i);
String to = (String) objectStream.readObject();
System.out.println(to);
System.out.println(++counter);
}
System.out.println("Closing socket");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
public static void main(String args[]) {
new TaskExecutionServer(2003);
}
}
available() is not a valid test for end of stream. See the Javadoc. You should read from the object stream until EOFException is caught.
I ask this question again here ( How to create Java socket that is localhost only? ) 'cause all before mentioned methods (simply to say to create one ServerSocket by 3 parameters method) can not solve my problem.
I am working in one big intranet in which, every time when I open one browser, I need enter my proxy account and password to access internet. This is why I hope to test my socket program on localhost.
Occasionally my Client side can connect the Server side, but usually I have to wait for a long time before she coming out. I suppose, it should be related with some of proxy/firewall.
Although I look over all following resources and believe all of them are well worth reading, but I still can not get my issues out.
http://zerioh.tripod.com/ressources/sockets.html
How to determine an incoming connection is from local machine
My Server Side Code
import java.net.Socket;
import java.net.ServerSocket;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.net.InetAddress;
public class Myserver {
private int serverPort = 8000;
private ServerSocket serverSock = null;
public Myserver(int serverPort) {
this.serverPort = serverPort;
try {
/*SocketAddress socketAddress = new InetSocketAddress(InetAddress.getByName("localhost"), serverPort);
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(socketAddress);
serverSocket.accept();*/
serverSock = new ServerSocket(serverPort, 0, InetAddress.getByName(null));
}
catch (IOException e){
e.printStackTrace(System.err);
}
}
public void handleConnection(InputStream sockInput, OutputStream sockOutput) {
while(true) {
byte[] buf=new byte[1024];
int bytes_read = 0;
try {
// This call to read() will wait forever, until the
// program on the other side either sends some data,
// or closes the socket.
bytes_read = sockInput.read(buf, 0, buf.length);
// If the socket is closed, sockInput.read() will return -1.
if(bytes_read < 0) {
System.err.println("Tried to read from socket, read() returned < 0, Closing socket.");
return;
}
System.err.println("Received "+bytes_read
+" bytes, sending them back to client, data="
+(new String(buf, 0, bytes_read)));
sockOutput.write(buf, 0, bytes_read);
// This call to flush() is optional - we're saying go
// ahead and send the data now instead of buffering
// it.
sockOutput.flush();
// sockOutput.close();
}
catch (Exception e){
System.err.println("Exception reading from/writing to socket, e="+e);
e.printStackTrace(System.err);
return;
}
}
}
public void waitForConnections() {
Socket sock = null;
InputStream sockInput = null;
OutputStream sockOutput = null;
while (true) {
try {
// This method call, accept(), blocks and waits
// (forever if necessary) until some other program
// opens a socket connection to our server. When some
// other program opens a connection to our server,
// accept() creates a new socket to represent that
// connection and returns.
sock = serverSock.accept();
System.err.println("Have accepted new socket.");
// From this point on, no new socket connections can
// be made to our server until we call accept() again.
sockInput = sock.getInputStream();
sockOutput = sock.getOutputStream();
}
catch (IOException e){
e.printStackTrace(System.err);
}
// Do something with the socket - read bytes from the
// socket and write them back to the socket until the
// other side closes the connection.
handleConnection(sockInput, sockOutput);
// Now we close the socket.
try {
System.err.println("Closing socket.");
sock.close();
}
catch (Exception e){
System.err.println("Exception while closing socket.");
e.printStackTrace(System.err);
}
System.err.println("Finished with socket, waiting for next connection.");
}
}
}
My Client Side Code
import java.net.Socket;
import java.net.ServerSocket;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
public class MyClient {
private String serverHostname = null;
private int serverPort =0;
private byte[] data = null;
private Socket sock = null;
private InputStream sockInput = null;
private OutputStream sockOutput = null;
public MyClient(String serverHostname, int serverPort, byte[] data){
this.serverHostname = serverHostname;
this.serverPort = serverPort;
this.data = data;
}
public void sendSomeMessages(int iterations) {
System.err.println("Opening connection to "+serverHostname+" port "+serverPort);
try {
sock = new Socket(serverHostname, serverPort);
sockInput = sock.getInputStream();
sockOutput = sock.getOutputStream();
}
catch (IOException e){
e.printStackTrace(System.err);
return;
}
System.err.println("About to start reading/writing to/from socket.");
byte[] buf = new byte[data.length];
int bytes_read = 0;
for(int loopi = 1; loopi <= iterations; loopi++) {
try {
sockOutput.write(data, 0, data.length);
bytes_read = sockInput.read(buf, 0, buf.length);
}
catch (IOException e){
e.printStackTrace(System.err);
}
if(bytes_read < data.length) {
System.err.println("run: Sent "+data.length+" bytes, server should have sent them back, read "+bytes_read+" bytes, not the same number of bytes.");
}
else {
System.err.println("Sent "+bytes_read+" bytes to server and received them back again, msg = "+(new String(data)));
}
// Sleep for a bit so the action doesn't happen to fast - this is purely for reasons of demonstration, and not required technically.
try { Thread.sleep(50);} catch (Exception e) {};
}
System.err.println("Done reading/writing to/from socket, closing socket.");
try {
sock.close();
}
catch (IOException e){
System.err.println("Exception closing socket.");
e.printStackTrace(System.err);
}
System.err.println("Exiting.");
}
}
My Test Code
import java.net.*;
public class Mytest {
public static void main(String[] args) {
String hostname = "localhost";
int port = 8000;
try {
InetAddress add = InetAddress.getLocalHost();
System.out.println( add);
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
byte[] data = "my program".getBytes();
MyClient client = new MyClient(hostname, port, data);
client.sendSomeMessages(10);
Myserver server = new Myserver(port);
server.waitForConnections();
}
}
I try telnet, but I can't connect it at all
The first problem is that the test code runs both the client and the server. In Mytest.main(), the main thread does the following:
Creates a client (I would have thought that this step would fail)
Tries to send some messsages (but no ServerSocket has been started)
The server is created
The server waits forever, blocking the main thread on accept()
As a starter to get your code working. Create two test classes TestServer and TestClient, both of these must have main() methods. Launch TestServer first in it's own Java process. Next launch TestClient in separate Java process. This should work!
After you've got everything working, you should introduce some concurrency into your server. The way that it's currently written it can only serve a single client at a time. Create new threads to manage new sockets returned from accept().
Good luck!
I am on windows 7 x64. I am writing a server which opens a thread for every incoming connection - the thread reads from the connection's input stream. The read() should block and throw an exception if the socket is closed(). It does not - just returns -1. If I do not close the connection from the client - just let the client terminate - I get a connection reset as excpected - but if I close() the connection from the client (or just the client's output stream for that matter) read() in the server thread does not throw - just returns -1. The docs are pretty clear on this :
public void close()
throws IOException
Closes this socket.
Any thread currently blocked in an I/O operation upon this socket will throw a SocketException.
Help
Working code :
Server :
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class CloseTest {
private int port;
public CloseTest(int port) {
this.port = port;
}
void base_station_activate() {
ServerSocket baseStationListeningSocket=null;
try {
baseStationListeningSocket = new ServerSocket(this.port, 1, InetAddress.getByName("127.0.0.1"));
} catch (IOException ex) {
}
main_server: while (true) {
try {
Socket clientSocket = baseStationListeningSocket.accept();
BaseStationClientHandler ch = new BaseStationClientHandler(clientSocket);
Thread myThread = new Thread(ch);
myThread.start();
} catch (IOException ex) {
System.exit(1);
} // main_server
finally {
// baseStationListeningSocket.close()
}
}
}
public static void main(String args[]){
CloseTest bs = new CloseTest(8082);
bs.base_station_activate();
}
public class BaseStationClientHandler implements Runnable {
private final Socket clientSocket;
private BaseStationClientHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
public void run() {
String debug_message = null;
try {
InputStream in = clientSocket.getInputStream();
// read message and respond
String s = "";
char x;
int r;
server: while (true) {
try {
while ((r = in.read()) != (int) '%') {
if (r == -1) {
debug_message = "Stream/socket .closed() - exception not thrown (WHYYYYY ????) by client";
System.out.println(debug_message);
break server;
}
x = (char) r;
s += x;
}
System.out.println(s);
} catch (SocketException socketException) {
System.out.println(socketException.getLocalizedMessage()); // if connection reset (but not if Stream/socket .closed()) read throws !!!!!
debug_message = "socket_reset";
break server;
}
s = "";
} //server
} catch (IOException ex) {
System.out.println("IOexception in client handler - check if thrown by read");
} finally {
try {
clientSocket.close();
} catch (IOException ex) {
}
}
}
}
}
Client :
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Vector;
public class CloseTestClient {
public CloseTestClient(int port, String ipAddress){
Vector<Socket> connections = new Vector<Socket>();
try {
for(int i=0;i<20;i++){
Socket connection = new Socket(InetAddress.getByName(ipAddress), port);
connections.add(connection);
OutputStream out = connection.getOutputStream();
out.write( ("CONNECT#"+(i+1)+"#1%").getBytes());
System.out.println("[CloseTestClient SENT]:"+"CONNECT#"+(i+1)+"#1%");
Thread.sleep(1000); // to be sure the server threads are blocked in the read()
// connection.close(); // if I comment this out I see the connection reset message from the server when this main terminates
// commented it out finally and moved the closing at the end to be sure the server threads are blocked in read()
}
} catch (Exception ex) {
ex.printStackTrace();
}
finally{
// if I comment *for* out I see the "connection_reset" message from the server when this main terminates
for (Socket c : connections){
try{
c.close();
}catch(Exception ex){
}
}
}
}
public static void main(String args[]){
System.out.println("CloseTestClient run !");
new CloseTestClient(8082,"127.0.0.1");
}
}
The bit of documentation you're referring to applies to threads on that machine, not remote threads. If you have thread A read()'ing on socket X, and thread B of the same process closes socket X, then an exception will be thrown for thread A's read call.
When a socket is close()'d on the the local machine, the remote machine can determine that there will be no more data coming over the socket so it returns -1 (see the read() documentation for InputStream). This is what is happening when you explicitly close the connection on the client. The server knows no more data will be coming so read() happily returns -1. There are no exceptional circumstances.
I'm guessing that when you let the client terminate without calling close() on the socket, the JVM or OS is sending a TCP RST instead of closing the connection nicely (sending TCP FIN). This causes the read() call on the server to throw an exception.