Non-blocking mode for all sockets for sure. I like the algorithm. Seems like you almost certainly still avoid trying to write multiple times to a congestion controlled socket which must not happen. I'll modify my code to try your slightly different approach.
Chad Sent from my iPhone On Jan 8, 2013, at 3:45 AM, Julien Vermillard <[email protected]> wrote: > the trick is to try to write first with the socket configured in non > blocking mode, so if it's congestion controlled , the write will > fail instantaneously so we en-queue the message and set the OP_WRITE flag > on the selection key. > > > On Tue, Jan 8, 2013 at 3:24 AM, Chad Beaulac <[email protected]> wrote: > >> >> On Jan 7, 2013, at 11:58 AM, Emmanuel Lécharny wrote: >> >>> Le 1/7/13 2:19 PM, Chad Beaulac a écrit : >>>> If you don't push the data onto a queue and wait for the selector to >> fire, you could be trying to write data to a socket that is congestion >> controlled, which you shouldn't do. The writer should wait for the selector >> to fire saying the socket is writable before trying to write. >>> >>> The thing is that in any case, we do try to write into the socket. If >>> the socket internal buffer gets full, we won't be able to write any ore >>> data into it, and we will have to wait for the socket to inform the >>> selector when it's ready to accept more data. >>> >>> What I'm proposing is not any different, except that I bypass the queue >>> *if* and only *if* the socket is ready to accept new data. In other >>> words, the algorithm is : >>> o if there is a queue containing messages waiting for the socket to be >>> ready (OP_WRITE set ti true), then enqueue the new message. >>> o else try to write the message into the socket >>> - if we can't write the full message, set the SelectionKey to be >>> interested in OP_WRITE, and enqueue the remaining data. >>> - Otherwise, the data have already been written anyway, we are done >>> >>> This is the way MINA 2 works since it's inception. >>> >>> Is there anything wrong with that ? >> >> Potentially. You should not attempt to write to the socket unless the >> OP_WRITE selector key says the socket is writable. If the selector has >> fired and says the socket is writable before you try to write, it's not a >> problem. Otherwise, you should queue the data, let the Selector fire and >> then try to write. I don't see any way around queuing the data. >> You never want to try to write to a socket that is writable. If it isn't >> writable, it's closed or congestion controlled. This "edge-triggered" I/O >> approach works well. You don't know what "edge" you're on if you haven't >> registered for an event before you try to write. >> >> Pseudocode Algorithm. >> >> // Client provides data to this class to output onto the socket. >> public synchronized void put(Data data) { >> if (queue.isEmpty) { >> register(key, OP_WRITE); // output queue is empty. We need to >> register for the write event so the OS can tell us when it's ok to write. >> enqueue(data); // Put the data onto the ConcurrentLinkedQueue >> } >> else { >> enqueue(data); // Just put the data onto the queue. We're already >> registered for the write event. >> } >> } >> >> public void runEventLoop() { >> // handle events on Selector >> } >> >> >> // OP_WRITE fired for key >> public synchronized void writeData(key) { >> while (!queue.isEmpty()) { >> Data data = queue.dequeue(); >> writeForKey(key,data); >> if (data.remaining() > 0) { >> enqueue(data); >> break; // socket is congestion controlled. We're still >> registered for the write event. When the TCP queue drains, the write event >> will fire again >> } >> } >> if (queue.isEmpty()) { >> unregister(key, OP_WRITE); // We don't have data to write to >> this socket anymore. Unregister for the write event. >> } >> } >> >> >>> >>> -- >>> Regards, >>> Cordialement, >>> Emmanuel Lécharny >>> www.iktek.com >> >> Chad Beaulac >> Objective Solutions, Inc. >> www.objectivesolutions.com >> [email protected] >> >> >> >> >> >> >>
