java nio类_Java NIO类简介

1、Java NIO类

ServerSocketChannel:ServerSocket的替代类,支持阻塞与非阻塞通信

SocketChannel:Socket的替代类,支持阻塞与非阻塞通信

Selector:监听接收连接就绪事件、监听连续就绪、读就绪、写就绪事件

SelectionKey:Selector注册时间的句柄

1.1 ServerSocketChannel及SocketChannel都是SelectableChannel的子类

1.2 SelectableChannel类及其子类都能委托Selector来监控它们可能发生的一些事件

ServerSocketChannel向Selector注册接收连续就绪事件

SelectionKey key = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

ServerSocketChannel只可能发生一种事件:SelectionKey.OP_ACCEPT 接收连接就绪事件

SocketChannel可能发生3种事件

SelectionKey.OP_CONNECT: 连接就绪事件

SelectionKey.OP_READ: 读就绪事件

SelectionKey.OP_WRITE: 写就绪事件

2、缓冲区Buffer

缓冲区属性

容量:capacity 该缓冲区可以保存多少数据

极限:limit 缓冲区当前终点,不能对超出极限部分进行读写,极限可以修改,不能大于容量

位置:position 缓冲区下一个读写单元的位置

缓冲区属性的方法

clear() 把极限设为容量,把位置设为0

flip() 把极限设为位置,把位置设为0

rewind() 不改变极限,把位置设为0

ByteBuffer获得示例的方法

allocate(int capacity) 返回ByteBuffer对象,capacity指定缓冲区的容量

directAllocate(int capacity) 该方法返回的缓冲区称为直接缓冲区,速度快,但开销大

缓冲区的读写方法

get() 相对读,从缓冲区当前位置读取一个单元数据,把位置+1

get(int index) 绝对读,从参数index指定的位置读取一个单元的数据

put() 相对写,想缓冲区的当前位置写入一个单元的数据,写完后位置+1

put(int index) 绝对写,向参数index指定的位置写入一个单元的数据

3、字符编码Charset

CharBuffer decode(ByteBuffer bb) 字节序列转字符串 解码

ByteBuffer encode(String str) encode(CharBuffer cb) 字符串转字节序列 编码

4、通道Channel

用来连接缓冲区与数据源或数据汇

5、实现socket的3个方式

阻塞

public class EchoServer {

private int port = 8000;

private ServerSocketChannel serverSocketChannel;

private ExecutorService executorService;

private static final int POOL_MULTIPLE = 4;

public EchoServer() throws IOException {

executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*POOL_MULTIPLE);

serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.socket().setReuseAddress(true);

serverSocketChannel.socket().bind(new InetSocketAddress(port));

System.out.println("服务器启动");

}

public void service(){

while(true){

SocketChannel socketChannel = null;

try {

socketChannel = serverSocketChannel.accept();

executorService.execute(new Handler(socketChannel));

} catch (IOException e) {

e.printStackTrace();

}

}

}

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

new EchoServer().service();

}

}

