一、Java的IO((Input/Output))模型
传统IO和Java NIO最大的区别是传统的IO是面向流,NIO是面向Buffer Socket之间建立链接及通信的过程!实际上就是对TCP/IP连接与通信过程的抽象: 1.服务端Socket会bind到指定的端口上,Listen客户端的”插入” 2.客户端Socket会Connect到服务端 3.当服务端Accept到客户端连接后 4.就可以进行发送与接收消息了 5.通信完成后即可Close
1、BIO(阻塞)
1.socketServer的accept方法是阻塞的;
2.获得连接的顺序是和客户端请求到达服务器的先后顺序相关;
3.适用于一个线程管理一个通道的情况;因为其中的流数据的读取是阻塞的;
4.适合需要管理同时打开不太多的连接,这些连接会发送大量的数据。
客户端代码
//Bind,Connect
Socket client = new Socket("127.0.0.1",7777);
//读写
PrintWriter pw = new PrintWriter(client.getOutputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
pw.write(br.readLine());
//Close
pw.close();
br.close();
服务端代码
Socket socket;
//Bind,Listen
ServerSocket ss = new ServerSocket(7777);
while (true) {
//Accept
socket = ss.accept();
//一般新建一个线程执行读写
BufferedReader br = new BufferedReader(
new InputStreamReader(socket .getInputStream()));
System.out.println("you input is : " + br.readLine());
}
2、NIO(非阻塞)
1.基于事件驱动,当有连接请求,会将此连接注册到多路复用器上(selector);
2.在多路复用器上可以注册监听事件,比如监听accept、read;
3.通过监听,当真正有请求数据时,才来处理数据;
4.会不停的轮询是否有就绪的事件,所以处理顺序和连接请求先后顺序无关,与请求数据到来的先后顺序有关;
5.优势在于一个线程管理多个通道;但是数据的处理将会变得复杂;
6.适合需要管理同时打开的成千上万个连接,这些连接每次只是发送少量的数据。
NIO客户端
//连接
//获取socket通道
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
//获得通道管理器
selector=Selector.open();
channel.connect(new InetSocketAddress(serverIp, port));
//为该通道注册SelectionKey.OP_CONNECT事件
channel.register(selector, SelectionKey.OP_CONNECT);
//监听
while(true){
//选择注册过的io操作的事件(第一次为SelectionKey.OP_CONNECT)
selector.select();
while(SelectionKey key : selector.selectedKeys()){
if(key.isConnectable()){
SocketChannel channel=(SocketChannel)key.channel();
if(channel.isConnectionPending()){
channel.finishConnect();//如果正在连接,则完成连接
}
channel.register(selector, SelectionKey.OP_READ);
}else if(key.isReadable()){ //有可读数据事件。
SocketChannel channel = (SocketChannel)key.channel();
ByteBuffer buffer = ByteBuffer.allocate(10);
channel.read(buffer);
byte[] data = buffer.array();
String message = new String(data);
System.out.println("recevie message from server:, size:" + buffer.position() + " msg: " + message);
}
}
}
服务端
//连接
//获取一个ServerSocket通道
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.socket().bind(new InetSocketAddress(port));
//获取通道管理器
selector = Selector.open();
//将通道管理器与通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
//监听
while(true){
//当有注册的事件到达时,方法返回,否则阻塞。
selector.select();
for(SelectionKey key : selector.selectedKeys()){
if(key.isAcceptable()){
ServerSocketChannel server = (ServerSocketChannel)key.channel();
SocketChannel channel = server.accept();
channel.write(ByteBuffer.wrap(
new String("send message to client").getBytes()));
//在与客户端连接成功后,为客户端通道注册SelectionKey.OP_READ事件。
channel.register(selector, SelectionKey.OP_READ);
}else if(key.isReadable()){ //有可读数据事件
SocketChannel channel = (SocketChannel)key.channel();
ByteBuffer buffer = ByteBuffer.allocate(10);
int read = channel.read(buffer);
byte[] data = buffer.array();
String message = new String(data);
System.out.println("receive message from client, size:" + buffer.position() + " msg: " + message);
}
}
}