NIO示例2

package com.mzj.nio.java;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Copyright (C),HTF<br>
 * NIO客户端<br>
 * NIO:1.缓冲区、2.选择器、3.通道、4.SelectionKey(事件类型)<br>
 * 类似于AWT事件机制
 *
 * @author muzhongjiang
 * @date 2014年8月20日
 */
public class NIOClient {

    private final Logger LOG = LoggerFactory.getLogger(this.getClass());

    private final int BLOCK = 4096;// 缓冲区大小
    private ByteBuffer sendBuf = ByteBuffer.allocate(BLOCK);// 数据接收缓冲区
    private ByteBuffer receiveBuf = ByteBuffer.allocate(BLOCK);// 数据发送缓冲区
    private Selector selector;// 通道选择器
    private final InetSocketAddress SERVER_ADDRESS;

    /**
     * 构造方法
     *
     * @throws IOException
     */
    public NIOClient(String hostName, int port) throws IOException {
        SERVER_ADDRESS = new InetSocketAddress(hostName, port);
        this.start();
    }

    public void start() throws IOException {
        // 1.打开client端socket通道:
        SocketChannel socketChannel = SocketChannel.open();

        // 2.通道设置为非阻塞式:
        socketChannel.configureBlocking(false);

        // 4.获得通道选择器:
        selector = Selector.open();

        // 5.注册连接服务端的key:
        socketChannel.register(selector, SelectionKey.OP_CONNECT);

        // 6.连接服务端:
        socketChannel.connect(SERVER_ADDRESS);

        LOG.info("开启客户端...");
        // 7.打开监听
        this.listener();

    }

    /**
     * 监听器
     *
     * @throws IOException
     */
    private void listener() throws IOException {
        while (true) {

            // 1.‘选择器‘获得一组‘已被client选择的key‘:
            int size = selector.select();
            LOG.info("客户端 size:【" + size + "】");

            // 2.‘key‘处理器(事件处理器)
            this.keyProcessor(selector.selectedKeys());

        }
    }

    /**
     * key处理器(事件处理器)<br>
     * 对不同的key(事件)进行不同的处理
     *
     * @throws IOException
     */
    private void keyProcessor(Set<SelectionKey> selectedKeys) throws IOException {

        SocketChannel client = null;

        Iterator<SelectionKey> iterator = selectedKeys.iterator();
        while (iterator.hasNext()) {
            SelectionKey selectionKey = iterator.next();
            iterator.remove();

            if (selectionKey.isConnectable()) {
                this.handConnect(selectionKey, client);

            } else if (selectionKey.isReadable()) {
                this.handRead(selectionKey, client);

            } else if (selectionKey.isWritable()) {
                this.handWrit(selectionKey, client);
            }
        }
    }

    private void handConnect(SelectionKey selectionKey, SocketChannel client) throws IOException {

        client = (SocketChannel) selectionKey.channel();

        if (client.isConnectionPending()) {// 判断此通道上是否正在进行连接操作。
            if (client.finishConnect()) {// 完成套接字通道的连接过程
                LOG.info("客户端完成连接");
                sendBuf.clear(); // 缓冲区清空:
                sendBuf.put("hello world server".getBytes());
                sendBuf.flip();
                client.write(sendBuf);
            }
            // client请求读server:
            client.register(selector, SelectionKey.OP_READ);
        }
    }

    private void handRead(SelectionKey selectionKey, SocketChannel client) throws IOException {

        client = (SocketChannel) selectionKey.channel();
        receiveBuf.clear();// 1.缓冲区清空:
        int count = client.read(receiveBuf);// 2.读取服务器发送来的数据到缓冲区中

        // 3.数据处理:
        if (count > 0) {
            String receiveText = new String(receiveBuf.array(), 0, count);
            // 可以保存到数据库.....
            LOG.info("客户端接收服务端数据:receiveText:【" + receiveText + "】");

            // client注册写:
            client.register(selector, SelectionKey.OP_WRITE);
        }

    }

    private void handWrit(SelectionKey selectionKey, SocketChannel client) throws IOException {
        client = (SocketChannel) selectionKey.channel();
        // 1.将缓冲区清空
        sendBuf.clear();

        // 2.向缓冲区中输入数据
        String sendText = String.valueOf(new Date().getTime());
        sendBuf.put(sendText.getBytes());

        // 3.将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
        sendBuf.flip();

        // 4.输出到通道
        client.write(sendBuf);
        LOG.info("客户端向服务器端发送数据--:" + sendText);

        // 5.client请求读server:
        client.register(selector, SelectionKey.OP_READ);
    }

