Java Network Programming -- ServerSocket

Java network programming (V) -- ServerSocket (II)

In the last blog Java network programming (IV) - ServerSocket (I) This blog introduces what is a server Socket and how to use it. This blog continues to introduce other knowledge about ServerSocket.

Request queue length

When the server process is running, it may listen to connection requests from multiple clients at the same time. For example, whenever a client process executes the following code:

Socket socket = new Socket("123.345.746.2", 80);

This means that a client's connection request is monitored on port 80 of the remote 123.345.746.2 host. The task of managing client connection requests is completed by the operating system, which stores these connection requests in a first in first out queue. Many operating systems limit the maximum length of a queue, typically 50. When the connection request in the queue reaches the maximum capacity of the queue, the host where the server process is located will reject the new connection request. Only when the server process takes out the connection request from the queue through the accept() method of ServerSocket to make the queue empty can the queue continue to add new connection requests.

For the client process, if the connection request sent by it is added to the server queue, it means that the connection between the client and the server is established successfully, and the client process returns normally from the Socket construction method. If the connection request sent by the client process is rejected by the server, the Socket constructor will throw ConnectionException.

The backlog parameter of the ServerSocket constructor is used to explicitly set the length of the connection request queue, which will override the maximum length of the queue limited by the operating system. It should be noted that if the value of backlog is set to 0, or the value is greater than the maximum length of the queue defined by the operating system, or there is no such parameter, the backlog will still adopt the maximum length of the queue defined by the operating system.

Accept and close connections to clients

The accept() method of ServerSocket takes a customer's connection request from the connection request queue, and then creates a Socket object connected with the customer. After that, the server will obtain the input stream and output stream from the Socket object, and can exchange data with the customer. However, when the server is sending data, if the client disconnects, the server will throw a SocketException subclass of IOException, and the server will exit the program. Therefore, we need to catch this exception so that the server can continue to communicate with other clients.

You can put the code communicating with a single client into a try block. If an exception is encountered, the exception will be caught by the catch code block. The try code block should be followed by a finally code block to close the Socket and disconnect the client.

public void server()
    {
        while(true)
        {
            Socket socket = null;
            try {
                socket = serverSocket.accept();//Waiting for customer connection
                System.out.println("There is already a client connection, address:"+socket.getInetAddress()+" Port number:"+socket.getPort());

                PrintWriter writer = this.getWriter(socket);
                BufferedReader reader = this.getReader(socket);
                String msg = null;
                while ((msg = reader.readLine())!=null)
                {
                    System.out.println(socket.getInetAddress()+" "+socket.getPort()+" Message from:"+msg);
                    writer.println("server I got it: " + msg);
                }
            } catch (IOException e) {
            	//You can choose to print exceptions or not
                //e.printStackTrace();
            }finally {
                try {
                    if(socket!=null)
                        socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

Multithreaded server

Generally, when a Server receives a customer connection, it will communicate with the customer, disconnect the connection after communication, and then receive the next customer connection. However, if more than one customer requests to connect at the same time, these customers must queue for a response.

Many practical applications require the server to provide services to multiple customers at the same time. The HTTP server is the most obvious example. At any time, the HTTP server may receive a large number of customer requests. Each customer wants to get the response of the HTTP server quickly. If customers wait for a long time, the website will lose its reputation and reduce the number of visits. Therefore, a multi-threaded method can be used to enable the server to accept multiple user requests at the same time.

Then you need to modify the code on the server side. When the accept() function is no longer blocked, it means that a client is connected to the server. Then create a new thread and pass the established socket into the thread for operation. The code is as follows:

public class ServerDemo {
    private int port = 40000;
    private ServerSocket serverSocket;
    
    
    
    class ThreadServer extends Thread {
        Socket socket;

        public PrintWriter getWriter(Socket socket) throws IOException {
            OutputStream socketoutput = socket.getOutputStream();
            PrintWriter printWriter = new PrintWriter(socketoutput, true);
            return printWriter;
        }

        public BufferedReader getReader(Socket socket) throws IOException {
            InputStream socketinput = socket.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socketinput));

            return bufferedReader;
        }

        public ThreadServer(Socket s) {
            this.socket = s;
        }

        @Override
        public void run() {
            System.out.println("There is already a client connection, address:" + socket.getInetAddress() + " Port number:" + socket.getPort());

            try {
                PrintWriter writer = this.getWriter(socket);
                BufferedReader reader = this.getReader(socket);
                String msg = null;
                msg = reader.readLine();
                while ((msg) != null) {
                    System.out.println(socket.getInetAddress() + " " + socket.getPort() + " Message from:" + msg);
                    writer.println("server I got it: " + msg);
                    msg = reader.readLine();
                }
            } catch (IOException e) {

            } finally {
                try {
                    if (socket != null)
                        socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }
    
    
    
    
    public ServerDemo() throws IOException {
        serverSocket = new ServerSocket(port);
        System.out.println("Server started");
    }
    public void server()
    {
        while(true)
        {
            Socket socket = null;
            try {
                socket = serverSocket.accept();//Waiting for customer connection

                ThreadServer threadServer = new ThreadServer(socket);
                threadServer.start();
            } catch (IOException e) {
                System.out.println("client :"+socket.getInetAddress()+" Disconnect, The server continues to run");
            }finally {

            }
        }
    }


    public static void main(String[] args) throws IOException {
        new ServerDemo().server();
    }
}

The client code does not need any change. Here is a big hole to note: when the multi-threaded mode is set, the established socket closing code cannot continue to be written under the finally block of the main thread. Otherwise, after a new thread is created, the main thread will continue to execute the code until the socket is finally closed, and there will be a problem!!! In this way, multiple clients can access the server at the same time. The effects are as follows:

Close the server Socket

The close() method of ServerSocket causes the server to release the occupied port and disconnect from all customers. When a server program finishes running, even if the close() method of ServerSocket is not executed, the operating system will release the port occupied by the server. Therefore, the server program does not have to execute the close() method of ServerSocket before it ends.

In some cases, if you want to release the port of the server in time so that other programs can occupy the port, you can explicitly call the close() method of ServerSocket.

Get ServerSocket information

The following two functions are provided by ServerSocket to obtain the bound IP address and port number of the server:

public InetAddress getInetAddress()

public int getLocalPort()

Most servers listen on fixed ports so that clients can access the server. However, anonymous ports are generally used for temporary communication between the server and the client. When the communication ends, the connection is disconnected, and the temporary port occupied by the ServerSocket is released.

Keywords: Java network server

Added by gt500pwr on Thu, 04 Nov 2021 15:25:40 +0200