[#2665] Continue writing on IOException when using DatagramChannel

Motivation:

As a DatagramChannel supports to write to multiple remote peers we must not close the Channel once a IOException accours as this error may be only valid for one remote peer.

Modification:

Continue writing on IOException.

Result:

DatagramChannel can be used even after an IOException accours during writing.
This commit is contained in:
Norman Maurer 2014-07-18 12:35:18 +02:00
parent 3ca19af2f8
commit 65718db3ec
4 changed files with 63 additions and 28 deletions

View File

@ -256,20 +256,27 @@ public final class EpollDatagramChannel extends AbstractEpollChannel implements
break; break;
} }
boolean done = false; try {
for (int i = config().getWriteSpinCount() - 1; i >= 0; i--) { boolean done = false;
if (doWriteMessage(msg)) { for (int i = config().getWriteSpinCount() - 1; i >= 0; i--) {
done = true; if (doWriteMessage(msg)) {
done = true;
break;
}
}
if (done) {
in.remove();
} else {
// Did not write all messages.
setEpollOut();
break; break;
} }
} } catch (IOException e) {
// Continue on write error as a DatagramChannel can write to multiple remote peers
if (done) { //
in.remove(); // See https://github.com/netty/netty/issues/2665
} else { in.remove(e);
// Did not write all messages.
setEpollOut();
break;
} }
} }
} }

View File

@ -138,27 +138,41 @@ public abstract class AbstractNioMessageChannel extends AbstractNioChannel {
} }
break; break;
} }
try {
boolean done = false;
for (int i = config().getWriteSpinCount() - 1; i >= 0; i--) {
if (doWriteMessage(msg, in)) {
done = true;
break;
}
}
boolean done = false; if (done) {
for (int i = config().getWriteSpinCount() - 1; i >= 0; i --) { in.remove();
if (doWriteMessage(msg, in)) { } else {
done = true; // Did not write all messages.
if ((interestOps & SelectionKey.OP_WRITE) == 0) {
key.interestOps(interestOps | SelectionKey.OP_WRITE);
}
break; break;
} }
} } catch (IOException e) {
if (continueOnWriteError()) {
if (done) { in.remove(e);
in.remove(); } else {
} else { throw e;
// Did not write all messages.
if ((interestOps & SelectionKey.OP_WRITE) == 0) {
key.interestOps(interestOps | SelectionKey.OP_WRITE);
} }
break;
} }
} }
} }
/**
* Returns {@code true} if we should continue the write loop on a write error.
*/
protected boolean continueOnWriteError() {
return false;
}
/** /**
* Read messages into the given array and return the amount which was read. * Read messages into the given array and return the amount which was read.
*/ */

View File

@ -291,10 +291,17 @@ public final class NioDatagramChannel
} else { } else {
writtenBytes = javaChannel().write(nioData); writtenBytes = javaChannel().write(nioData);
} }
return writtenBytes > 0; return writtenBytes > 0;
} }
@Override
protected boolean continueOnWriteError() {
// Continue on write error as a DatagramChannel can write to multiple remote peers
//
// See https://github.com/netty/netty/issues/2665
return true;
}
@Override @Override
public InetSocketAddress localAddress() { public InetSocketAddress localAddress() {
return (InetSocketAddress) super.localAddress(); return (InetSocketAddress) super.localAddress();

View File

@ -276,8 +276,15 @@ public class OioDatagramChannel extends AbstractOioMessageChannel
data.getBytes(data.readerIndex(), tmp); data.getBytes(data.readerIndex(), tmp);
tmpPacket.setData(tmp); tmpPacket.setData(tmp);
} }
socket.send(tmpPacket); try {
in.remove(); socket.send(tmpPacket);
in.remove();
} catch (IOException e) {
// Continue on write error as a DatagramChannel can write to multiple remote peers
//
// See https://github.com/netty/netty/issues/2665
in.remove(e);
}
} }
} }