NIO非阻塞式网络通信
1.简单介绍
阻塞式:客户端发送请求给服务端,服务端不能确定客户端发过来的数据真实有效时,这个线程会阻塞,此时服务端的线程等待。当客户端发送大量数据时,服务端使用多个线程进行数据传输。(使用多线程解决IO阻塞问题)即使是使用多线程,那么一个服务器的线程数量还是有效的,一旦有阻塞就无法做其他事情。这就是传统IO的阻塞问题。
非阻塞式: 添加了选择器,将每个通道注册到该选择器上,(选择器的作用是监控通道的IO状况(读,写,连接等等))。选择器会实时监控通道的状态,某个通道上的请求事件完全准备就绪,选择器才会将任务分配到服务端的一个或者多个线程去运行。如果客户端的请求没有准备就绪,服务器断的线程完全可以做其他事情。
TCP:
package jnio;
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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import org.junit.Test;
public class TestNoBlockingNIO {
@Test
public void server() throws IOException {
// 获取通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//设置非阻塞模式
serverSocketChannel.configureBlocking(false);
// 绑定链接
serverSocketChannel.bind(new InetSocketAddress(7777));
// 获取选择器
Selector selector = Selector.open();
// 将通道注册到选择器上.SelectionKey为选择键,监控什么状态
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
// 轮循式的获取准备事件
while (selector.select() > 0) {
//获取当前选择器中所有注册的选择键(已就绪的)
Iterator<SelectionKey> iterable = selector.selectedKeys()
.iterator();
//迭代获取
while(iterable.hasNext()){
SelectionKey selectionKey = iterable.next();
//判断是什么准备事件
if (selectionKey.isAcceptable()) {
SocketChannel socketChannel = serverSocketChannel.accept();
//将客户端的链接切换成非阻塞模式
socketChannel.configureBlocking(false);
//将该通道注册到选择器上
socketChannel.register(selector, SelectionKey.OP_READ);
}else if(selectionKey.isReadable()){
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int len = 0;
while((len = socketChannel.read(buffer))!=-1){
buffer.flip();
System.out.println(new String(buffer.array(),0,len));
buffer.clear();
}
}
}
//取消选择键
iterable.remove();
}
}
@Test
public void client() throws IOException {
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(
"127.0.0.1", 7777));
// 切换成非阻塞模式
socketChannel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put(new Date().toString().getBytes());
buffer.flip();
socketChannel.write(buffer);
buffer.clear();
socketChannel.close();
}
}
UDP:
package jnio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Date;
import java.util.Iterator;
import java.util.Scanner;
import org.junit.Test;
public class Udp {
@Test
public void send() throws IOException{
DatagramChannel datagramChannel = DatagramChannel.open();
datagramChannel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()){
String s = scanner.next();
buffer.put((new Date().toString()+" :"+s).getBytes());
buffer.flip();
datagramChannel.send(buffer, new InetSocketAddress("127.0.0.1",9999));
buffer.clear();
}
datagramChannel.close();
}
@Test
public void reciver() throws IOException{
DatagramChannel datagramChannel= DatagramChannel.open();
datagramChannel.configureBlocking(false);
datagramChannel.bind(new InetSocketAddress(9999));
Selector selector = Selector.open();
datagramChannel.register(selector,SelectionKey.OP_READ);
while(selector.select()>0){
Iterator<SelectionKey> iterator = selector.keys().iterator();
while(iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
if (selectionKey.isReadable()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
datagramChannel.receive(buffer);
buffer.flip();
System.out.println(new String(buffer.array(),0,buffer.limit()));
buffer.clear();
}
}
iterator.remove();
}
}
}