File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Sockets and Internet Protocols and the fly likes interrupting a Socket.accept() Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Java » Sockets and Internet Protocols
Bookmark "interrupting a Socket.accept()" Watch "interrupting a Socket.accept()" New topic
Author

interrupting a Socket.accept()

M Beck
Ranch Hand

Joined: Jan 14, 2005
Posts: 323
here's the situation:
  • my main thread is in a while loop so long as a private boolean stays true.
  • in this loop, the main thread will mostly spawn off subthreads as needed, and hand them each a reference to itself. (to the object the main thread is looping in, anyway, i mean.)
  • the subthreads use their reference to the main thread's object to call methods in the main class.
  • one of these callback methods should be able to set that private boolean false, causing the main thread to exit.

  • the problem is, the main method spends most of its time blocked on I/O waiting for clients to connect to a ServerSocket. therefore, the loop it's in never ends, since even if the boolean gets changed to false, the loop's still blocked on the socket.

    how do i wake it up? is there any way i can raise an InterruptedException, perhaps from the subthread or the callback, such that the main loop has to catch it?
    David Harkness
    Ranch Hand

    Joined: Aug 07, 2003
    Posts: 1646
    If you're using JDK 1.4 and the server socket you're using happens to be backed by an InterruptibleChannel, you can interrupt() the main thread.
    If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.
    If you're pre-1.4, I think you need to set the server socket's SoTimeout before entering your accept() loop. If you don't get a connection request, accept() returns null I guess and you can then test your boolean.
    M Beck
    Ranch Hand

    Joined: Jan 14, 2005
    Posts: 323
    thanks, that did it. i'm still confused about threads... enough so that i'm seriously considering trying your second suggestion, even though i'm on 1.4, just so i won't have to mess around so much with Thread references!

    for reference: i now pass a reference to the main thread in to my subthreads. (that reference can be retrieved using a static method in class Thread, btw.) then, after using the callback to set the boolean variable to false, the subthreads can do mainThread.interrupt() and have that show up as an IOException in the main thread's mostly-blocked loop.

    i'm only worried about what might happen if one subthread interrupts the main thread during one of the fractional-second periods when it isn't blocked on accept() but rather managing subthread creation. maybe i should just set that timeout on the socket and spin on that...
    [ April 16, 2005: Message edited by: M Beck ]
    David Harkness
    Ranch Hand

    Joined: Aug 07, 2003
    Posts: 1646
    It takes several projects to get comfortable with threads. It doesn't help that some of the methods in Thread (the static ones) work on the current thread. They seem to follow the Singleton pattern because they're static and operate on "the" thread, yet "the" thread changes from moment to moment.

    I have two very different suggestions. One is to switch over to using the new 1.4 NIO non-blocking sockets so you don't have to have one thread per connection. While it would be a cleaner solution, it's still complex and requires learning NIO on top of threads. It would be fun, though.

    The other idea is to take a look at Doug Lea's Concurrent library, specifically the PooledExecutor class (thread pool). It manages a queue of work and a pool of worker threads to process it. His code is very well tested, robust, documented, and a great example for threading work. I used it to build part of an HTTP/S proxy server about five years ago.

    Regardless of which way you go, you still need to handle the signaling from the worker threads back to the accept thread. Is "got an exit signal from client -- close server socket and exit" the only message the workers give to the accept thread? If so, it's pretty straight-forward. The key is synchronization around the boolean flag.

    First, don't give out references to the accept thread. Instead, create a class to encapsulte the ServerSocket and Thread. Implement Runnable and set it up with a reference to the Thread that's running it. This class (I think you have a class for it already from what you wrote above) would have the accept loop and two synchronized methods for dealing with the "canceled" flag.I'm not sure on this ... back of the napkin design and all that. So the race condition is that a worker thread could call cancel() while the accept thread is suspended at the line marked "DANGER!!" The canceled flag would be set -- too late -- and the accept thread would be interrupted -- too early -- and then the accept thread would block on the accept() call.

    Therefore, I combined the timeout approach which will cover that condition. Now, I was just looking at ServerSocket and noticed that if you call close() on it while another thread is blocked on accept(), the blocked thread aborts the accept() call and gets a SocketException. I didn't see in the docs what happens if you call accept() on an already-closed SS. I assume you get an IOException, but you'd have to test it out. Besides, I don't know if that makes it any cleaner. I think you could get rid of the canceled flag, though, which would simplify the logic.

    Anyway, play around with that and let us know how it goes.
    M Beck
    Ranch Hand

    Joined: Jan 14, 2005
    Posts: 323
    i considered learning NIO myself, but there's only so much i could do with it; i'm writing this for a class assignment, and the requirements explicitly specify multithreading, so i've got to bite this bullet whether i like the taste or not. :roll: for any project of my own, i would definitely go that way; i'm more familiar and comfortable with the single-threaded, non-blocking strategy from my pre-Java experience, anyway.

    thread pooling sounds like the right way to go for a robust, real-life threaded design, but i get the feeling i had better understand the basics about threading before i jump into anything more complex and abstracted than just "plain vanilla" threads. the design i've got right now is all kinds of messy and ugly, but it works for the very limited needs i have, and i think mucking about with something i can more or less understand is more likely to teach me what i need to learn for now.

    and my needs are fairly simplistic. the worker threads will need to use several callbacks to the main class, but they can do that in their own context; the only real signal they'll have to send the main thread is "quit listening to that socket and close up shop". i know that the framework i've made for sending it is jerry-rigged and shakey, but so long as it keeps working i'm wary of spending more of my limited time learning how to build a better one, especially since it would only get used by one single signal.

    i considered an approach similar to the one you're recommending, and i think if i get the time to mess around more with the server side of my code, i'll switch over to it after all. (for now, i've got the client side to write... make it a bit easier for me to test the whole thing once that's up.) but my main problem right now is keeping the difference between "thread" and "class" straight in my head.

    as of right now, all my worker threads are instances of a separate class that does nothing else, and which extends Thread. the ServerSocket work is done in the main thread, which runs in the main class of the project. so are you saying i should make the main class extend Runnable (or Thread?) and start another thread in it? or rather that i should make a singleton class extending Runnable (Thread?) and start a single thread running that? i'm assuming the latter, since that would confuse me less.

    right now, i'm not doing any synchronization on the boolean, either. i did worry about that, for a moment, but decided not to. i thought, it's a boolean; it can only have two states, it starts out in one, and once switched to the other it can never be switched back -- so what if a couple of threads have a race condition on switching its state? it's not like they'll block on it, after all, right? if it were an object, or had more complicated state than it does, then of course i wouldn't be so flippant about it.

    i don't think your concerns in your last paragraph apply to my situation; i'll only ever have a single thread working with the ServerSocket, so there's no way i'll end up calling accept() on it after it's closed, or try to close it while it's blocked on accept.

    for right now, i think i'll add the timeout to the ServerSocket for a bit more robustness, and if i get the time i'll split this code off into its own class (and possibly thread) for clarity. thanks for your advice; now, i've got a client GUI to design...
    David Harkness
    Ranch Hand

    Joined: Aug 07, 2003
    Posts: 1646
    Originally posted by M Beck:
    so are you saying i should make the main class extend Runnable (or Thread?) and start another thread in it? or rather that i should make a singleton class extending Runnable (Thread?) and start a single thread running that?
    I hadn't considered that you were using the main thread. I normally use Runnable instead of extending Thread as it's cleaner, expresses the intent better (I'm not altering how threads behave), and keeps me from exposing methods I don't want the clients of my class calling (interrupt for one).

    However, in your case I'd just pass a reference to the main thread to the Server class. You could still implement Runnable from Server, and just call run() on it from your main code to get it into the loop. There's no reason Thread has to call run().
    i thought, it's a boolean; it can only have two states, it starts out in one, and once switched to the other it can never be switched back -- so what if a couple of threads have a race condition on switching its state? it's not like they'll block on it, after all, right?
    I used to feel the same way until I read through the JLS section on threading. The thing is, each thread is allowed to put variables into registers for optimization. Since the boolean is used in a tight loop, it's quite possible that it will be cached in a register and never checked in memory again. In that case, it wouldn't pick up the changed value. Synchronizing forces it to be pulled from memory again. Another way is to mark that field volatile. Then every time it is accessed, it must be accessed directly from memory.

    The reason for synchronization is to keep the accept thread from checking the value while a worker thread is in the cancel() method. For your needs I'd say you can safely get away with merely marking it volatile and moving on.
    i don't think your concerns in your last paragraph apply to my situation; i'll only ever have a single thread working with the ServerSocket, so there's no way i'll end up calling accept() on it after it's closed, or try to close it while it's blocked on accept.
    My last paragraph was actually me musing on a different way of implementing the cancellation logic -- not a concern that multiple threads would close the socket. Instead of using interrupt, I was suggesting closing the socket directly. This would kick the main thread out of its accept() state with an exception. It was just another method of achieving the same thing.

    Since this is for a class assignment and you have other things to do, I'd go with what you're doing: move on to the client. At most I'd recommend making the boolean volatile to be extra safe, and it's a ten second fix.

    Good luck with your client!
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: interrupting a Socket.accept()