Re: NIO writing to a channel
nooneinparticular314159@yahoo.com wrote:
The problem is, no matter what I do to set my
channel as writable, data is still only transmitted when the channel
has previously become readable from the remote client transmitting
data. For example, I can try the following on the channel:
public void RegisterChannelForWriting(SocketChannel Channel,
Selector S) {
//Register the socket channel for reading
try {
Channel.register(S, SelectionKey.OP_WRITE);
Doesn't that cancel interest in OP_READ? Have you got a similar method
to set OP_READ, which might be cancelling OP_WRITE?
Since I've not really practiced with nio, I thought I'd give it a go:
import java.util.*;
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.charset.*;
import java.nio.channels.*;
public class ServerFirst extends Thread {
public static void main(String[] args) throws Exception {
new ServerFirst().start();
}
private final ServerSocketChannel server;
private final Selector selector;
public ServerFirst() throws IOException {
selector = Selector.open();
server = ServerSocketChannel.open();
server.socket().bind(new InetSocketAddress(12000));
server.configureBlocking(false);
server.register(selector, SelectionKey.OP_ACCEPT);
}
private boolean processOneEvent() {
try {
System.err.printf("Waiting...%n");
selector.select();
for (SelectionKey key : selector.selectedKeys()) {
if (key.isAcceptable()) {
assert key.channel() == server;
SocketChannel channel = server.accept();
if (channel != null)
clients.add(new Client(channel));
else
System.err.printf("null accept%n");
}
if (key.isWritable()) {
Client client = (Client) key.attachment();
assert key.channel() == client.channel;
client.processOutput();
}
if (key.isReadable()) {
Client client = (Client) key.attachment();
assert key.channel() == client.channel;
client.processInput();
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
return true;
}
public void run() {
while (processOneEvent())
;
}
private Collection<Client> clients = new HashSet<Client>();
private class Client {
private Charset charset = Charset.forName("UTF-8");
private final SocketChannel channel;
private final ByteBuffer inBytes = ByteBuffer.allocate(1024);
private final CharBuffer inChars = CharBuffer.allocate(1024);
private final CharsetDecoder decoder = charset.newDecoder();
private final ByteBuffer outBytes = ByteBuffer.allocate(1024);
private final CharBuffer outChars = CharBuffer.allocate(1024);
private final CharsetEncoder encoder = charset.newEncoder();
public Client(SocketChannel channel) throws IOException {
this.channel = channel;
this.channel.configureBlocking(false);
outBytes.clear();
outBytes.compact();
System.err.printf("Connected from %s%n",
channel.socket().getRemoteSocketAddress());
channel.register(selector, SelectionKey.OP_READ, this);
send("Hello\r\n");
}
public void send(String message) throws IOException {
outChars.put(message);
outChars.flip();
outBytes.compact();
encoder.encode(outChars, outBytes, false);
outBytes.flip();
outChars.compact();
if (outBytes.remaining() > 0)
channel.register(selector,
SelectionKey.OP_READ |
SelectionKey.OP_WRITE,
this);
}
public void processOutput() {
try {
channel.write(outBytes);
encoder.encode(outChars, outBytes, false);
if (outBytes.remaining() == 0)
channel.register(selector, SelectionKey.OP_READ, this);
} catch (IOException ex) {
ex.printStackTrace();
clients.remove(this);
try {
channel.close();
} catch (IOException ex2) {
// Can't do much now.
}
}
}
public void processInput() throws IOException {
int code = channel.read(inBytes);
if (code < 0)
System.err.printf("Peer %s closes%n",
channel.socket().getRemoteSocketAddress());
inBytes.flip();
CoderResult result = null;
// Convert as many bytes as we can into chars, and print
// them out.
do {
result = decoder.decode(inBytes, inChars, code < 0);
if (result.isError()) {
clients.remove(this);
channel.close();
result.throwException();
}
inChars.flip();
System.out.print(inChars);
inChars.clear();
} while (result.isOverflow());
inBytes.compact();
if (code < 0) {
clients.remove(this);
channel.close();
}
}
}
}
I'm sure I've been sloppily ignoring some return values here and there...
--
ss at comp dot lancs dot ac dot uk