I'm using this code to detect if a server isn't connect
private boolean isServerListening() {
try {
s = new Socket("localhost", PORT);
return true;
} catch (IOException e) {
System.out.println(e);
return false;
}
}
and Thread to handle suddenly disconnected server
Thread checkServer = new Thread(() -> {
while (true) {
if (isServerListening()==false) {
JOptionPane.showMessageDialog(null, "Server is disconnected!");
System.exit(0);
}
}
});
The problem is:
I think the method took too much time (about 4 seconds) to execute and return.So is there a proper way?
No matter the server is connected or not, this Thread still show the JOptionPane and terminate my program.Am I wrong at some point?
There is no general solution that fits all. Bsically there are different types of "lost connection":
Your computer disconnects, so it knows immediatley that the connection is closed.
The other side disconnects, it might happen that this signal does not reach your computer, so it will still think that you are connected.
The physical connection breaks, both sides cannot inform the other side.
The Socket has the methods isConnected() and isClosed() which you should use.
The only way to check a connection surely is by sending a message and receiving an answer. Then it might take up to 60 seconds (by default) until your computer notices the lost connection.
Related
Explanation
I'm revisiting the project I used to teach myself Java.
In this project I want to be able to stop the server from accepting new clients and then perform a few 'cleanup' operations before exiting the JVM.
In that project I used the following style for a client accept/handle loop:
//Exit loop by changing running to false and waiting up to 2 seconds
ServerSocket serverSocket = new ServerSocket(123);
serverSocket.setSoTimeout(2000);
Socket client;
while (running){ // 'running' is a private static boolean
try{
client = serverSocket.accept();
createComms(client); //Handles Connection in New Thread
} catch (IOException ex){
//Do Nothing
}
}
In this approach a SocketTimeoutException will be thrown every 2 seconds, if there are no clients connecting, and I don't like relying on exceptions for normal operation unless it's necessary.
I've been experimenting with the following style to try and minimise relying on Exceptions for normal operation:
//Exit loop by calling serverSocket.close()
ServerSocket serverSocket = new ServerSocket(123);
Socket client;
try{
while ((client = serverSocket.accept()) != null){
createComms(client); //Handles Connection in New Thread
}
} catch (IOException ex){
//Do Nothing
}
In this case my intention is that an Exception will only be thrown when I call serverSocket.close() or if something goes wrong.
Question
Is there any significant difference in the two approaches, or are they both viable solutions?
I'm totally self-taught so I have no idea if I've re-invented the wheel for no reason or if I've come up something good.
I've been lurking on SO for a while, this is the first time I've not been able to find what I need already.
Please feel free to suggest completely different approaches =3
The problem with second approach is that the server will die if an exception occurs in the while loop.
The first approach is better, though you might want to add logging exceptions using Log4j.
while (running){
try{
client = serverSocket.accept();
createComms(client);
} catch (IOException ex){
// Log errors
LOG.warn(ex,ex);
}
}
Non-blocking IO is what you're looking for. Instead of blocking until a SocketChannel (non-blocking alternative to Socket) is returned, it'll return null if there is currently no connection to accept.
This will allow you to remove the timeout, since nothing will be blocking.
You could also register a Selector, which informs you when there is a connection to accept or when there is data to read. I have a small example of that here, as well as a non-blocking ServerSocket that doesnt use a selector
EDIT: In case something goes wrong with my link, here is the example of non-blocking IO, without a selector, accepting a connection:
class Server {
public static void main(String[] args) throws Exception {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
while(true) {
SocketChannel sc = ssc.accept();
if(sc != null) {
//handle channel
}
}
}
}
The second approach is better (for the reasons you mentioned: relying on exceptions in normal program flow is not a good practise) allthough your code suggests that serverSocket.accept() can return null, which it can not. The method can throw all kinds of exceptions though (see the api-docs). You might want to catch those exceptions: a server should not go down without a very good reason.
I have been using the second approach with good success, but added some more code to make it more stable/reliable: see my take on it here (unit tests here). One of the 'cleanup' tasks to consider is to give some time to the threads that are handling the client communications so that these threads can finish or properly inform the client the connection will be closed. This prevents situations where the client is not sure if the server completed an important task before the connection was suddenly lost/closed.
I am writing an application that streams data that clients can then listen to and receive. However I am running into an issue with closing a socket when a client is no longer listening.
What I do is create a ServerSocket, when then waits for a connection and once it is connected, I start streaming the data. However, once the client is no longer connected, I am stuck in a loop of streaming and cannot tell if anyone is listening. Is there a way around this?
try {
serverSocket = new ServerSocket(STREAM_PORT);
Socket clientSocket = serverSocket.accept();
PrintWriter pw = new PrintWriter(clientSocket.getOutputStream(), true);
while (true) {
pw.println("some data");
}
} catch (SocketException e) {
// Never occurs when client disconnects
} catch (IOException e) {
// Never occurs when client disconnects
}
I have tried using socket.isClosed(), but it always returns false. Am I approaching this from the wrong angle, or is there a way to do it. I would ideally not want the client to have to send the server a "end" command.
EDIT: Edited to reflect what current code I am running after #Rod_Algonquin suggestion
As you are using PrintWriter, which swallows I/O exceptions, you need to call checkError() after each write to see if an error has occurred.
Ok so my question is really simple as I have it I pretty much have a server and a client program, however I don't want my server to have to be on for client to run, so I want to have it so the client never stops searching for server and all I have to do is turn server on, does anyone know how I'd do that? thanks
Put it in a while loop. Keep in mind that this will stall your program until it connects, so you should probably do this on a separate thread.
boolean done = false;
while (!done) {
try {
// Socket initialization code
} catch (IOException e) {
if (!e.getMessage().equals(/* Error code for unable to find server */) {
done = true;
}
}
I'm currently involved in a project at school in which we are building a communication system to be used on Android phones. For this, we will be using a server which opens sockets towards all clients, making them communicate.
I've done several chat applications before without any problems with sockets or thread handling but this time, for some reason, it boogles my mind.
The problem is that the application starts to listen as soon as I initiate the ServerSocket object, serverSocket = new ServerSocket(5000), and not at the serverSocket.accept().
Why is that?
As soon as I use the following method:
public void startListen(String port) {
try {
serverSocket = new ServerSocket(Integer.parseInt(port));
portField.setEditable(false);
} catch (IOException e) {
printMessage("Failed to initiate serverSocket: " + e.toString());
}}
The port is showing up as Listening in the command prompt (using netstat). If I don't call it, the port is not listed as listening.
TCP 0.0.0.0:5000 Computer:0 LISTENING
So, is here anything I'm missing when using the ServerSocket object? My older programs using ServerSocket doesnt start listening until I call accept().
If you're talking about the Java ServerSocket, there's no listen method for it, presumably since it's distinct from a client-side socket. In that case, once it has a port number (either in the constructor or as part of a bind), it can just go ahead and listen automagically.
The reason "regular" sockets (a la BSD) have a listen is because the same type is used for client and server, so you need to decide yourself how you're going to use it. That's not the case with ServerSocket since, well, it's a server socket :-)
To be honest, I'm not sure why you'd care whether or not the listening is active before accept is called. It's the "listen" call (which is implicit in this class) that should mark your server open for business. At that point, the communication layers should start allowing incoming calls to be queued up waiting for you to call accept. That's generally the way they work, queuing the requests in case your program is a little slow in accepting them.
In terms as to why it does it, it's actually supposed to according to the source code. In the OpenJDK6 source/share/classes/java/net/ServerSocket.java, the constructors all end up calling a single constructor:
public ServerSocket(int port, int backlog, InetAddress bindAddr)
throws IOException {
setImpl();
if (port < 0 || port > 0xFFFF)
throw new IllegalArgumentException(
"Port value out of range: " + port);
if (backlog < 1)
backlog = 50;
try {
bind(new InetSocketAddress(bindAddr, port), backlog);
} catch(SecurityException e) {
close();
throw e;
} catch(IOException e) {
close();
throw e;
}
}
And that call to bind (same file) follows:
public void bind(SocketAddress endpoint, int backlog) throws IOException {
if (isClosed())
throw new SocketException("Socket is closed");
if (!oldImpl && isBound())
throw new SocketException("Already bound");
if (endpoint == null)
endpoint = new InetSocketAddress(0);
if (!(endpoint instanceof InetSocketAddress))
throw new IllegalArgumentException("Unsupported address type");
InetSocketAddress epoint = (InetSocketAddress) endpoint;
if (epoint.isUnresolved())
throw new SocketException("Unresolved address");
if (backlog < 1)
backlog = 50;
try {
SecurityManager security = System.getSecurityManager();
if (security != null)
security.checkListen(epoint.getPort());
getImpl().bind(epoint.getAddress(), epoint.getPort());
getImpl().listen(backlog);
bound = true;
} catch(SecurityException e) {
bound = false;
throw e;
} catch(IOException e) {
bound = false;
throw e;
}
}
The relevant bit there is:
getImpl().bind(epoint.getAddress(), epoint.getPort());
getImpl().listen(backlog);
meaning that both the bind and listen are done at the lower level when you create the socket.
So the question is not so much "why is it suddenly appearing in netstat?" but "why wasn't it appearing in netstat before?"
I'd probably put that down to a mis-read on your part, or a not-so-good implementation of netstat. The former is more likely unless you were specifically testing for a socket you hadn't called accept on, which would be unlikely.
I think you have a slightly wrong idea of the purpose of accept. Liken a ServerSocket to a queue and accept to a blocking dequeue operation. The socket enqueues incoming connections as soon as it is bound to a port and the accept method dequeues them at its own pace. So yes, they could have named accept better, something less confusing.
A key reason may be myServerSocket.setSoTimeout(). The accept() call blocks - except if you define a timeout before calling it, then it only blocks for that duration and afterwards, harmlessly (i.e. ServerSocket is still valid), throws a SocketTimeoutException.
This way, the thread stays under your control ... but what happens in those milliseconds while you're not in your temporarily blocking accept() call? Will clients find a listening port or not? - That's why it's a good thing the accept() call is not required for the port to be listening.
The problem is that the application starts to listen as soon as I
initiate the ServerSocket object, serverSocket = new ServerSocket(5000), and not at the serverSocket.accept().
I'm thankful for this question (-> upvote) because it's exactly this behavior I wanted to know about, without having to do the experiment. Google-term was 'java serversocket what happens if trying to connect without accept', this question was in the link list of the first hit.
I have a java app that holds open many connections to an address, probably in the ballpark of 2,000 at once, with hardly any activity, mostly open for monitoring purposes passing a few bytes every now and then. When new connections need to be opened up, it automatically opens them and adds them to its pool. Sometimes though, for an unknown reason, the application receives a ClosedByInterruptException immediately during/after creating the socket to the remote address. To the best of my knowledge, this only occurs on the client side as a result of an interrupt signal to the thread. I have checked and rechecked the source code surrounding the problem area and it seems ok. I was hoping I could get someone's expertise as to if there could be an alternate cause, besides source code, for instance, is there a system reason that causes this? Is there a hardware cause? Server level/router level? My network knowledge I would consider amateur, but is 2K connections too many for a router, or no?
INFO [08 Sep 2011 23:11:45,982]: Reconnecting id 20831
ERROR [08 Sep 2011 23:11:45,990]: IOException while creating plain socket channel
java.nio.channels.ClosedByInterruptException
at java.nio.channels.spi.AbstractInterruptibleChannel.end(AbstractInterruptibleChannel.java:184)
at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:518)
at com.*.createSocketChannelPlain(MyTask.java:441)
at com.*._executeTask(MyTask.java:176)
at com.*.executeTask(MyTask.java:90)
at com.*.ThreadPool$WorkerThread.run(ThreadPool.java:55)
ERROR [08 Sep 2011 23:11:45,990]: Could not open socket
WARN [08 Sep 2011 23:11:45,990]: WorkerThread_24 received interrupted exception in ThreadPool
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at com.*.TaskQueue.getTask(TaskQueue.java:39)
at com.*.ThreadPool$WorkerThread.run(ThreadPool.java:48)
Update: I would like to try and offer all I can to help others contribute to a diagnosis. So here is the actual function where the exception occurs, only difference being the line marking I added to line 441.
private SocketChannel createSocketChannelPlain() throws TaskFailedException {
SocketChannel socketChannel = null;
try {
// Create a non-blocking socket channel to use to communicate for imap connection
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
try {socketChannel.socket().setSoLinger(true, 0);} catch (Exception e) {}
try {socketChannel.socket().setKeepAlive(true);} catch (Exception e) {}
/*Line 441*/ socketChannel.connect(new InetSocketAddress(_HOSTNAME, _PORT));
//System.out.println("Started connection");
// Complete connection
while (!socketChannel.finishConnect()) {
// do something until connect completed
try {
//do what you want to do before sleeping
Thread.sleep(500);//sleep for 500 ms
//do what you want to do after sleeping
} catch(InterruptedException ie){
//If this thread was interrupted by another thread
try { socketChannel.close(); } catch (Exception e) {}
finally { socketChannel = null; }
break;
}
}
//System.out.println("Finished connecting");
return socketChannel;
} catch (IOException e) {
logger.error("IOException while creating plain socket channel to gmail", e);
try { socketChannel.close(); } catch (Exception e1) {}
finally { socketChannel = null; }
//throw new TaskFailedException("IOException occurred in createSocketChannel");
}
return socketChannel;
}
What OS are you running this on? I don't know about Windows, but on Linux (and presumably other Unix-like OSes), you can run out of file handles by having large numbers of sockets. You can work around this by doing ulimit -n 8192 or similar before running the Java app. Alternatively, edit /etc/security/limits.conf and set nofile. All of that said, ClosedByInterruptedException would be an odd way to notice this.
If the above isn't the issue, the next thing I'd try would be to run tcpdump (if we're talking about a GUI-less machine) or Wireshark (if we aren't) and capture the traffic your program's generating, looking for weird things happening at the time that connection starts.