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]