class Handler implements Runnable{

private SocketChannel socketChannel;

public Handler(SocketChannel socketChannel) {

this.socketChannel = socketChannel;

}

@Override

public void run() {

Socket socket = socketChannel.socket();

System.out.println("接收到客户连接,来自:"+socket.getInetAddress()+":"+socket.getPort());

try {

BufferedReader br = getReader(socket);

PrintWriter pw = getWriter(socket);

String msg = null;

while((msg=br.readLine())!=null){

System.out.println(msg);

pw.println(echo(msg));

if(msg.equals("bye")){

break;

}

}

} catch (IOException e) {

e.printStackTrace();

} finally {

if(socketChannel!=null){

try {

socketChannel.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

private PrintWriter getWriter(Socket socket) throws IOException {

OutputStream socketOut = socket.getOutputStream();

return new PrintWriter(socketOut, true);

}

private BufferedReader getReader(Socket socket) throws IOException {

InputStream socketIn = socket.getInputStream();

return new BufferedReader(new InputStreamReader(socketIn));

}

public String echo(String msg){

return "echo:"+msg;

}

}

public class EchoClient {

private SocketChannel socketChannel = null;

public EchoClient() throws IOException {

socketChannel = SocketChannel.open();

InetAddress ia = InetAddress.getLocalHost();

InetSocketAddress isa = new InetSocketAddress(ia, 8000);

socketChannel.connect(isa);

System.out.println("与服务器连接成功");

}

private PrintWriter getWriter(Socket socket) throws IOException {

OutputStream socketOut = socket.getOutputStream();

return new PrintWriter(socketOut, true);

}

private BufferedReader getReader(Socket socket) throws IOException {

InputStream socketIn = socket.getInputStream();

return new BufferedReader(new InputStreamReader(socketIn));

}

public void talk(){

try {

BufferedReader br = getReader(socketChannel.socket());

PrintWriter pw = getWriter(socketChannel.socket());

BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));

String msg;

while((msg=localReader.readLine())!=null){

pw.println(msg);

System.out.println(br.readLine());

if(msg.equals("bye")){

break;

}

}

} catch (IOException e) {

e.printStackTrace();

} finally{

try {

socketChannel.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

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

new EchoClient().talk();

}

}

非阻塞

public class EchoServer {

private Selector selector;

private ServerSocketChannel serverSocketChannel;

private int port = 8000;

private Charset charset = Charset.forName("GBK");

public EchoServer() throws IOException {

selector = Selector.open();

serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.socket().setReuseAddress(true);

serverSocketChannel.configureBlocking(false);

serverSocketChannel.socket().bind(new InetSocketAddress(port));

System.out.println("服务器启动");

}

public void service() throws IOException {

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

while(selector.select()>0){

Set readyKeys = selector.selectedKeys();

Iterator it = readyKeys.iterator();

while(it.hasNext()){

SelectionKey key = null;

try {

key = (SelectionKey) it.next();

it.remove();

if(key.isAcceptable()){

ServerSocketChannel ssc = (ServerSocketChannel) key.channel();

SocketChannel socketChannel = ssc.accept();

System.out.println("接收到客户连接,来自:" +socketChannel.socket().getInetAddress()+

":"+socketChannel.socket().getPort());

socketChannel.configureBlocking(false);

ByteBuffer buffer = ByteBuffer.allocate(1024);

socketChannel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE, buffer);

}

if(key.isReadable()){

receive(key);

}

if(key.isWritable()){

send(key);

}

} catch (IOException e){

if(key!=null){

key.cancel();

key.channel().close();

}

}

}

}

}

public void receive(SelectionKey key) throws IOException {

ByteBuffer buffer = (ByteBuffer) key.attachment();

SocketChannel socketChannel = (SocketChannel) key.channel();

// 一次读取的数据,一次只读32个字节

ByteBuffer readBuff = ByteBuffer.allocate(32);

socketChannel.read(readBuff);

// 把极限设为位置,把位置设为0

readBuff.flip();

buffer.limit(buffer.capacity());

buffer.put(readBuff);

}

public void send(SelectionKey key) throws IOException {

ByteBuffer buffer = (ByteBuffer) key.attachment();

SocketChannel socketChannel = (SocketChannel) key.channel();

buffer.flip();

String data = decode(buffer);

if(data.indexOf("\r\n")==-1){

return;

}

String outputData = data.substring(0, data.indexOf("\n")+1);

System.out.println(outputData);

ByteBuffer outputBuffer = encode("echo:"+outputData);

while(outputBuffer.hasRemaining()){

socketChannel.write(outputBuffer);

}

ByteBuffer temp = encode(outputData);

buffer.position(temp.limit());

buffer.compact();

if(outputData.equals("bye\r\n")){

key.cancel();

socketChannel.close();

System.out.println("关闭与客户的连接");

}

}

public String decode(ByteBuffer buffer){

CharBuffer charBuffer = charset.decode(buffer);

return charBuffer.toString();

}

public ByteBuffer encode(String str){

return charset.encode(str);

}

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

new EchoServer().service();

}

}

public class EchoClient {

private SocketChannel socketChannel = null;

private ByteBuffer sendBuffer = ByteBuffer.allocate(1024);

private ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);

private Charset charset = Charset.forName("GBK");

private Selector selector;

public EchoClient() throws IOException {

socketChannel = SocketChannel.open();

InetAddress ia = InetAddress.getLocalHost();

InetSocketAddress isa = new InetSocketAddress(ia, 8000);

socketChannel.connect(isa);

socketChannel.configureBlocking(false);

System.out.println("与服务器的连接建立成功");

selector = Selector.open();

}

public void receive(SelectionKey key) throws IOException {

SocketChannel socketChannel = (SocketChannel) key.channel();

socketChannel.read(receiveBuffer);

receiveBuffer.flip();

String receiveData = decode(receiveBuffer);

if(receiveData.indexOf("\n")==-1){

return;

}

String outputData = receiveData.substring(0, receiveData.indexOf("\n")+1);

System.out.println(outputData);

if(outputData.equals("echo:bye\r\n")){

key.cancel();

socketChannel.close();

System.out.println("关闭与服务器的连接");

selector.close();

System.exit(0);

}

ByteBuffer temp = encode(outputData);

receiveBuffer.position(temp.limit());

receiveBuffer.compact();

}

public String decode(ByteBuffer buffer){

CharBuffer charBuffer = charset.decode(buffer);

return charBuffer.toString();

}

public void send(SelectionKey key) throws IOException {

SocketChannel socketChannel = (SocketChannel) key.channel();

synchronized (sendBuffer){

sendBuffer.flip();

socketChannel.write(sendBuffer);

sendBuffer.compact();// 删除已处理的数据

}

}

public void receiveFromUser(){

BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));

String msg = null;

try {

while((msg=localReader.readLine())!=null){

synchronized (sendBuffer){

sendBuffer.put(encode(msg+"\r\n"));

}

if(msg.equals("bye")){

break;

}

}

} catch (IOException e) {

e.printStackTrace();

}

}

