使用Java NIO编写高性能的服务器

View Code
package nio.file;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;

/**
 * 测试文件下载的NIOServer
 * 
 * 
@author tenyears.cn
 
*/
public class NIOServer {
    static int BLOCK = 4096;

    // 处理与客户端的交互
    public class HandleClient {
        protected FileChannel channel;
        protected ByteBuffer buffer;

        public HandleClient() throws IOException {
            this.channel = new FileInputStream(filename).getChannel();
            this.buffer = ByteBuffer.allocate(BLOCK);
        }

        public ByteBuffer readBlock() {
            try {
                buffer.clear();
                int count = channel.read(buffer);
                buffer.flip();
                if (count <= 0)
                    return null;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return buffer;
        }

        public void close() {
            try {
                channel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    protected Selector selector;
    protected String filename = "D:\\Downloads\\QqAd.rar"; // a big file
    protected ByteBuffer clientBuffer = ByteBuffer.allocate(BLOCK);
    protected CharsetDecoder decoder;

    public NIOServer(int port) throws IOException {
        selector = this.getSelector(port);
        Charset charset = Charset.forName("GB2312");
        decoder = charset.newDecoder();
    }

    // 获取Selector
    protected Selector getSelector(int port) throws IOException {
        ServerSocketChannel server = ServerSocketChannel.open();
        Selector sel = Selector.open();
        server.socket().bind(new InetSocketAddress(port));
        server.configureBlocking(false);
        server.register(sel, SelectionKey.OP_ACCEPT);
        return sel;
    }

    // 监听端口
    public void listen() {
                try {
                  for (;;) {
                    selector.select();
                    Iterator<SelectionKey> iter = selector.selectedKeys()
                        .iterator();
                    while (iter.hasNext()) {
                      SelectionKey key = iter.next();
                      iter.remove();
                      handleKey(key);
                    }
                  }
                } catch (IOException e) {
                  e.printStackTrace();
                }
              }

    // 处理事件
    protected void handleKey(SelectionKey key) throws IOException {
        if (key.isAcceptable()) { // 接收请求
            ServerSocketChannel server = (ServerSocketChannel) key.channel();
            SocketChannel channel = server.accept();
            channel.configureBlocking(false);
            channel.register(selector, SelectionKey.OP_READ);
        } else if (key.isReadable()) { // 读信息
            SocketChannel channel = (SocketChannel) key.channel();
            int count = channel.read(clientBuffer);
            if (count > 0) {
                clientBuffer.flip();
                CharBuffer charBuffer = decoder.decode(clientBuffer);
                System.out.println("Client >>" + charBuffer.toString());
                SelectionKey wKey = channel.register(selector,
                        SelectionKey.OP_WRITE);
                wKey.attach(new HandleClient());
            } else
                channel.close();
            clientBuffer.clear();
        } else if (key.isWritable()) { // 写事件
            SocketChannel channel = (SocketChannel) key.channel();
            HandleClient handle = (HandleClient) key.attachment();
            ByteBuffer block = handle.readBlock();
            if (block != null)
                channel.write(block);
            else {
                handle.close();
                channel.close();
            }
        }
    }

    public static void main(String[] args) {
        int port = 12345;
        try {
            NIOServer server = new NIOServer(port);
            System.out.println("Listernint on " + port);
            while (true) {
                server.listen();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
Client
View Code
package nio.file;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 文件下载客户端
 * 
 * 
@author tenyears.cn
 
*/
public class NIOClient {
    static int SIZE = 3;
    static InetSocketAddress ip = new InetSocketAddress("localhost", 12345);
    static CharsetEncoder encoder = Charset.forName("GB2312").newEncoder();

    static class Download implements Runnable {
        protected int index;
        private String filePath = "D:/Downloads";
        private File file;

        public Download(int index) {
            this.index = index;
            file = new File(filePath + "/" + index + ".test");
        }

        public void run() {
            try {
                long start = System.currentTimeMillis();
                SocketChannel client = SocketChannel.open();
                client.configureBlocking(false);
                Selector selector = Selector.open();
                client.register(selector, SelectionKey.OP_CONNECT);
                client.connect(ip);
                ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
                // file channel
                FileChannel fileChannel = new FileOutputStream(file)
                        .getChannel();
                int total = 0;
                FOR: for (;;) {
                    selector.select();
                    Iterator<SelectionKey> iter = selector.selectedKeys()
                            .iterator();
                    while (iter.hasNext()) {
                        SelectionKey key = iter.next();
                        iter.remove();
                        if (key.isConnectable()) {
                            SocketChannel channel = (SocketChannel) key
                                    .channel();
                            if (channel.isConnectionPending())
                                channel.finishConnect();
                            channel.write(encoder.encode(CharBuffer
                                    .wrap("Hello from " + index)));
                            channel.register(selector, SelectionKey.OP_READ);
                        } else if (key.isReadable()) {
                            SocketChannel channel = (SocketChannel) key
                                    .channel();
                            int count = channel.read(buffer);
                            if (count > 0) {
                                buffer.flip();
                                fileChannel.write(buffer);
                                total += count;
                                buffer.clear();
                            } else {
                                client.close();
                                break FOR;
                            }
                        }
                    }
                }
                double last = (System.currentTimeMillis() - start) * 1.0 / 1000;
                System.out.println("Thread " + index + " downloaded " + total
                        + "bytes in " + last + "s.");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        ExecutorService exec = Executors.newFixedThreadPool(SIZE);
        for (int index = 0; index < SIZE; index++) {
            exec.execute(new Download(index));
        }
        exec.shutdown();
    }
}
posted @ 2012-07-15 18:14  wasp  阅读(333)  评论(0编辑  收藏  举报