ServerSocket和ServerSocketChannel实例

来源:互联网 发布:淘宝类目在哪里修改 编辑:程序博客网 时间:2024/06/01 18:12

1.传统Socket

传统Socket单线程只能处理一个连接,要处理多个连接需要借助线程或者线程池,但是这样比较消耗资源。

public class ServerSocketDemo {    public static void main(String[] args) throws IOException {        new ServerSocketDemo().start(8080);    }    private  void start(int port) throws IOException {        ServerSocket serverSocket = new ServerSocket(port,2000);        System.out.println("server is start!");        //线程池可以处理多个连接比较消耗性能        ExecutorService executorService= Executors.newCachedThreadPool();        try {            while (true) {                //accept 会阻塞                Socket socket = serverSocket.accept();                System.out.println("有客户端连接来了"+socket.toString());                executorService.execute(new SocketHandler(socket));            }        } catch (Exception ex) {            System.out.println(ex.getMessage());        } finally {            serverSocket.close();        }    }}
public class SocketHandler implements Runnable {    private Socket socket;    public SocketHandler(Socket socket) {        this.socket = socket;    }    public void run() {        InputStream in = null;        OutputStream out = null;        try {            in = socket.getInputStream();            out = socket.getOutputStream();            byte[] bytes = new byte[1024];            while (true) {                //会阻塞                int n = in.read(bytes);                if (n == -1) {                    break;                }                System.out.println(new String(bytes, 0, n));                out.write(bytes,0,n);            }        } catch (Exception ex) {            System.out.println(ex.getMessage());        } finally {            try {                System.out.print("关闭 socket");                socket.close();            } catch (Exception ex) {                System.out.println(ex.getMessage());            }            try {                if(in!=null) {                    in.close();                }            } catch (Exception ex) {                System.out.println(ex.getMessage());            }            try {                if(out!=null) {                    out.close();                }            } catch (Exception ex) {                System.out.println(ex.getMessage());            }        }    }}

2.NIO

java nio 借鉴了Linux下select、poll、epoll模型;其性能有很大的提高。

public class ServerSocketChannelDemo {    private Selector selector;    public void initServer(int port) throws IOException {        //创建ServerSocketChannel        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();        serverSocketChannel.configureBlocking(false);        serverSocketChannel.socket().bind(new InetSocketAddress(port));        this.selector = Selector.open();        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);    }    public void listen() throws IOException {        System.out.println("server is start!");        while (true) {            //这条语句会阻塞            selector.select();            Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();            while (iterator.hasNext()) {                SelectionKey key = iterator.next();                iterator.remove();                handler(key);            }        }    }    public void handler(SelectionKey key) throws IOException {        if (key.isAcceptable()) {            handlerAccept(key);        } else if (key.isReadable()) {            handlerReader(key);        }    }    public void handlerAccept(SelectionKey key) throws IOException {        ServerSocketChannel sever = (ServerSocketChannel) key.channel();        SocketChannel channel = sever.accept();        channel.configureBlocking(false);        System.out.println("有客服端连接来了" + channel.toString());        channel.register(this.selector, SelectionKey.OP_READ);    }    public void handlerReader(SelectionKey key) throws IOException {        SocketChannel socketChannel = (SocketChannel) key.channel();        ByteBuffer buffer = ByteBuffer.allocate(1024);        //不会阻塞        int n = socketChannel.read(buffer);        System.out.println(n);        if (n > 0) {            byte[] data = buffer.array();            System.out.println("服务端收到信息:" + new String(data, 0, n));            buffer.flip();            socketChannel.write(buffer);        } else {            System.out.println("clinet is close");            key.cancel();        }    }    public static void main(String[] args) throws IOException {        ServerSocketChannelDemo sever = new ServerSocketChannelDemo();        sever.initServer(8081);        sever.listen();    }}

NIO 的基本知识可以参考:
IO 模型
缓冲区
通道
值得说明是:
selector.select()是阻塞的,selector.select(1000)是非阻塞的(1000 表示等待时间)、selector.selectNow()也是非阻塞的、selector.wakeup()可以唤醒selector
SelectionKey.OP_WRITE一般很少使用OP_WRITE表示底层缓冲区是否有空间,是则响应返还true。

0 0
原创粉丝点击