Nio Client

public class NIOClient {
    static int SIZE = 2;
    final static int bufferSize = 500 * 1024;
    static InetSocketAddress ip = new InetSocketAddress("localhost", 12345);
    static CharsetEncoder encoder = Charset.forName("GB2312").newEncoder();

    static class Download implements Runnable {
        protected int index;
        String outfile = null;

        public Download(int index) {
            this.index = index;
            this.outfile = "c:\\" + index + ".rmvb";
        }

        public void run() {
            FileOutputStream fout = null;
            // FileChannel fcout = null;
            try {
                fout = new FileOutputStream(outfile);
                // fcout = fout.getChannel();
            } catch (FileNotFoundException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }

            try {
                long start = System.currentTimeMillis();

                // 打开客户端socket管道
                SocketChannel client = SocketChannel.open();

                // 客户端的管道的通讯模式
                client.configureBlocking(false);

                // 选择器
                Selector selector = Selector.open();

                // 往客户端管道上注册感兴趣的连接事件
                client.register(selector, SelectionKey.OP_CONNECT);

                // 配置IP
                client.connect(ip);

                // 配置缓存大小
                ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
                int total = 0;
                FOR: for (;;) {

                    // 阻塞,返回发生感兴趣事件的数量
                    selector.select();

                    // 相当于获得感兴趣事件的集合迭代
                    Iterator<SelectionKey> iter = selector.selectedKeys()
                            .iterator();

                    while (iter.hasNext()) {

                        SelectionKey key = iter.next();

                        System.out.println("-----Thread " + index
                                + "------------------" + key.readyOps());

                        // 删除这个马上就要被处理的事件
                        iter.remove();

                        // 感兴趣的是可连接的事件
                        if (key.isConnectable()) {

                            // 获得该事件中的管道对象
                            SocketChannel channel = (SocketChannel) key.channel();

                            // 如果该管道对象已经连接好了
                            if (channel.isConnectionPending())
                                channel.finishConnect();
                            // channel.write(encoder.encode(CharBuffer
                            // .wrap("d://film//" + index + ".mp3")));

                            // 往管道中写一些块信息
                            channel.write(encoder.encode(CharBuffer
                                    .wrap("d://film//1-hadoop-1.1.2.tar.gz")));

                            // 之后为该客户端管道注册新的感兴趣的事件---读操作
                            channel.register(selector, SelectionKey.OP_READ);
                        } else if (key.isReadable()) {

                            // 由事件获得通讯管道
                            SocketChannel channel = (SocketChannel) key
                                    .channel();

                            // 从管道中读取数据放到缓存中
                            int count = channel.read(buffer);
                            System.out.println("count:" + count);
                            if (count > 0) {

                                // 统计读取的字节数目
                                total += count;

                                // 这样一来从posistion~limit这段缓存数据是有效,可利用的
                                // buffer.flip();

                                buffer.clear();

                                // 往输出文件中去写了
                                if (count < bufferSize) {

                                    byte[] overByte = new byte[count];

                                    for (int index = 0; index < count; index++) {
                                        overByte[index] = buffer.get(index);
                                    }

                                    fout.write(overByte);
                                    // System.out.println(":::"
                                    // + new String(buffer.array()));
                                } else {
                                    fout.write(buffer.array());
                                    // System.out.println(":::"
                                    // + new String(buffer.array()));
                                }
                            } else {
                                // 关闭客户端通道
                                client.close();
                                // 退出大循环
                                break FOR;
                            }
                            //// buffer.clear();
                        }
                    }
                }

                // 计算时间
                double last = (System.currentTimeMillis() - start) * 1.0 / 1000;
                System.out.println("Thread " + index + " downloaded " + total
                        / 1024 + "kbytes in " + last + "s.");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

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

        long startTime = System.currentTimeMillis();

        // 启用线程池
        ExecutorService exec = Executors.newFixedThreadPool(SIZE);
        for (int index = 1; index <= SIZE; index++) {
            exec.execute(new Download(index));
        }
        exec.shutdown();

        long endTime = System.currentTimeMillis();

        long timeLong = endTime - startTime;

        System.out.println("下载时间:" + timeLong);

    }

 

转载于:https://www.cnblogs.com/fuxinci/p/3201891.html

<think>我们根据用户需求,需要提供Java NIO的教程或网络编程详解。结合引用内容,我们可以从以下几个方面进行讲解: 1. Java NIO的核心概念(通道、缓冲区、选择器) 2. NIO与BIO(传统IO)的区别 3. NIO网络编程实例(包括客户端和服务端) 注意:用户要求回答结构清晰,逐步解决问题,并保证真实可靠。同时,按照指令要求,数学公式使用$...$或$$...$$格式,但我们这里主要是代码和概念,所以重点在代码展示和文字描述。 由于引用中提供了部分内容,我们将整合这些内容并扩展。 步骤: 1. 介绍Java NIO 2. 核心概念:通道、缓冲区、选择器 3. 代码示例:客户端和服务端 注意:引用中已经有一个客户端代码(引用[3]),我们可以补充一个服务端代码,并解释。 另外,根据系统指令,我们需要在最后生成相关问题。 开始回答:</think>### Java NIO 网络编程详解 Java NIO(New I/O)是 Java 1.4 引入的非阻塞 I/O API,通过通道(Channel)、缓冲区(Buffer)和选择器(Selector)实现高性能网络通信。与传统 BIO(Blocking I/O)相比,NIO 能单线程处理数千并发连接[^1]。 #### 一、核心组件 1. **通道 (Channel)** 双向数据传输管道,支持异步读写操作。常用实现类: - `SocketChannel`:TCP 客户端通道 - `ServerSocketChannel`:TCP 服务端通道 - `FileChannel`:文件操作通道 2. **缓冲区 (Buffer)** 数据存储容器,核心属性: - `capacity`:最大容量(只读) - `position`:当前读写位置 - `limit`:可操作数据边界 ```java // 创建缓冲区示例 ByteBuffer buffer = ByteBuffer.allocate(1024); // 分配堆内存 ``` 3. **选择器 (Selector)** 多路复用器,监控通道的 I/O 事件(如连接就绪、数据到达): ```java Selector selector = Selector.open(); channel.configureBlocking(false); channel.register(selector, SelectionKey.OP_READ); // 注册读事件 ``` #### 二、NIO 与 BIO 关键差异 | **特性** | **BIO** | **NIO** | |----------------|-----------------------|-----------------------| | 阻塞模式 | 同步阻塞 | 同步非阻塞 | | 线程模型 | 1 连接 = 1 线程 | 单线程处理多连接 | | 数据传输单位 | 流(Stream) | 块(Buffer) | | 核心优势 | 编程简单 | 高并发、低资源消耗 | #### 三、网络编程实战 1. **NIO 客户端示例**(基于引用[3]优化): ```java public class NIOClient { public static void main(String[] args) throws IOException { SocketChannel socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); // 非阻塞模式 socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080)); while (!socketChannel.finishConnect()) { // 连接建立中,可执行其他任务 } ByteBuffer buffer = ByteBuffer.wrap("Hello Server".getBytes()); socketChannel.write(buffer); // 异步发送数据 socketChannel.close(); } } ``` 2. **NIO 服务端示例**: ```java public class NIOServer { public static void main(String[] args) throws IOException { ServerSocketChannel serverChannel = ServerSocketChannel.open(); serverChannel.bind(new InetSocketAddress(8080)); serverChannel.configureBlocking(false); // 非阻塞模式 Selector selector = Selector.open(); serverChannel.register(selector, SelectionKey.OP_ACCEPT); // 监听连接事件 while (true) { selector.select(); // 阻塞直到有就绪事件 Set<SelectionKey> keys = selector.selectedKeys(); Iterator<SelectionKey> iter = keys.iterator(); while (iter.hasNext()) { SelectionKey key = iter.next(); if (key.isAcceptable()) { // 处理新连接 SocketChannel client = serverChannel.accept(); client.configureBlocking(false); client.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // 处理数据读取 SocketChannel client = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(128); client.read(buffer); System.out.println("Received: " + new String(buffer.array())); } iter.remove(); // 移除已处理事件 } } } } ``` #### 四、性能优化建议 1. **使用直接缓冲区**:通过 `ByteBuffer.allocateDirect()` 分配堆外内存,减少 JVM 堆与操作系统间的数据拷贝[^2]。 2. **批量处理事件**:单次 `selector.select()` 调用处理多个就绪通道,降低系统调用开销。 3. **避免频繁注册**:对频繁读写的通道保持持久注册状态。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值