    public static void main(String[] args) throws IOException {
        new NIOClient("127.0.0.1", 9999);
    }
}
package com.mzj.nio.java;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Copyright (C),HTF<br>
 * NIO服务端<br>
 * NIO:1.缓冲区、2.选择器、3.通道、4.SelectionKey(事件类型)<br>
 * 类似于AWT事件机制
 *
 * @author muzhongjiang
 * @date 2014年8月20日
 */
public class NIOServer {

    private final Logger LOG = LoggerFactory.getLogger(this.getClass());

    private final int BLOCK = 4096;// 缓冲区大小
    private ByteBuffer sendBuf = ByteBuffer.allocate(BLOCK);// 数据接收缓冲区
    private ByteBuffer receiveBuf = ByteBuffer.allocate(BLOCK);// 数据发送缓冲区
    private Selector selector;// 通道选择器

    /**
     * 构造方法:
     */
    public NIOServer(int port) throws IOException {
        // 1.打开server端socket通道:
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 2.通道设置为非阻塞式:
        serverSocketChannel.configureBlocking(false);

        // 3.获得Socket,并绑定服务‘地址‘:
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(port));

        // 4.获得通道选择器:
        selector = Selector.open();

        /*
         * 5.在‘选择器‘上注册‘通道‘的‘事件(类型)‘<br> 一般ServerSocketChannel只注册accept事件,对于read和write事件是注册到accept的SocketChannel中的
         */
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        LOG.info("开启服务端...");
        // 6.打开监听
        this.listener();

    }

    /**
     * 监听器
     *
     * @throws IOException
     */
    private void listener() throws IOException {

        while (true) {
            // 1.‘选择器‘获得一组‘已被client选择的key‘:
            int size = selector.select();
            LOG.info("服务端 size:【" + size + "】");
            // 2.‘key‘处理器(事件处理器)
            this.keyProcessor(selector.selectedKeys());

        }

    }

    /**
     * key处理器(事件处理器)<br>
     * 对不同的key(事件)进行不同的处理
     *
     * @throws IOException
     */
    private void keyProcessor(Set<SelectionKey> selectedKeys) throws IOException {

        SocketChannel client = null;

        Iterator<SelectionKey> iterator = selectedKeys.iterator();
        while (iterator.hasNext()) {
            SelectionKey selectionKey = iterator.next();
            iterator.remove();

            if (selectionKey.isAcceptable()) {
                this.handAccept(selectionKey, client);

            } else if (selectionKey.isReadable()) {
                this.handRead(selectionKey, client);

            } else if (selectionKey.isWritable()) {
                this.handWrit(selectionKey, client);
            }
        }
    }

    private void handAccept(SelectionKey selectionKey, SocketChannel client) throws IOException {
        LOG.info("服务端 handAccept");
        ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel();

        // 1.获得client套接字通道:
        client = server.accept();

        // 2.配置为非阻塞:
        client.configureBlocking(false);

        // 3.给客户端注册read的Key:
        client.register(selector, SelectionKey.OP_READ);
    }

    private void handRead(SelectionKey selectionKey, SocketChannel client) throws IOException {

        client = (SocketChannel) selectionKey.channel();

        // 1.将缓冲区清空
        receiveBuf.clear();
        // 2.读取发送来的数据到缓冲区中
        int count = client.read(receiveBuf);
        if (count > 0) {
            String receiveText = new String(receiveBuf.array(), 0, count);
            LOG.info("服务器端接受客户端数据:" + receiveText);
            // 3.client注册write key :
            client.register(selector, SelectionKey.OP_WRITE);
        }

    }

    private void handWrit(SelectionKey selectionKey, SocketChannel client) throws IOException {

        client = (SocketChannel) selectionKey.channel();
        // 1.将缓冲区清空
        sendBuf.clear();

        // 2.向缓冲区中输入数据
        String sendText = String.valueOf(new Date().getTime());
        sendBuf.put(sendText.getBytes());

        // 3.将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
        sendBuf.flip();

        // 4.输出到通道
        client.write(sendBuf);
        LOG.info("向客户端发送数据:" + sendText);

        // 5.client注册read key :
        client.register(selector, SelectionKey.OP_READ);
    }

    public static void main(String[] args) throws IOException {
        new NIOServer(9999);
    }
}
时间: 2025-01-03 19:09:02

NIO示例2的相关文章

NIO示例1

package com.mzj.nio.java; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.It

Java NIO示例:多人网络聊天室

