Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)

本文深入介绍了传统的BIO编程模型,并提供了详细的代码示例。通过一个客户端发送算式、服务器计算并返回结果的例子,展示了如何使用Java实现BIO通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处:http://blog.youkuaiyun.com/anxpp/article/details/51512200,谢谢!

    本文会从传统的BIO到NIO再到AIO自浅至深介绍,并附上完整的代码讲解。

    下面代码中会使用这样一个例子:客户端发送一段算式的字符串到服务器,服务器计算后返回结果到客户端。

    代码的所有说明,都直接作为注释,嵌入到代码中,看代码时就能更容易理解,代码中会用到一个计算结果的工具类,见文章代码部分。

    相关的基础知识文章推荐:

    Linux 网络 I/O 模型简介(图文)

    Java 并发(多线程)    

1、BIO编程

    1.1、传统的BIO编程

    网络编程的基本模型是C/S模型,即两个进程间的通信。

    服务端提供IP和监听端口,客户端通过连接操作想服务端监听的地址发起连接请求,通过三次握手连接,如果连接成功建立,双方就可以通过套接字进行通信。

    传统的同步阻塞模型开发中,ServerSocket负责绑定IP地址,启动监听端口;Socket负责发起连接操作。连接成功后,双方通过输入和输出流进行同步阻塞式通信。 

    简单的描述一下BIO的服务端通信模型:采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,它接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理没处理完成后,通过输出流返回应答给客户端,线程销毁。即典型的一请求一应答通宵模型。

    传统BIO通信模型图:

    01

    该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,Java中的线程也是比较宝贵的系统资源,线程数量快速膨胀后,系统的性能将急剧下降,随着访问量的继续增大,系统最终就死-掉-了

    同步阻塞式I/O创建的Server源码:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.anxpp.io.calculator.bio;  
  2. import java.io.IOException;  
  3. import java.net.ServerSocket;  
  4. import java.net.Socket;  
  5. /** 
  6.  * BIO服务端源码 
  7.  * @author yangtao__anxpp.com 
  8.  * @version 1.0 
  9.  */  
  10. public final class ServerNormal {  
  11.     //默认的端口号  
  12.     private static int DEFAULT_PORT = 12345;  
  13.     //单例的ServerSocket  
  14.     private static ServerSocket server;  
  15.     //根据传入参数设置监听端口,如果没有参数调用以下方法并使用默认值  
  16.     public static void start() throws IOException{  
  17.         //使用默认值  
  18.         start(DEFAULT_PORT);  
  19.     }  
  20.     //这个方法不会被大量并发访问,不太需要考虑效率,直接进行方法同步就行了  
  21.     public synchronized static void start(int port) throws IOException{  
  22.         if(server != nullreturn;  
  23.         try{  
  24.             //通过构造函数创建ServerSocket  
  25.             //如果端口合法且空闲,服务端就监听成功  
  26.             server = new ServerSocket(port);  
  27.             System.out.println("服务器已启动,端口号:" + port);  
  28.             Socket socket;  
  29.             //通过无线循环监听客户端连接  
  30.             //如果没有客户端接入,将阻塞在accept操作上。  
  31.             while(true){  
  32.                 socket = server.accept();  
  33.                 //当有新的客户端接入时,会执行下面的代码  
  34.                 //然后创建一个新的线程处理这条Socket链路  
  35.                 new Thread(new ServerHandler(socket)).start();  
  36.             }  
  37.         }finally{  
  38.             //一些必要的清理工作  
  39.             if(server != null){  
  40.                 System.out.println("服务器已关闭。");  
  41.                 server.close();  
  42.                 server = null;  
  43.             }  
  44.         }  
  45.     }  
  46. }  

    客户端消息处理线程ServerHandler源码:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.anxpp.io.calculator.bio;  
  2. import java.io.BufferedReader;  
  3. import java.io.IOException;  
  4. import java.io.InputStreamReader;  
  5. import java.io.PrintWriter;  
  6. import java.net.Socket;  
  7.   
  8. import com.anxpp.io.utils.Calculator;  
  9. /** 
  10.  * 客户端线程 
  11.  * @author yangtao__anxpp.com 
  12.  * 用于处理一个客户端的Socket链路 
  13.  */  
  14. public class ServerHandler implements Runnable{  
  15.     private Socket socket;  
  16.     public ServerHandler(Socket socket) {  
  17.         this.socket = socket;  
  18.     }  
  19.     @Override  
  20.     public void run() {  
  21.         BufferedReader in = null;  
  22.         PrintWriter out = null;  
  23.         try{  
  24.             in = new BufferedReader(new InputStreamReader(socket.getInputStream()));  
  25.             out = new PrintWriter(socket.getOutputStream(),true);  
  26.             String expression;  
  27.             String result;  
  28.             while(true){  
  29.                 //通过BufferedReader读取一行  
  30.                 //如果已经读到输入流尾部,返回null,退出循环  
  31.                 //如果得到非空值,就尝试计算结果并返回  
  32.                 if((expression = in.readLine())==nullbreak;  
  33.                 System.out.println("服务器收到消息:" + expression);  
  34.                 try{  
  35.                     result = Calculator.cal(expression).toString();  
  36.                 }catch(Exception e){  
  37.                     result = "计算错误:" + e.getMessage();  
  38.                 }  
  39.                 out.println(result);  
  40.             }  
  41.         }catch(Exception e){  
  42.             e.printStackTrace();  
  43.         }finally{  
  44.             //一些必要的清理工作  
  45.             if(in != null){  
  46.                 try {  
  47.                     in.close();  
  48.                 } catch (IOException e) {  
  49.                     e.printStackTrace();  
  50.                 }  
  51.                 in = null;  
  52.             }  
  53.             if(out != null){  
  54.                 out.close();  
  55.                 out = null;  
  56.             }  
  57.             if(socket != null){  
  58.                 try {  
  59.                     socket.close();  
  60.                 } catch (IOException e) {  
  61.                     e.printStackTrace();  
  62.                 }  
  63.                 socket = null;  
  64.             }  
  65.         }  
  66.     }  
  67. }  

    同步阻塞式I/O创建的Client源码:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.anxpp.io.calculator.bio;  
  2. import java.io.BufferedReader;  
  3. import java.io.IOException;  
  4. import java.io.InputStreamReader;  
  5. import java.io.PrintWriter;  
  6. import java.net.Socket;  
  7. /** 
  8.  * 阻塞式I/O创建的客户端 
  9.  * @author yangtao__anxpp.com 
  10.  * @version 1.0 
  11.  */  
  12. public class Client {  
  13.     //默认的端口号  
  14.     private static int DEFAULT_SERVER_PORT = 12345;  
  15.     private static String DEFAULT_SERVER_IP = "127.0.0.1";  
  16.     public static void send(String expression){  
  17.         send(DEFAULT_SERVER_PORT,expression);  
  18.     }  
  19.     public static void send(int port,String expression){  
  20.         System.out.println("算术表达式为:" + expression);  
  21.         Socket socket = null;  
  22.         BufferedReader in = null;  
  23.         PrintWriter out = null;  
  24.         try{  
  25.             socket = new Socket(DEFAULT_SERVER_IP,port);  
  26.             in = new BufferedReader(new InputStreamReader(socket.getInputStream()));  
  27.             out = new PrintWriter(socket.getOutputStream(),true);  
  28.             out.println(expression);  
  29.             System.out.println("___结果为:" + in.readLine());  
  30.         }catch(Exception e){  
  31.             e.printStackTrace();  
  32.         }finally{  
  33.             //一下必要的清理工作  
  34.             if(in != null){  
  35.                 try {  
  36.                     in.close();  
  37.                 } catch (IOException e) {  
  38.                     e.printStackTrace();  
  39.                 }  
  40.                 in = null;  
  41.             }  
  42.             if(out != null){  
  43.                 out.close();  
  44.                 out = null;  
  45.             }  
  46.             if(socket != null){  
  47.                 try {  
  48.                     socket.close();  
  49.                 } catch (IOException e) {  
  50.                     e.printStackTrace();  
  51.                 }  
  52.                 socket = null;  
  53.             }  
  54.         }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值