0

I actually had a much bigger question, but I reduced it:

How does Socket.connect() behave when close() was called on that Socket before, but no connection attempt was made previously?

Multithreading/Threads is related, because I have one thread that is doing the connecting and one that invokes this and may abort the connection before being connected. Due to the joys of multithreading, an abort could be made before connect() is actually called, even if I synchronized-check with a boolean before. (lets say the abort code gets called just before connect() is doing its work, but after connect() was called - at the beginning of the method for example.)

Some code, heavily reduced:

public class Connecter {
    private Socket socket;

    public void connect() {
        // start the connecting thread, synchronized
    }

    public void abort() {
        // synchronized as well: closes the socket, nulls the refernce, sets a boolean value to true (aborted)
    }

    private class ConnectingThread extends Thread {
        public void run() {
            try {
                // synchronized: create a socket object and set stuff such as TCP_NODELAY
                socket.connect(new InetSocketAddress(ip, port));
                // handle stuff afterwards, synced of course
            } catch (Exception ex) {
                // wow. such exceptions. much handling.
            }
        }
    }
}
AyCe
  • 727
  • 2
  • 11
  • 30
  • 2
    Have you tried it? What does it do? – Gray Feb 21 '14 at 23:00
  • @Gray: Well, for every case now it behaved exactly as it should: It wasn't called at all, because I nulled the socket reference, or it aborted the connect (not my question, I knew this should happen). I edited my question to express why this is still worrying to me. – AyCe Feb 21 '14 at 23:02
  • why you don't post a snippet of code of your problem ! – Scorpion Feb 21 '14 at 23:07
  • @Scorpion Added some code :) – AyCe Feb 21 '14 at 23:13
  • `lets say the abort code gets called just before connect() is doing its work, but after connect() was called - at the beginning of the method for example.` I don't see the issue here, why can't you guarantee that `connect` have finished its work before allowing `close` to run? There are a dozen ways to achieve that, for instance, [Lock Objects](http://docs.oracle.com/javase/tutorial/essential/concurrency/newlocks.html) – Anthony Accioly Feb 21 '14 at 23:44
  • @Anthony You might not have fully understood my question. What `connect()` does after the VM jumps into the method is beyond my control. And I _don't want_ to run `close` _after_ connect, but at _any time_: If run _before_ `connect()` is called, connect should throw a `NullPointerException` or a special Socket-Exception that tells me the socket was closed previously (see EJP's answer). If called _while_ doing the connecting, it should abort it, which it does just fine. If called _after_ connect, it depends if the synced-block after it was reached already. If yes, do nothing, otherwise close. – AyCe Feb 22 '14 at 00:24
  • Ok, so let's make your question clear. You are asking: "What happens if `Connecter.abort` gets called, after a `new Socket` is created but before `socket.connect` finish its business. Right or wrong? – Anthony Accioly Feb 22 '14 at 00:35
  • @Anthony Right. You replied `I don't see the issue here, why can't you guarantee that connect have finished its work before allowing close to run?` Because of synchronization of course. `connect()` does block and I don't want it to hold a lock while it's blocking. It would mean that indeed `close()` would only get called after `connect()`. But I want it to be callable at any time. My question was how it does behave if it happens to be called before or while `connect()` is working. Hope that cleared it up :) – AyCe Feb 22 '14 at 00:44
  • Ayce. Then I've understand your question correctly and my comment still holds. You are worried about intermediate unsafe states between object creation and the end of `socket.connect` (which indeed you should - [check OpenJDK source](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/java/net/Socket.java#Socket.connect%28java.net.SocketAddress%29), close might be called after `impl.create(stream)` and before `created = true`, in a way that internally `impl.close()` might never be called), I'm telling you, do not take the risk - make this step atomic. – Anthony Accioly Feb 22 '14 at 01:34
  • @Anthony Make what atomic? Connecting? But my whole point is that the user should be able to abort the connecting process. What you just told me makes me worry me even more. Of course I could add a check that will just close the socket as soon as it's connected if the user called the abort function during the process. I have used the method I showed for quite a while now and it never caused problems. Will a `close()` on a wrong time crash anything? I made sure that there is no way for the thread to exit without the connect being successful or aborted completely. – AyCe Feb 22 '14 at 04:49
  • TCP stacks on multithreaded OS are thread-safe. Don't worry about it - you will get exceptions raised or errors returned, but you will not crash anything. – Martin James Feb 22 '14 at 09:10
  • @Ayce, yes. Just use some lock / condition to avoid a call to `socket.close` while `socket.connect` is running. As soon as you release the lock `close` you run and everything will be beautiful. Don't worry too much about canceling connections "in progress"; while establishing a connection can take some time, `closing` a connection under construction will not be that common. (If you really, really need to do it go with [SocketChannel](http://docs.oracle.com/javase/7/docs/api/java/nio/channels/SocketChannel.html) which is thread safe). – Anthony Accioly Feb 22 '14 at 10:29
  • @Anthony But that's just what I'm doing ATM and want to keep doing. `close()` actually cancels the `connect()`, it will throw an exception, so it's just what I want. And it works, but I just don't know it will ALWAYS work - until now I had assumed that it would. From the technical side it would be a matter of 1 minute to change the code accordingly, but then the "cool" connect-kill function is gone and the socket still attempts to connect while the program isn't actually interested in the result anymore. – AyCe Feb 22 '14 at 11:02
  • @MartinJames That's what I've thought until now - the people who did all the low-level stuff are geniuses anyway, so they will probably have prepared their components for such situations or at least patched out such "obvious" bugs (synchronization issues with connect/close) in the mean time. :) – AyCe Feb 22 '14 at 11:05