一个多客户端聊天室,支持多客户端聊天,有如下功能: 功能1: 客户端通过Java NIO连接到服务端,支持多客户端的连接 功能2:客户端初次连接时,服务端提示输入昵称,如果昵称已经有人使用,提示重新输入,如果昵称唯一,则登录成功,之后发送消息都需要按照规定格式带着昵称发送消息 功能3:客户端登录后,发送已经设置好的欢迎信息和在线人数给客户端,并且通知其他客户端该客户端上线 功能4:服务器收到已登录客户端输入内容,转发至其他登录客户端. 功能5 TODO:客户端下线检测  方案是:客户端在线的时候

Java Socket NIO示例总结

Java NIO是非阻塞IO的实现,基于事件驱动,非常适用于服务器需要维持大量连接,但是数据交换量不大的情况,例如一些即时通信的服务等等,它主要有三个部分组成: Channels Buffers Selectors Channel有两种ServerSocketChannel 和 SocketChannel,ServerSocketChannel可以监听新加入的Socket连接,SocketChannel用于读和写操作.NIO总是把缓冲区的数据写入通道,或者把通道里的数据读出到缓冲区. Buffe

Java NIO的探究

1.Java NIO与阻塞IO的区别 阻塞IO通信模型(在上一篇<J2SE网络编程之 TCP与UDP>博客中有所介绍) 我们知道阻塞I/O在调用InputStream.read()方法时是阻塞的,它会一直等到数据到来时(或超时)才会返回:同样,在调用ServerSocket.accept()方法时,也会一直阻塞到有客户端连接才会返回,每个客户端连接过来后,服务端都会启动一个线程去处理该客户端的请求.阻塞I/O的通信模型示意图如下: 如果你细细分析,一定会发现阻塞I/O存在一些缺点.根据阻塞I/

java IO总结(BIO、NIO、AIO)

1.BIO编程 1.1.传统的BIO编程 网络编程的基本模型是C/S模型,即两个进程间的通信. 服务端提供IP和监听端口,客户端通过连接操作想服务端监听的地址发起连接请求,通过三次握手连接,如果连接成功建立,双方就可以通过套接字进行通信. 传统的同步阻塞模型开发中,ServerSocket负责绑定IP地址,启动监听端口:Socket负责发起连接操作.连接成功后,双方通过输入和输出流进行同步阻塞式通信. 简单的描述一下BIO的服务端通信模型: 采用BIO通信模型的服务端,通常由一个独立的Accep

Tomcat架构解析(六)-----BIO、NIO、NIO2、APR

对于应用服务器来说,性能是非常重要的,基本可以说决定着这款应用服务器的未来.通常从软件角度来说,应用服务器性能包括如下几个方面: 1.请求处理的并发程度,当前主流服务器均采用异步的方式处理客户端的请求: 2.减少网络传输的数据量,提高网络利用率: 3.降低新建网络链接的开销,以实现链接在多个请求之间的复用: 4.选择合适的I/O方式,例如NIO等. 一.阻塞与非阻塞.同步与异步 ------同步:发出一个调用时,没有得到结果之前,该调用不返回,由调用者主动等待调用结果. | 关注的是消息通信机制

快速了解NIO

NIO的由来 我们都知道,在jdk1.4的时候就开始引入NIO了,它是基于Selector机制的非阻塞I/O,可以将多个异步的I/O操作集中到一个或几个线程中进行处理,目的就是为了代替阻塞I/O,提到系统的并发吞吐量,以提升性能. 什么场景下使用NIO 当客户端的数据传递不是连续的,而是断断续续的,这时如果使用传统的阻塞I/O,则程序需要等待,若此时还有多个线程,每个客户端的请求使用一个线程进行处理,那么操作系统还要进行上下文切换,性能上更是雪上加霜. 而此时使用NIO,则可以明显提升系统处理效

JAVA NIO工作原理及代码示例

简介:本文主要介绍了JAVA NIO中的Buffer, Channel, Selector的工作原理以及使用它们的若干注意事项,最后是利用它们实现服务器和客户端通信的代码实例. 欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 1. ByteBuffer 1.1直接缓冲区和非直接缓冲区 下面是创建ByteBuffer对象的几种方式 static ByteBuffer allocate(int capacity) static Byte

nio原理和示例代码

我正在为学习大数据打基础中,为了手撸rpc框架,需要懂得nio的原理,在搞懂nio框架前,我会带着大家手撸一些比较底层的代码,当然今后当我们学会了框架,这些繁琐的代码也就不用写了,但是学一学底层的代码也是有好处的嘛. java.nio全称java non-blocking IO(实际上是 new io),是指jdk1.4 及以上版本里提供的新api(New IO) ,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络. 前面我写的socket的