NIO核心详解——案例

UDP案例

UDPClient
package chapter03_Java_NIO;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;


/**
 * 从示例程序可以看出,在客户端使用DatagramChannel发送数据比在客户端使用SocketChannel发送数据要简单得多。
 */
public class java04_5_UDPClient {
    public void send() throws IOException {
        //获取DatagramChannel
        DatagramChannel dChannel = DatagramChannel.open();
        //设置为非阻塞
        dChannel.configureBlocking(false);
        ByteBuffer buffer =
                ByteBuffer.allocate(1024);
        Scanner scanner = new Scanner(System.in);
        System.out.println("UDP客户端启动成功!");
        System.out.println("请输入发送内容:");
        while (scanner.hasNext()) {
            String next = scanner.next();
            String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            buffer.put(( date+ " >>" + next).getBytes());
            buffer.flip();
            //通过DatagramChannel发送数据
            dChannel.send(buffer,new InetSocketAddress("127.0.0.1",18899));
            buffer.clear();
        }
        //关闭DatagramChannel
        dChannel.close();
    }
    public static void main(String[] args) throws IOException {
        new java04_5_UDPClient().send();
    }
}
UDPServer
package chapter03_Java_NIO;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;

/**
 * 服务端是通过DatagramChannel绑定一个服务器地址(IP+端口),接收客户端发送过来的UDP数据报。服务端的完整代码如下:
 *
 * @在服务端,首先调用了bind()方法绑定DatagramChannel的监听端口。
 * @当数据到来时调用了receive()方法,从DatagramChannel接收数据后写入ByteBuffer缓冲区中。
 * @在服务端代码中,为了监控数据的到来,使用了Selector。
 */
public class java04_6_UDPServer {
    public void receive() throws IOException {
        //获取DatagramChannel
        DatagramChannel datagramChannel = DatagramChannel.open();
        //设置为非阻塞模式
        datagramChannel.configureBlocking(false);
        //绑定监听地址
        datagramChannel.bind(new InetSocketAddress("127.0.0.1",18899));
        System.out.println("UDP服务器启动成功!");
        //开启一个通道选择器
        Selector selector = Selector.open();
        //将通道注册到选择器
        datagramChannel.register(selector, SelectionKey.OP_READ);
        //通过选择器查询IO事件
        while (selector.select() > 0) {
            Iterator<SelectionKey> iterator =
                    selector.selectedKeys().iterator();
            ByteBuffer buffer =
                    ByteBuffer.allocate(1024);

            //迭代IO事件
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                //可读事件,有数据到来
                if (selectionKey.isReadable()) {
                    //读取DatagramChannel数据
                    SocketAddress client = datagramChannel.receive(buffer);
                    buffer.flip();
                    System.out.println(new String(buffer.array(), 0, buffer.limit()));
                    buffer.clear();
                }
            }
            iterator.remove();
        }
        //关闭选择器和通道
        selector.close();
        datagramChannel.close();
    }
    public static void main(String[] args) throws IOException {
        new java04_6_UDPServer().receive();
    }
}

简单NIO案例

Server用main方法启动 Client 用@Test 注解启动

class NioDiscardServer {
    public static void startServer() throws IOException {
        //1.获取选择器
        Selector selector = Selector.open();
        //2.获取通道
        ServerSocketChannel serverSocketChannel =
                ServerSocketChannel.open();
        //3.设置为非阻塞
        serverSocketChannel.configureBlocking(false);
        //4.绑定连接
        serverSocketChannel.bind(new InetSocketAddress(18899));
        Logger.info("服务器启动成功");
        //5.将通道注册的“接收新连接”IO事件注册到选择器上
        serverSocketChannel.register(selector,
                SelectionKey.OP_ACCEPT);
        //6.轮询感兴趣的IO就绪事件(选择键集合)
        while (selector.select() > 0) {
            //7.获取选择键集合
            Iterator<SelectionKey> selectedKeys =
                    selector.selectedKeys().iterator();
            while (selectedKeys.hasNext()) {
                //8.获取单个的选择键,并处理
                SelectionKey selectedKey = selectedKeys.next();
                //9.判断key是具体的什么事件
                if (selectedKey.isAcceptable()) {

                    //10.若选择键的IO事件是“连接就绪”,就获取客户端连接
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    //11.将新连接切换为非阻塞模式
                    socketChannel.configureBlocking(false);
                    //12.将新连接的通道的可读事件注册到选择器上
                    socketChannel.register(selector, SelectionKey.OP_READ);

                } else if (selectedKey.isReadable()) {

                    //13.若选择键的IO事件是“可读”,则读取数据
                    SocketChannel socketChannel = (SocketChannel) selectedKey.channel();

                    //14.读取数据,然后丢弃
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    int length = 0;
                    while ((length = socketChannel.read(byteBuffer)) >0)
                    {
                        byteBuffer.flip();
                        Logger.info(new String(byteBuffer.array(), 0, length));
                        byteBuffer.clear();
                    }
                    socketChannel.close();
                }
                //15.移除选择键
                selectedKeys.remove();
            }
        }
        //16.关闭连接
        serverSocketChannel.close();
    }
    public static void main(String[] args) throws IOException {
        startServer();
    }

    /**
     * 客户端首先建立到服务器的连接,发送一些简单的数据,然后直接关闭连接。客户端的DiscardClient代码更加简单,代码如下:
     *
     * 通过Discard服务器的开发实战,大家应该对NIO Selector的使用流程了解得非常清楚了。下面来看一个稍微复杂一点的案例:在服务端接收文件和内容。
     */
    @Test
    public void startClient() throws IOException {
        InetSocketAddress address =new InetSocketAddress("127.0.0.1",18899);
        //1.获取通道
        SocketChannel socketChannel = SocketChannel.open(address);
        //2.切换成非阻塞模式
        socketChannel.configureBlocking(false);
        //不断地自旋、等待连接完成,或者做一些其他的事情
        while (!socketChannel.finishConnect()) {
        }
        Logger.info("客户端连接成功");
        //3.分配指定大小的缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        byteBuffer.put("hello world".getBytes());
        byteBuffer.flip();
        //发送到服务器
        socketChannel.write(byteBuffer);
        socketChannel.shutdownOutput();
        socketChannel.close();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值