xnio实现SimpleEchoServer代码分析

12 阅读1分钟
package org.jboss.xnio.lihptest;

import org.xnio.*;
import org.xnio.channels.AcceptingChannel;
import org.xnio.channels.Channels;
import org.xnio.channels.StreamSinkChannel;
import org.xnio.channels.StreamSourceChannel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;


public final class SimpleEchoServer {

    public static void main(String[] args) throws Exception {

        class ReadListener implements ChannelListener<StreamSourceChannel> {

            private StreamSinkChannel sinkChannel;

            public ReadListener(StreamSinkChannel sinkChannel) {
                this.sinkChannel = sinkChannel;
            }
                 //5、所以客户端读通道的读事件就会经过handleEvent(StreamSourceChannel channel)处理,StreamSourceChannel channel就是读通道
            public void handleEvent(StreamSourceChannel channel) {
                final ByteBuffer buffer = ByteBuffer.allocate(512);
                int res;
                try {
                    //6、将数据读出,然后通过写通道sinkChannel写回,完成echo的效果。
                    while ((res = channel.read(buffer)) > 0) {
                        buffer.flip();

                        ByteBuffer view = buffer.asReadOnlyBuffer(); // 不影响原 buffer
                        String s = StandardCharsets.UTF_8.decode(view).toString();
                        System.out.println("recv[" + res + "B UTF-8]: " + s);

                        Channels.writeBlocking(sinkChannel, buffer);
                        buffer.clear();
                    }
                    Channels.flushBlocking(sinkChannel);
                    if (res == -1) {
                        channel.close();
                    } else {
                        channel.resumeReads();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    IoUtils.safeClose(channel);
                }
            }

        }

        class AcceptListener implements ChannelListener<AcceptingChannel<StreamConnection>>{

            @Override
            public void handleEvent(AcceptingChannel<StreamConnection> channel) {
                try {
                    StreamConnection accepted;
                    //3、通过accepted = channel.accept()得到客户端通道。
                    while ((accepted = channel.accept()) != null) {
                        System.out.println("accepted "
                                + accepted.getPeerAddress());
                        // 4、 accepted.getSourceChannel() 得到客户端读通道,然后通过setReadListener给客户端读通道设置读处理器。
                        // 构造ReadListener,给其传入accepted.getSinkChannel()客户端写通道。
                        // 然后客户端读通道开始监听读事件。
                        accepted.getSourceChannel().setReadListener(new ReadListener(accepted.getSinkChannel()));
                        accepted.getSourceChannel().resumeReads();
                    }
                } catch (IOException ignored) {
                }
            }
        }

        final XnioWorker worker = Xnio.getInstance().createWorker(OptionMap.EMPTY);

// 1、创建服务器通道AcceptingChannel<StreamConnection> serverChannel,底层是ServerSocketChannel,然后resumeAccepts开始监听新连接
// 2、有新连接的时候,监听器就是创建的AcceptListener, 它的handleEvent会去处理serverChannel
        AcceptingChannel<StreamConnection> serverChannel = worker
                .createStreamConnectionServer(new InetSocketAddress(12345),
                        new AcceptListener(), OptionMap.EMPTY);
        serverChannel.resumeAccepts();
    }
}

摘自: github.com/ecki/xnio-s…