0

I'm writing a server to exchange messages among clients. One issue left to be solved is how to release a channel when a client happens to be closed. What I do is to start a monitor thread in which the all-Clients map is monitored, and I attempt to remove() a channel if an exception been detected when trying write() to it. However, after closing a client, the write() method in monitor thread don't throw an exception so the useless channel will never be released. Anybody know why?

public class ServerMonitor extends Thread{
private Map<String, SocketChannel> allClients;
private Set set;
private Iterator it;
private Entry entry;
private SocketChannel channel;
private ByteBuffer buf;

public ServerMonitor(Map<String, SocketChannel> allClients) {
    this.allClients = allClients;
    buf = ByteBuffer.allocateDirect(10);
    byte b = 0;
    buf.put(b);
    buf.flip();
}

public void run(){
    while(true) {
        if(!allClients.isEmpty()) {
            set = allClients.entrySet();
            it = set.iterator();
            while(it.hasNext()) {
                entry = (Entry) it.next();
                channel = (SocketChannel) entry.getValue();
                try{
                    channel.write(buf);
                } catch(Exception e) {
                    allClients.remove(entry.getKey());
                    //set.remove(entry);
                }
            }
        }
        try {
            Thread.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

}

9000
  • 39,899
  • 9
  • 66
  • 104
dastan
  • 105
  • 6
  • `this.allClients = allClients;` <-- this is pretty dangerous unless you really know what you are doing... If the caller modifies the map, your class' map will see the changes! Good source for `ConcurrentModificationException`s... – fge Jun 21 '13 at 13:06
  • @fge I do want to perform this.allClients = allClients; because I need to modify the source allClients (release a useless channel) when the monitor thread has detected a channel which cannot be written bytes to. – dastan Jun 21 '13 at 13:14

2 Answers2

1

Writing to a TCP socket is buffered locally and put on the wire asynchronously. So you can't rely on the first write after the peer closes to fail. You can rely on a subsequent write failing, but it could take a number of writes to get there.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • So can I write bytebuffer.size() bytes to the channel so that I can detect exception in the first write? – dastan Jun 21 '13 at 13:29
  • I've just answered that. No. ByteBuffer.size() has nothing to do with it. – user207421 Jun 21 '13 at 13:32
  • Is the size depends on TCP itself? – dastan Jun 21 '13 at 13:36
  • What size are you talking about? – user207421 Jun 21 '13 at 23:19
  • You said I can't rely on the first time of write() to handle the IOExeption because bytes are written into a buffer but not immediately into the client. So I guess maybe there is a size in the buffer so that when the buffer has 'size' bytes then bytes will be delivered. – dastan Jun 22 '13 at 04:57
  • I can only repeat. You can't get an error on the first write. Period. There needs to have been a prior write that has caused an error to be returned. – user207421 Jun 22 '13 at 08:14
0

I've run into this issue when writing applications that send data over TCP. You've discovered that the only real way to know if a client has closed the connection is by the IOException on a call to write(...). This is pretty much the way it works.

There is a cleaner solution. First of all, you must always handle the case that a client disconnects without you knowing, and properly remove them when you get the IOException on write(...). However, if the client sends a message telling the server it is disconnecting, you can use that to close the connection when you see it.

VolatileDream
  • 1,083
  • 7
  • 15
  • Yea I really do as you say but a call to write(...) don't cause an IOException, this confuses me. – dastan Jun 21 '13 at 13:51
  • Like EJP has said, you can not rely on a particular write failing, but it will fail eventually. The more data you write to the socket, the faster it will fail. – VolatileDream Jun 21 '13 at 14:03