Nio--Selector实现简易的http服务器

来源:互联网 发布:php cookie自动登录 编辑:程序博客网 时间:2024/05/21 17:39

标题貌似很牛,但这里只是我的对Nio--Selector的测试demo,没有什么特别。再深化开发一下,实现一个http服务器也不是难事。

 

package com.vdebug.nio.selector;import java.io.IOException;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.nio.ByteBuffer;import java.nio.CharBuffer;import java.nio.channels.*;import java.nio.charset.Charset;import java.nio.charset.CharsetDecoder;import java.util.Iterator;import java.util.Set;/** * Created by pc on 2014/12/30. * http://ifeve.com/buffers/#clearandcompact */public class Server {    static int PORT = 8080;    static int BUFFER_SIZE = 1024;    static String CHARSET = "utf-8"; //默认编码    CharsetDecoder decoder; //解码    private final int port;    private ServerSocketChannel channel;    private Selector selector;    private final ByteBuffer buffer;    public Server(int port) throws IOException {        this.port = port;        this.buffer = ByteBuffer.allocate(BUFFER_SIZE);        this.decoder = Charset.forName(CHARSET).newDecoder();        this.selector = Selector.open();//打开选择器    }    /**     * 单线程服务,通过单一个线程同时为多路复用IO流服务     * 1、此方式适合:IO密集型的操作:如代理服务.     * 2、相信大家写过:使用socket的聊天程序:     * 即accept()一个socket后,new一个Thread为该socket服务,     * 此方式适合:CPU密集型的操作,如需要处理大量业务、计算     *     * @throws IOException     */    public void listen() throws IOException {        //打开一个服务通道        this.channel = ServerSocketChannel.open();        //绑定服务端口        ServerSocket socket = channel.socket();        socket.bind(new InetSocketAddress(port));        //使用非阻塞模式,使用多道io操作        channel.configureBlocking(false);        System.out.println("服务运行中...");        while (true) {            //非阻塞,没有连接,立即返回null,与socket.accept()方法(阻塞)不同,            SocketChannel client = channel.accept();            if (client != null) {                System.out.println("客户端口-->" + client.getRemoteAddress());                registerClient(client);            }            service();        }    }    /**     * 将客户端channel注册到selector上     * 四个事件:Connect、Accept、Read、Write     *     * @param client     * @throws IOException     */    private void registerClient(SocketChannel client) throws IOException {        //设置非阻塞        client.configureBlocking(false);        //将客户端channel注册到selector上        client.register(selector, SelectionKey.OP_READ);    }    /**     * 遍历各客户端通道     * select()阻塞到至少有一个通道在你注册的事件上就绪了     * select(long timeout) 多设置一个阻塞时间(毫秒)     * selectNow() 不阻塞,有无都返回。     */    private void service() throws IOException {        if (selector.selectNow() > 0) {            //客户端channel的键集合            Set<SelectionKey> keys = selector.selectedKeys();            System.out.println("selector长度-->" + keys.size());            Iterator<SelectionKey> it = keys.iterator();            while (it.hasNext()) {                SelectionKey key = it.next();                SocketChannel client = (SocketChannel) key.channel();                if (key.isReadable()) {                    read(key);                } else if (key.isWritable()) {                    write(key);                }            }        }    }    //读信息    private void read(SelectionKey key) throws IOException {        SocketChannel client = (SocketChannel) key.channel();        buffer.clear();        int c = client.read(buffer);        if (c > 0) {            //flip方法将Buffer从写模式切换到读模式            buffer.flip();            CharBuffer charBuffer = decoder.decode(buffer);            //接收请求            System.out.println(charBuffer.toString());            key.attach("ack syn...");            // 改变自身关注事件,可以用位或操作|组合时间            key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);        } else {            client.close();        }        buffer.clear();    }    //响应信息    private void write(SelectionKey key) throws IOException {        SocketChannel client = (SocketChannel) key.channel();        String handle = (String) key.attachment();//取出read方法传递的信息。        String res = Response.getMsg();        if (handle != null) {            res = res + "\r\n" + handle;        }        ByteBuffer block = ByteBuffer.wrap(res.getBytes());        client.write(block);        client.close();        // 改变自身关注事件,可以用位或操作|组合时间        //key.interestOps(SelectionKey.OP_READ);    }    public static void main(String[] args) {        try {            System.out.println("正在启动服务...");            Server server = new Server(PORT);            server.listen();        } catch (IOException e) {            e.printStackTrace();        }    }}class Response {    public static String getMsg() {        return "HTTP/1.1 200 OK" + "\r\n";    }}


 

 

 

 

 

 

 

0 0
原创粉丝点击