BIO

Summary::同步阻塞模型,一个连接一个线程
BIO(Blocking IO) 是最传统的IO模型,也称为同步阻塞IO。它实现的是同步阻塞模型,即服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理。如果这个连接不做任何事情会造成不必要的线程开销,并且线程在进行IO操作期间是被阻塞的,无法进行其他任务。在高并发环境下,BIO的性能较差,因为它需要为每个连接创建一个线程,而且线程切换开销较大,不过可以通过线程池机制改善。BIO适合一些简单的、低频的、短连接的通信场景,例如HTTP请求。

优缺点

优点:

  1. 简单易用: BIO模型的编程方式相对简单,易于理解和使用。
  2. 可靠性高: 由于阻塞特性,IO操作的结果是可靠的。
    缺点:
  3. 阻塞等待: 当一个IO操作被阻塞时,线程会一直等待,无法执行其他任务,导致资源浪费。
  4. 并发能力有限: 每个连接都需要一个独立的线程,当连接数增加时,线程数量也会增加,造成资源消耗和性能下降。
  5. 由于I/O操作是同步的,客户端的连接需要等待服务器响应,会降低系统的整体性能。
    Pasted image 20240729095913.png

代码样例

服务端

import java.io.*;
import java.net.*;
public class BIOServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;
        Socket clientSocket = null;
        try {
            //创建服务端
            serverSocket = new ServerSocket(8888);
            System.out.println("服务端已启动,等待客户端连接...");
            while (true){
                // 监听客户端请求,接收不到请求会一直等待
                // //accept() 会阻塞(挂起)调用线程,直到一个客户端尝试连接到由 ServerSocket 监听的端口。一旦有客户端连接,accept() 方法就会返回一个新的 Socket 对象,代表与该客户端的连接。
                clientSocket = serverSocket.accept();
                int port = clientSocket.getPort();
                InetAddress inetAddress = clientSocket.getInetAddress();
                System.out.println("客户端 "+inetAddress+":"+port+" 连接成功!");
                //处理客户端消息
                new Thread(new ServerThread(clientSocket)).start();
            }
        } catch (IOException e) {
            System.out.println("客户端连接失败:" + e.getMessage());
        } finally {
            try {
                if (clientSocket != null) {
                    clientSocket.close();
                }
                if (serverSocket != null) {
                    serverSocket.close();
                }
            } catch (IOException e) {
                System.out.println("关闭资源失败:" + e.getMessage());
            }
        }
    }
}
/**
 * 服务端线程处理类
 */
class ServerThread  implements Runnable{
    private Socket clientSocket;
    public ServerThread(Socket clientSocket) {
        this.clientSocket = clientSocket;
    }
    @Override
    public void run() {
        //获取客户端输入流以便接收客户端数据
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            //获取客户端输出流以便向客户端发送数据
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream());
            int port = clientSocket.getPort();
            InetAddress inetAddress = clientSocket.getInetAddress();
            String address = inetAddress+":"+port;
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                //接收客户端消息
                System.out.println("客户端"+address+"发来消息:" + inputLine);
                //给客户端发送消息
                out.println("服务端已接收到消息并回复:"+inputLine);
                out.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端

public class BIOClient {
    public static void main(String[] args) throws IOException {
        Socket clientSocket = null;
        BufferedReader in = null;
        PrintWriter out = null;
        try {
            //绑定服务端ip和端口号
            clientSocket = new Socket("localhost", 8888);
            System.out.println("连接服务端成功!");
            //获取输入流,接收服务端消息
            in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            //获取输出流,给服务端发送消息
            out = new PrintWriter(clientSocket.getOutputStream(), true);

            Scanner scanner = new Scanner(System.in);
            while (true){
                System.out.print("给服务端发送消息:");
                String msg = scanner.nextLine();
                out.println(msg);

                String response;
                if ((response = in.readLine()) != null) {
                    //接收服务端响应
                    System.out.println("服务端响应:" + response);
                }
            }
        } catch (IOException e) {
            System.out.println("连接服务端失败:" + e.getMessage());
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
                if (clientSocket != null) {
                    clientSocket.close();
                }
            } catch (IOException e) {
                System.out.println("关闭资源失败:" + e.getMessage());
            }
        }
    }
}

参考文章

从理论到实践:深度解读BIO、NIO、AIO的优缺点及使用场景-腾讯云开发者社区-腾讯云