public ByteBuffer encode(String str){

return charset.encode(str);

}

public void talk() throws IOException {

socketChannel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);

while(selector.select()>0){

Set readyKeys = selector.selectedKeys();

Iterator it = readyKeys.iterator();

while(it.hasNext()){

SelectionKey key = null;

try {

key = it.next();

it.remove();

if(key.isReadable()){

receive(key);

}

if(key.isWritable()){

send(key);

}

} catch (Exception e) {

e.printStackTrace();

if(key!=null){

key.cancel();

key.channel().close();

}

}

}

}

}

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

final EchoClient client = new EchoClient();

new Thread(){

@Override

public void run() {

client.receiveFromUser();

}

}.start();

client.talk();

}

}

双线程

public class EchoServer {

private Selector selector = null;

private ServerSocketChannel serverSocketChannel;

private int port = 8000;

private Charset charset = Charset.forName("GBK");

public EchoServer() throws IOException {

selector = Selector.open();

serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.socket().setReuseAddress(true);

serverSocketChannel.socket().bind(new InetSocketAddress(port));

System.out.println("服务器启动");

}

public void accept(){

for(;;){

try {

SocketChannel socketChannel = serverSocketChannel.accept();

System.out.println("接收到客户连接,来自:" +

socketChannel.socket().getInetAddress() +

":" + socketChannel.socket().getPort());

socketChannel.configureBlocking(false);

ByteBuffer buffer = ByteBuffer.allocate(1024);

System.out.println("1==========>");

synchronized (EchoServer.this){

System.out.println("2==========>");

selector.wakeup();

System.out.println("3==========>");

// socketChannel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE,buffer);

System.out.println("4==========>");

}

System.out.println("5==========>");

} catch (IOException e) {

e.printStackTrace();

}

}

}

public void service() throws IOException {

for(;;){

System.out.println("0----------->");

synchronized(EchoServer.this){}

System.out.println("1----------->");

int n = selector.select();

System.out.println("2----------->"+n);

if(n==0)continue;

Set readyKeys = selector.selectedKeys();

Iterator it = readyKeys.iterator();

while(it.hasNext()){

SelectionKey key = null;

try{

key = it.next();

it.remove();

if(key.isReadable()){

receive(key);

}

if(key.isWritable()){

send(key);

}

}catch(IOException e){

e.printStackTrace();

try{

if(key!=null){

key.cancel();

key.channel().close();

}

}catch(Exception ex){e.printStackTrace();}

}

}

}

}

public void receive(SelectionKey key) throws IOException {

ByteBuffer buffer = (ByteBuffer) key.attachment();

SocketChannel socketChannel = (SocketChannel) key.channel();

ByteBuffer readBuffer = ByteBuffer.allocate(32);

socketChannel.read(readBuffer);

readBuffer.flip();// 极限设为位置,位置设为0

buffer.limit(buffer.capacity());// 极限设为容量,为读写作准备

buffer.put(readBuffer);

}

public void send(SelectionKey key) throws IOException {

ByteBuffer buffer = (ByteBuffer) key.attachment();

SocketChannel socketChannel = (SocketChannel) key.channel();

buffer.flip();

String data = decode(buffer);

if(data.indexOf("\n")==-1){

return;

}

String outputData = data.substring(0, data.indexOf("\n")+1);

System.out.println(outputData);

ByteBuffer outputBuffer = encode("echo:"+outputData);

while(outputBuffer.hasRemaining()){

socketChannel.write(outputBuffer);

}

ByteBuffer temp = encode(outputData);

buffer.position(temp.limit());

buffer.compact();

if(outputData.equals("bye\r\n")){

key.cancel();

socketChannel.close();

System.out.println("关闭与客户的连接");

}

}

public String decode(ByteBuffer buffer){

CharBuffer charBuffer = charset.decode(buffer);

return charBuffer.toString();

}

public ByteBuffer encode(String str){

return charset.encode(str);

}

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

final EchoServer server = new EchoServer();

new Thread(){

@Override

public void run() {

server.accept();

}

}.start();

server.service();

}

}

注:selector.select()中没有任何事件会进入阻塞状态,如果此时socketChannel.register()向Selector注册事件,由于线程被阻塞,导致无法注册事件,形成死锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值