6

Using the default socket implementation on Windows, I was not able to find any effective method to stop Socket.connect(). This answer suggests Thread.interrupt() will not work, but Socket.close() will. However, in my trial, the latter didn't work either.

My goal is to terminate the application quickly and cleanly (i.e. clean up work needs to be done after the socket termination). I do not want to use the timeout in Socket.connect() because the process can be killed before a reasonable timeout has expired.

import java.net.InetSocketAddress;
import java.net.Socket;


public class ComTest {
    static Socket s;
    static Thread t;

    public static void main(String[] args) throws Exception {
        s = new Socket();
        InetSocketAddress addr = new InetSocketAddress("10.1.1.1", 11);
        p(addr);
        t = Thread.currentThread();
        (new Thread() {
            @Override
            public void run() {
                try {
                    sleep(4000);
                    p("Closing...");
                    s.close();
                    p("Closed");
                    t.interrupt();
                    p("Interrupted");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
        s.connect(addr);
    }

    static void p(Object o) {
        System.out.println(o);
    }
}

Output:

/10.1.1.1:11
Closing...
Closed
Interrupted
(A few seconds later)
Exception in thread "main" java.net.SocketException: Socket operation on nonsocket: connect
Community
  • 1
  • 1
billc.cn
  • 7,187
  • 3
  • 39
  • 79
  • *Why* are you trying to close a socket during connect? If it's to impose a connect timeout, you can do that with the API. – user207421 Jan 26 '13 at 03:22
  • @EJP This is a business application where every operation needs to be atomic. However, it runs on tomcat where the stop command has a timeout. If the socket happens to be in the connect call when the tomcat shuts down, we found that the clean up code in the socket thread does not run. – billc.cn Jan 26 '13 at 10:57
  • So you shouldn't do anything that needs cleaning up afterwards until you have the connection. – user207421 Jan 27 '13 at 00:32

1 Answers1

4

You fork the thread and then the main thread is trying to make the connection to the remote server. The socket is not yet connected so I suspect s.close() does nothing on a socket that is not connected. It's hard to see what the INET socket implementation does here. t.interrupt(); won't work because the connect(...) is not interruptible.

You could use the NIO SocketChannel.connect(...) which looks to be interruptible. Maybe something like:

SocketChannel sc = SocketChannel.open();
// this can be interrupted
boolean connected = sc.connect(t.address);

Not sure if that would help though.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • Yeah, that is my guess as well. However, there must be some alternative implementation that can be killed... – billc.cn Jan 25 '13 at 19:38
  • Looking at the documentation, it seems one of the major advantage of SocketChannel is the ability to stop `connect()`. I'll give it a try later, but I believe it is the solution. Thanks! – billc.cn Jan 25 '13 at 21:19
  • Actually, it seems the API requires you to use a Selector to really have a easy to interrupt behavior (i.e. if the channel is non-blocking, then you need a selector to know when it is actually connected). Otherwise will have to spin on `SocketChannel.finishConnect()`. Temporarily unmark as answer to see if other people have better alternatives (unlikely though :[ ). – billc.cn Jan 26 '13 at 15:01