1 Answers1

1

How does Socket.connect() behave when close() was called on that Socket before, but no connection attempt was made previously?

It will throw a SocketException with the text 'Socket is closed.'

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Apparently, that's what I've gotten as a result as well. I'm still a bit worried about the problem I explained, but if the VM programmers did their job properly, this should be handled just fine. Thanks :) – AyCe Feb 21 '14 at 23:27
  • Why do you have a separate `connect()` thread? Are you aware of the `connect()` timeout parameter? – user207421 Feb 21 '14 at 23:52
  • Because I want the UI to keep responding to user input, for example. And yes, I am aware. :) Thanks btw, you're probably the person that has helped me the most since I joined SO! – AyCe Feb 22 '14 at 00:18
  • Just to point out, while `close()` implementation uses a internal `lock` - there is no guarantee that interleaving `connect` and `close` will not break the `Socket` internal state. Actually there are no guarantees that `Socket` is thread safe at all. See the discussion [here](http://stackoverflow.com/questions/6672413/in-what-way-is-java-net-socket-threadsafe/6672582#6672582) (involving @EJP by the way :D). While, like EJP, I've seen sockets used in concurrent environments. We shouldn't assume thread-safe behavior, the client should properly handle concurrency. – Anthony Accioly Feb 22 '14 at 02:05
  • This does not make EJP answer wrong; if `connect` is called **after** `close` we will receive an `SocketException`. But if `close` gets called during the execution of [Socket.connect](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/java/net/Socket.java#Socket.connect%28java.net.SocketAddress%29) there is room for the socket to be marked as closed while its [SocketImpl](http://docs.oracle.com/javase/7/docs/api/java/net/SocketImpl.html) remains open. – Anthony Accioly Feb 22 '14 at 02:13
  • @Anthony whenever I think that my code is failsafe, someone, including myself, proves me wrong :) It's interesting, although the actual work on the socket is performed in 1 sender and 1 receiver thread in my code, any thread could cause it to `close()`. So what impact would this have on my existing code? It should not be problematic to use `close()` after the initial initialization I assume - since it's basically the only way to interrupt a blocked (read/write calls) socket. – AyCe Feb 22 '14 at 04:56
  • James, you are right about this, but the underlying model be thread safe does not mean that java Socket layer will not have concurrency problems (I just pointed some interleaving logic that can trick Open JDK Socket implementation into flagging itself as closed its internal `SocketImpl`), the point here is, do not assume that anything is thread safe unless the Javadocs tells you so. – Anthony Accioly Feb 22 '14 at 10:00
  • @AyCe, from the Open JDK implementation details I could grasp, after `connect` returns there should be no problem calling `close`, of course that those are implementation details subject to change, but I wouldn't worry about it. As EJP wrote in the linked thread, I doubt that anyone would dare make a change that would break gazillions of lines of code dependent on this behavior. – Anthony Accioly Feb 22 '14 at 10:04
  • @MartinJames Irrelevant. The question isn't about the behaviour of TCP stacks on multitasking OS's. It is about the behaviour of Java.lang.Socket, which runs in user space, and whose behaviour is ascertainable from the Javadoc and the source code. Can we stick to the point please. – user207421 Feb 22 '14 at 10:42
  • @AnthonyAccioly You're right, I got this point by now, thanks. :) And indeed I'm considering using what you proposed. But as I said, that would remove the ability to abort a running attempt to connect. Maybe I should subclass Socket if I really want my functionality to stay? – AyCe Feb 22 '14 at 11:25
  • Ayce, I wouldn't open this can of worms. [SocketChannel](http://docs.oracle.com/javase/7/docs/api/java/nio/channels/SocketChannel.html) wouldn't cut it? – Anthony Accioly Feb 22 '14 at 15:57