在工作中,无论什么项目我们都会用到网络传输,tomcat等server服务器、Dubbo等Rpc协议框架、Redis等NOsql数据库、各种MQ的中间件等等。这篇文章是学习《Netty权威指南》后的总结,从Java基础的BIO、NIO、AIO进行学习。
在说JavaIO以前,先看看unix提供的5种IO模型:
1,阻塞IO模型:
2,非阻塞IO模型:
3,IO复用模型:
4,信号驱动IO模型:
5,异步IO模型:
小结:最基本的1对1IO阻塞模型,通过使用轮询调用、selector管家进行协调、buffer缓存空间进行解耦、信号进行主动通知等方面进行优化实现的各种模型。
一,Java最基础的BIO,网络编程基于Client/Server模型,BIO就是其中最基础的阻塞模型,通过ServerSocket和Socket建立通道,进行通讯。下边我们以“查询服务器时间”例子,来进行实现。
public class TimeServer {
public static void main(String[] args) throws IOException {
int port = 8090;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
}catch (NumberFormatException e){
}
}
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
System.out.println("The time server is start in port : " + port);
Socket socket =null;
while (true){
socket =serverSocket.accept();
new Thread(new TimeServerHandler(socket)).start();
}
}finally {
if(serverSocket != null){
System.out.println("The time server close");
serverSocket.close();
serverSocket =null;
}
}
}
}
public class TimeServerHandler implements Runnable {
private Socket socket;
public TimeServerHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader in = null;
PrintWriter out = null;
try {
in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
out = new PrintWriter(this.socket.getOutputStream(), true);
String currentTime = null;
String body = null;
while (true) {
body = in.readLine();
if (body == null) {
break;
}
System.out.println("the time server receive order : " + body);
currentTime = "query time order".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "bad order";
out.println(currentTime);
}
} catch (Exception e) {
if (in != null) {
try {
in.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (out != null) {
out.close();
out = null;
}
if (this.socket != null) {
try {
this.socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
this.socket = null;
}
} finally {
}
}
}
public class TimeClient {
public static void main(String[] args) {
int port = 8090;
if(args !=null && args.length >0){
try {
port = Integer.valueOf(args[0]);
}catch (NumberFormatException e){
}
}
Socket socket =null;
BufferedReader in =null;
PrintWriter out = null;
try {
socket =new Socket("127.0.0.1",port);
in =new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
out.println("QUERY TIME ORDER");
System.out.println("Send order 2 server succeed.");
String resp = in.readLine();
System.out.println("Now is :" + resp);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(out !=null){
out.close();
out =null;
}
if(in !=null){
try {
in.close();
}catch (IOException e){
e.printStackTrace();
}
in = null;
}
if(socket !=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket = null;
}
}
}
}
二,伪异步IO:为了解决同步阻塞IO一个链路需要一个线程来处理的问题,可以利用引入线程池,可以使用线程池中的线程处理多个client客户端,提高线程的利用率。但是如果由于通选非常慢,耗尽了线程池中的线程,其它的client处理请求就会在队列中排队阻塞了,所以仅仅是理想情况下,看起来异步了。来看伪异步“查询服务器时间”的例子。
public class TimeServer {
public static void main(String[] args) throws IOException {
int port = 8090;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
}catch (NumberFormatException e){
}
}
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
System.out.println("The time server is start in port : " + port);
Socket socket =null;
//thread pool
TimeServerHandlerExecutePool singleExecutePool = new TimeServerHandlerExecutePool(50,10000);
while (true){
socket =serverSocket.accept();
singleExecutePool.execute(new TimeServerHandler(socket));
}
}finally {
if(serverSocket != null