您的位置:首页 > 编程语言 > Java开发

java的nio实现

2016-06-17 20:30 441 查看
前言:最近在研究java netty这个网络框架,第一篇先介绍java的nio。 

java nio在jdk1.4引入,其实也算比较早的了,主要引入非阻塞io和io多路复用。内部基于reactor模式。

nio核心: 

- buffer 

- channel 

- selector

buffer: 

类似网络编程中的缓冲区,有 

ByteBuffer 字节 

CharBuffer 字符 

IntBuffer 

DoubleBuffer… 

常用的有ByteBuffer和CharBuffer

java nio buffer是开辟了一块空间,内部有4个标记,分别为position,limit,capicity,mask。 


 

position是当前读缓冲区位置,limit是数据的结尾,表示最多能读到limit位置,capacity是缓冲区的容量,在position和limit之间还会有mask用来标记一个位置,可以移动position到达mask位置 

buffer有两个重要的方法clear和flip 

clear()方法没有清空数据而是将position置为0,limit置为capacity, 

为再次向buffer装数据做好准备 

flip()方法在装载完数据后,将limit设为当前position位置,然后将position设置为0,简单来说就是flip()为从buffer中取出数据做好准备。

>

channel: 

类似网络编程中的套接字,Java nio中称为Channel(通道),个人认为这样更加方便我们理解,服务器和客户端之间通过Channel来传输数据。

channel 有 

FileChannel 文件管道 

DatagramChannel 数据报管道 

SocketChannel socket管道 

ServerSocketChannel 服务端socket管道 

channel可以直接文件的部分或全部映射为buffer 

注意: 

程序不能直接访问channel的数据,channel必须和buffer结合起来使用。 

所有的channel都不应该用构造器,从传统的流节点Inputstream 等来获取channel

selector: 

事件分发收集器,内部封装的epoll。我们可以往上面注册事件,然后监听多个channel通道上的事件等。

时序图 


 

注:图片非原创

从时序图可以看出java nio和我们平时写的网络编程很像。


java nio实现简单的回射服务器

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.channels.spi.SelectorProvider;
import java.nio.charset.Charset;
import java.util.Set;

/**
* Created by wwh on 15-7-25.
*/
public class NioSocket {
//字符序列和字节序列的编码和解码
private Charset charset = Charset.forName("UTF-8");

void run(String ip, int port) throws IOException {
try {
//创建服务端套接字
ServerSocketChannel server = ServerSocketChannel.open();
//绑定ip和端口
server.socket().bind(new InetSocketAddress(ip, port));
//设置非阻塞
server.configureBlocking(false);
//创建selector事件选择器
Selector selector = Selector.open();
//将自己的监听套接字注册到selector上,监听 accept事件
//SelectionKey代表SelectableChannel和Selector的关系,Selectable是Selector可监听的事件channel.
server.register(selector, SelectionKey.OP_ACCEPT);
while(selector.select() > 0){
//selector.select()返回事件
for(SelectionKey sk : selector.selectedKeys()) {
//从事件集合中删除正要处理的事件
selector.selectedKeys().remove(sk);
//判断事件的类型,依次处理
if(sk.isAcceptable()){
//如果事件为接受连接accpet事件
System.out.println("accpet 事件");
//调用accept接受请求连接
SocketChannel client = server.accept();
//设置为非阻塞
client.configureBlocking(false);
//向selector上注册读事件
client.register(selector, SelectionKey.OP_READ);
//将sk对应的channel设置为准备接受其他请求
sk.interestOps(SelectionKey.OP_ACCEPT);
}
if(sk.isReadable()){
//如果事件为可读事件
System.out.println("read 事件");
SocketChannel client = (SocketChannel)sk.channel();
//定义缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
String mesg = "";
try {
while (client.read(buffer) > 0) {
buffer.flip();
mesg += charset.decode(buffer);
}
System.out.println("收到:" + mesg);
sk.interestOps(SelectionKey.OP_READ);
}catch (IOException e){
//如果出现异常,则取消当前的client连接
sk.cancel();
if(sk.channel() != null){
sk.channel().close();
}
}
//回复给发来消息的client
client.write(charset.encode(mesg));
System.out.println("回复:" + mesg);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}

public static void main(String[] args) throws IOException {
NioSocket Server = new NioSocket();
Server.run("192.168.10.75", 10000);
}
}


转自:http://blog.csdn.net/wwh578867817/article/details/47071417
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: