Nio的介绍
nio是指jdk1.4 及以上版本里提供的新api(New IO) ,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络
nio里面最重要的三个对象
- Buffer 缓存区
- channel 通道
- selector 选择器
nio的常用方法
- buffer.flip()改变position和limit的值,就是传统说的把写变成读,把读变成写。
- buffer.clear()清除buffer,buffer.compact()也是清除,只是清除已读
- Selector.select()监听注册通道.
- Selector.selectKeys获取事件中的SelectKey
- channel.register()把通道注册到Selector,并指定你要监听的事件
Nio的使用
使用nio操作文件
拷贝a.txt的内容到b.txt
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/**
* Created by tannent on 11/14/17.
*/
public class CopyFile {
public static void main(String []args) throws IOException {
//打开文件输入流
FileInputStream inputStream=new FileInputStream(new File("D:\\a.txt"));
//从输入流中获取通道
FileChannel inputChannel= inputStream.getChannel();
//打开文件输出流
FileOutputStream outputStream=new FileOutputStream(new File("D:\\b.txt"));
//从输出流获取通道
FileChannel outChannel=outputStream.getChannel();
//创建一个字节缓存区
ByteBuffer buffer=ByteBuffer.allocate(1024);
while(true){
int n=inputChannel.read(buffer);
if(n<=0){
break;
}
//使读模式改成写模式,其实就是改变Position,Limit的值,
// 把position的值赋给limit,然后把position设置为0
buffer.flip();
//向输出通道写入
outChannel.write(buffer);
//清空缓存区
buffer.clear();
}
outChannel.close();
inputChannel.close();
outputStream.close();
inputStream.close();
}
}
使用Nio进行网络通信
简单的使用,通过客户端发送信息,服务端回消息给客户端
客户端代码
import sun.beans.editors.ByteEditor;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
/**
* Created by tannent on 11/14/17.
*/
public class NioClient {
public static void main(String[] args) throws IOException {
SocketChannel socketChannel=SocketChannel.open();
socketChannel.connect(new InetSocketAddress("localhost",8088));
ByteBuffer byteBuffer= ByteBuffer.wrap("连接服务器".getBytes());
socketChannel.write(byteBuffer);
socketChannel.socket().shutdownOutput();
ByteBuffer outBuffer=ByteBuffer.allocate(1024);
byte[] bytes;
int n=0;
String str="";
while((n=socketChannel.read(outBuffer))>0){
outBuffer.flip();
bytes=new byte[n];
outBuffer.get(bytes);
str+=new String(bytes);
outBuffer.clear();
}
System.out.println(str);
socketChannel.socket().shutdownInput();
socketChannel.socket().close();
socketChannel.close();
}
}
服务端代码
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.Iterator;
import java.util.Set;
/**
* Created by tannent on 11/14/17.
*/
public class Server {
public static void main(String[] args) throws IOException {
Selector selector=Selector.open();
ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
ServerSocket serverSocket= serverSocketChannel.socket();
serverSocket.bind(new InetSocketAddress(8088));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while(true){
int num=selector.select();
if(num>0){
Set<SelectionKey> selectionKeys=selector.selectedKeys();
Iterator<SelectionKey> selectionKeyIterator=selectionKeys.iterator();
while (selectionKeyIterator.hasNext()){
SelectionKey selectionKey=selectionKeyIterator.next();
if(selectionKey.isAcceptable()){
ServerSocketChannel serverSocketChannel1= (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel=serverSocketChannel1.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector,SelectionKey.OP_READ);
selectionKeyIterator.remove();
}else if(selectionKey.isReadable()){
ByteBuffer buffer=ByteBuffer.allocate(1024);
SocketChannel socketChannel= (SocketChannel) selectionKey.channel();
int n=0;
byte[] bytes;
String str="服务器响应,你的连接信息是 ";
while ((n=socketChannel.read(buffer))>0){
buffer.flip();
bytes=new byte[n];
buffer.get(bytes);
str+=new String(bytes);
buffer.clear();
}
socketChannel.write(ByteBuffer.wrap(str.getBytes()));
socketChannel.close();
selectionKeyIterator.remove();
}
}
}
}
}
}
案例2 客户端通过服务器转发数据进行客户端之间的通讯
客户端代码
import com.sun.org.apache.bcel.internal.generic.Select;
import sun.beans.editors.ByteEditor;
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.Iterator;
import java.util.Set;
/**
* Created by tannent on 11/14/17.
*/
public class NioClient {
SocketChannel socketChannel;
public NioClient(String num) {
Selector selector= null;
try {
selector = Selector.open();
socketChannel=SocketChannel.open();
socketChannel.connect(new InetSocketAddress("localhost",8088));
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
ClientThread clientThread=new ClientThread();
clientThread.setSelector(selector);
new Thread(clientThread).start();
sendMsg(MessageType.LOGIN+"#"+num+"#0#你好");
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMsg(String msg){
try {
socketChannel.write(ByteBuffer.wrap(msg.getBytes()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端接受消息的线程
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
/**
* Created by tannent on 11/14/17.
*/
public class ClientThread implements Runnable {
public static int i=0;
private Selector selector;
public void setSelector(Selector selector) {
this.selector = selector;
}
@Override
public void run() {
try {
while (selector.select()>0) {
Set<SelectionKey> selectionKeySet = selector.selectedKeys();
Iterator<SelectionKey> selectionKeyIterator = selectionKeySet.iterator();
while (selectionKeyIterator.hasNext()) {
SelectionKey key = selectionKeyIterator.next();
if (key.isReadable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer outBuffer = ByteBuffer.allocate(1024);
byte[] bytes;
int n = 0;
String str = "";
while ((n = socketChannel.read(outBuffer)) > 0) {
outBuffer.flip();
bytes = new byte[n];
outBuffer.get(bytes);
str += new String(bytes);
outBuffer.clear();
}
// key.interestOps(SelectionKey.OP_READ);
System.out.println(str);
selector.selectedKeys().remove(key);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端代码
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.Iterator;
import java.util.Set;
/**
* Created by tannent on 11/14/17.
*/
public class Server {
public static int i=0;
public static void main(String[] args) throws IOException {
Selector selector=Selector.open();
ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
ServerSocket serverSocket= serverSocketChannel.socket();
serverSocket.bind(new InetSocketAddress(8088));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while(true){
int num=selector.select();
if(num>0){
Set<SelectionKey> selectionKeys=selector.selectedKeys();
Iterator<SelectionKey> selectionKeyIterator=selectionKeys.iterator();
while (selectionKeyIterator.hasNext()){
SelectionKey selectionKey=selectionKeyIterator.next();
if(selectionKey.isAcceptable()){
ServerSocketChannel serverSocketChannel1= (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel=serverSocketChannel1.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector,SelectionKey.OP_READ|SelectionKey.OP_WRITE,ByteBuffer.allocate(1024));
selectionKeyIterator.remove();
}else if(selectionKey.isReadable()){
ByteBuffer buffer=(ByteBuffer)selectionKey.attachment();
buffer.clear();
SocketChannel socketChannel= (SocketChannel) selectionKey.channel();
int n=0;
byte[] bytes;
String str="";
while ((n=socketChannel.read(buffer))>0){
if(n==-1){
socketChannel.close();
}
buffer.flip();
bytes=new byte[n];
buffer.get(bytes);
str+=new String(bytes);
buffer.clear();
}
System.out.println(str);
String[] strings=str.split("#");
for (String str1:strings
) {
System.out.println(str1);
}
if(strings[0].equals("1")){
SocketChannelManage.addSocketChannel(strings[1],socketChannel);
}else {
System.out.println("发送消息");
SocketChannelManage.getSocketChannel(strings[2]).write(ByteBuffer.wrap((strings[1]+"发来消息"+strings[3]).getBytes()));
System.out.println("发送消息");
}
// selectionKey.interestOps(SelectionKey.OP_READ);
selectionKeyIterator.remove();
}
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
发送消息的类型
public final class MessageType {
private MessageType(){}
public static final int LOGIN=1;
public static final int MESSAGE=2;}
服务端channel管理的类
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Map;
public class SocketChannelManage {
private static Map<String,SocketChannel> socketChannelMap=new HashMap<>();
private SocketChannelManage(){}
public static void addSocketChannel(String key,SocketChannel socketChannel){
if(socketChannelMap.containsKey(key))
return;
socketChannelMap.put(key,socketChannel);
}
public static void removeSocketChannel(String key){
socketChannelMap.remove(key);
}
public static SocketChannel getSocketChannel(String key){
return socketChannelMap.get(key);
}
}