Java-IO模型中的BIO模型

x33g5p2x  于2021-12-06 转载在 Java  
字(4.1k)|赞(0)|评价(0)|浏览(540)
  1. BIO介绍 

  2. BIO编程

  3. BIO支持高并发

1. BIO介绍 

在BIO编程中,相应的方法会产生阻塞:accept()、read()、write()、connect(),直至相关的操作等待完成之后才能继续后续代码处理,比如read操作,整个IO操作的过程都会阻塞,直至读取到数据之后才能继续执行(阻塞IO)。

如果BIO来考虑高并发问题,同时处理多个客户端的连接,就必须要使用多线程,即每次accept阻塞等待来自客户端的连接请求,一旦收到连接请求就将获取的套接字socket通过创建一个新的线程来处理IO操作,然后又继续通过accept接收客户端的连接

2. BIO编程

服务端(SingleServer.java):

  1. public class SingleServer {
  2. public static void main(String[] args) {
  3. ServerSocket serverSocket = null;
  4. Socket socket = null;
  5. InputStream inputStream = null;
  6. OutputStream outputStream = null;
  7. try {
  8. //创建ServerSocket实例并绑定端口
  9. serverSocket = new ServerSocket(7777);
  10. System.out.println("服务端绑定端口7777并启动啦");
  11. //等待并接受客户端连接
  12. socket = serverSocket.accept();
  13. //getRemoteSocketAddress() 获取连接的对方的IP和端口
  14. System.out.println("有新的客户端连接:" + socket.getRemoteSocketAddress());
  15. //进行读写操作
  16. inputStream = socket.getInputStream(); //读取客户端数据
  17. outputStream = socket.getOutputStream();//给客户端发送数据
  18. byte[] bytes = new byte[100];
  19. //可多次接受数据
  20. int len = 0;
  21. //判断当前的一个消息是否结束
  22. String recv = null;
  23. while ((len = inputStream.read(bytes)) != -1) {
  24. recv = new String(bytes, 0, len);
  25. System.out.println("客户端发送消息:" + recv);
  26. //封装返回给客户端
  27. outputStream.write(("[echo]" + recv + "\n").getBytes());
  28. outputStream.flush();
  29. //判断当前业务结束标识:客户端发送exit
  30. if (recv != null && "exit".equals(recv.trim())) {
  31. System.out.println("客户端断开即将断开连接");
  32. break;
  33. }
  34. }
  35. } catch (IOException e) {
  36. e.printStackTrace();
  37. } finally {
  38. try {
  39. //关闭资源
  40. if (serverSocket != null) serverSocket.close();
  41. if (socket != null) socket.close();
  42. if (inputStream != null) inputStream.close();
  43. if (outputStream != null) outputStream.close();
  44. } catch (IOException e) {
  45. e.printStackTrace();
  46. }
  47. }
  48. }
  49. }

客户端(Client.java):

  1. public class Client {
  2. public static void main(String[] args) {
  3. Socket socket = null;
  4. InputStream inputStream = null;
  5. OutputStream outputStream = null;
  6. //获取从键盘输入的内容
  7. Scanner scanner = new Scanner(System.in);
  8. scanner.useDelimiter("\n");
  9. try {
  10. //创建socket实例
  11. socket = new Socket();
  12. //连接服务端
  13. socket.connect(new InetSocketAddress("127.0.0.1",7777));
  14. System.out.println("客户端连接服务端成功");
  15. //读写操作
  16. outputStream = socket.getOutputStream();
  17. inputStream = socket.getInputStream();
  18. byte[] bytes = new byte[100];
  19. while (scanner.hasNext()) {
  20. //获取键盘内容
  21. String msg = scanner.next();
  22. if (msg == null || "".equals(msg.trim())) continue;
  23. //发给服务端
  24. outputStream.write(msg.getBytes());
  25. outputStream.flush();
  26. //接收服务端返回的数据
  27. int num = inputStream.read(bytes);
  28. System.out.println("服务端返回:"+new String(bytes,0,num));
  29. if ("exit".equals(msg.trim())) {
  30. //特定结束
  31. System.out.println("客户端主动断开连接啦");
  32. break;
  33. }
  34. }
  35. } catch (IOException e) {
  36. e.printStackTrace();
  37. } finally {
  38. //关闭资源
  39. try {
  40. if (socket != null) socket.close();
  41. if (outputStream != null) outputStream.close();
  42. if (inputStream != null) inputStream.close();
  43. } catch (Exception e) {}
  44. }
  45. }
  46. }

3. BIO支持高并发

服务端(MultiThreadServer.java):

  1. /**
  2. * desc:服务端
  3. * BIO+ 多线程方案:解决高并发问题
  4. * 主线程主要职责:监听客户端的连接,每有一个新客户端的连接获取到连接实例socket,新创建子线程来处理读写IO操作
  5. * 子线程职责:处理IO读写操作
  6. */
  7. public class MultiThreadServer {
  8. public static void main(String[] args) {
  9. ServerSocket serverSocket = null;
  10. try {
  11. //创建ServerSocket实例
  12. serverSocket = new ServerSocket(9999);
  13. System.out.println("服务端绑定端口9999并启动啦");
  14. //等待多客户端的连接,不断循环等待客户端的连接
  15. while (true) {
  16. Socket socket = serverSocket.accept();
  17. System.out.println("有新用户连接啦:"+socket.getRemoteSocketAddress());
  18. //每一个新用户连接都交给一个新线程来处理,重点:将Socket交给子线程
  19. new Thread(new RunableHandler(socket)).start();
  20. }
  21. } catch (IOException e) {
  22. }
  23. }
  24. }

** RunableHandler.java:**

  1. public class RunableHandler implements Runnable {
  2.     private Socket socket;//socket实例,每一个线程单独处理一个socket
  3.     public RunableHandler(Socket socket) {
  4.         this.socket = socket;
  5.     }
  6.     @Override
  7.     public void run() {
  8.         try {
  9.             //进行读写操作
  10.             InputStream inputStream = socket.getInputStream(); //读取客户端数据
  11.             OutputStream outputStream = socket.getOutputStream();//给客户端发送数据
  12.             byte[] bytes = new byte[100];
  13.             //可多次接受数据
  14.             int len = 0;
  15.             //判断当前的一个消息是否结束
  16.             String recv = null;
  17.             while ((len = inputStream.read(bytes)) != -1) {
  18.                 recv = new String(bytes, 0, len);
  19.                 System.out.println("客户端:"+socket.getRemoteSocketAddress()+" 发送消息:" + recv);
  20.                 //封装返回给客户端
  21.                 outputStream.write(("[echo]" + recv + "\n").getBytes());
  22.                 outputStream.flush();
  23.                 //判断当前业务结束标识:客户端发送exit
  24.                 if (recv != null && "exit".equals(recv.trim())) {
  25.                     System.out.println("客户端:"+socket.getRemoteSocketAddress()+" 断开即将断开连接");
  26.                     break;
  27.                 }
  28.             }
  29.             //关闭资源
  30.             socket.close();
  31.             inputStream.close();
  32.             outputStream.close();
  33.         } catch (Exception e) {}
  34.     }
  35. }

以上都是学习中的总结,如果有错误或者有疑问,欢迎一起交流吖~~~

相关文章

最新文章

更多