Java's BIO network programming

Commonly used routines

In network programming, the one that provides the service is called the server, and the one that connects to the service is called the client. In the development process, the class with the word Server or ServerSocket is used by the server. If there is only a class with the word Socket, it is responsible for specific network reading and writing.

For the server, ServerSocket is just a place, not responsible for specific read and write operations, only responsible for creating a new socket to communicate with the client after connecting to the client. The specific communication with the client is still a Socket class. This is common to all modes of network programming.

In network programming, we only need to pay attention to three things: connection (the client connects to the server, the server waits for and receives the connection), reads network data, and writes network data. The server provides IP and listening port. The client initiates a connection request to the address monitored by the server through the connection operation. After the connection is successfully established, the two parties can communicate through the socket.

BIO

insert image description here
The server using the BIO communication model usually has an independent Acceptor thread responsible for monitoring the connection of the client. After receiving the client connection request, it creates a new thread for each client to process the link. After the processing is completed, it passes the output The stream returns a reply to the client, and the thread is destroyed. That is, a typical request-response model. At the same time, the reading and writing of data must also be blocked in a thread and wait for its completion.

The biggest problem with this model is the lack of elastic scalability. When the number of concurrent client visits increases, the number of threads on the server and the number of concurrent client visits are proportional to 1:1. Threads in Java are also relatively valuable system resources. After the number of threads expands rapidly, the performance of the system will drop sharply. As the number of visits continues to increase, the system will eventually die.

In order to improve this one-connection-one-thread model, we can use thread pools to manage these threads, and implement a model in which one or more threads process N clients (but the bottom layer still uses synchronous blocking I/O), usually called For the "pseudo-asynchronous I/O model".

Code

client:

public class Client {
    
    

    public static void main(String[] args) throws IOException {
    
    
        //客户端启动必备
        Socket socket = null;
        //实例化与服务端通信的输入输出流
        ObjectOutputStream output = null;
        ObjectInputStream input = null;
        //服务器的通信地址
        InetSocketAddress addr
                = new InetSocketAddress("127.0.0.1",10001);

        try{
    
    
            socket = new Socket();
            socket.connect(addr);//连接服务器

            output = new ObjectOutputStream(socket.getOutputStream());
            input = new ObjectInputStream(socket.getInputStream());

            /*向服务器输出请求*/
            output.writeUTF("ceshi");
            output.flush();

            //接收服务器的输出
            System.out.println(input.readUTF());
        }finally{
    
    
            if (socket!=null) socket.close();
            if (output!=null) output.close();
            if (input!=null) input.close();

        }
    }

}

Server:

public class Server {
    
    

    public static void main(String[] args) throws IOException {
    
    
        //服务端启动必备
        ServerSocket serverSocket = new ServerSocket();
        //表示服务端在哪个端口上监听
        serverSocket.bind(new InetSocketAddress(10001));
        System.out.println("Start Server ....");
        try{
    
    
            while(true){
    
    
            //当有客户端连接时,会执行完一次循环,到下一次循环时,如果没有客户端连接,则一直阻塞在serverSocket.accept()方法那里,不往下执行,直到下一个客户端连接过来
                new Thread(new ServerTask(serverSocket.accept())).start();
            }
        }finally {
    
    
            serverSocket.close();
        }
    }

    //每个和客户端的通信都会打包成一个任务,交个一个线程来执行
    private static class ServerTask implements Runnable{
    
    

        private Socket socket = null;
        public ServerTask(Socket socket){
    
    
            this.socket = socket;
        }

        @Override
        public void run() {
    
    
            //实例化与客户端通信的输入输出流
            try(ObjectInputStream inputStream =
                    new ObjectInputStream(socket.getInputStream());
                ObjectOutputStream outputStream =
                    new ObjectOutputStream(socket.getOutputStream())){
    
    

                //接收客户端的输出,也就是服务器的输入
                String userName = inputStream.readUTF();
                System.out.println(Thread.currentThread().getName()+"Accept client message:"+userName);

                //服务器的输出,也就是客户端的输入
                outputStream.writeUTF(Thread.currentThread().getName()+"Hello,"+userName);
                outputStream.flush();
            }catch(Exception e){
    
    
                e.printStackTrace();
            }finally {
    
    
                try {
    
    
                    socket.close();
                } catch (IOException e) {
    
    
                    e.printStackTrace();
                }
            }
        }
    }

}

The thread pool implements the server:

public class ServerPool {
    
    

    private static ExecutorService executorService
            = Executors.newFixedThreadPool(
                    Runtime.getRuntime().availableProcessors());

    public static void main(String[] args) throws IOException {
    
    
        //服务端启动必备
        ServerSocket serverSocket = new ServerSocket();
        //表示服务端在哪个端口上监听
        serverSocket.bind(new InetSocketAddress(10001));
        System.out.println("Start Server ....");
        try{
    
    
            while(true){
    
    
                executorService.execute(new ServerTask(serverSocket.accept()));
            }
        }finally {
    
    
            serverSocket.close();
        }
    }

    //每个和客户端的通信都会打包成一个任务,交个一个线程来执行
    private static class ServerTask implements Runnable{
    
    

        private Socket socket = null;
        public ServerTask(Socket socket){
    
    
            this.socket = socket;
        }

        @Override
        public void run() {
    
    
            //实例化与客户端通信的输入输出流
            try(ObjectInputStream inputStream =
                    new ObjectInputStream(socket.getInputStream());
                ObjectOutputStream outputStream =
                    new ObjectOutputStream(socket.getOutputStream())){
    
    

                //接收客户端的输出,也就是服务器的输入
                String userName = inputStream.readUTF();
                System.out.println("Accept client message:"+userName);

                //服务器的输出,也就是客户端的输入
                outputStream.writeUTF("Hello,"+userName);
                outputStream.flush();
            }catch(Exception e){
    
    
                e.printStackTrace();
            }finally {
    
    
                try {
    
    
                    socket.close();
                } catch (IOException e) {
    
    
                    e.printStackTrace();
                }
            }
        }
    }

}

Understanding of blocking

The blocking of bio is mainly reflected in two places:
①If a server is ready to start, then the main thread has been waiting for the connection of the client, and the main thread has been blocked during the waiting process. That is, the socketServer.accept() method will only execute the code when there is a client connection. Otherwise it will always be blocked here.

② After the connection is established, a sub-thread serves the connection, and the service provided by the sub-thread is nothing more than socket communication. Before reading the socket information, the sub-thread is always waiting and in a blocked state.

The pseudo-asynchronous IO implemented by the thread pool only reduces the number of new threads created when the client connects to the server, and does not help blocking.

Guess you like

Origin blog.csdn.net/qq1309664161/article/details/128067057