官术网_书友最值得收藏!

Scalability

When the demand on a server increases and decreases, it is desirable to change the resources dedicated to the server. The options available range from the use of manual threads to allow concurrent behavior to those embedded in specialized classes to handle thread pools and NIO channels.

Creating a threaded server

In this section, we will use threads to augment our simple echo server. The definition of the ThreadedEchoServer class is as follows. It implements the Runnable interface to create a new thread for each connection. The private Socket variable will hold the client socket for a specific thread:

public class ThreadedEchoServer implements Runnable {
    private static Socket clientSocket;

    public ThreadedEchoServer(Socket clientSocket) {
        this.clientSocket = clientSocket;
    }
    ...
}

Note

A thread is a block of code that executes concurrently with other blocks of code in an application. The Thread class supports threads in Java. While there are several ways of creating threads, one way is to pass an object that implements the Runnable interface to its constructor. When the Thread class' start method is invoked, the thread is created and the Runnable interface's run method executes. When the run method terminates, so does the thread.

Another way of adding the thread is to use a separate class for the thread. This can be declared separate from the ThreadedEchoServer class or as an inner class of the ThreadedEchoServer class. Using a separate class, better splits the functionality of the application.

The main method creates the server socket as before, but when a client socket is created, the client socket is used to create a thread, as shown here:

    public static void main(String[] args) {
        System.out.println("Threaded Echo Server");
        try (ServerSocket serverSocket = new ServerSocket(6000)) {
            while (true) {
                System.out.println("Waiting for connection.....");
                clientSocket = serverSocket.accept();
                ThreadedEchoServer tes = 
                    new ThreadedEchoServer(clientSocket);
                new Thread(tes).start();
            }

        } catch (IOException ex) {
            // Handle exceptions
        }
        System.out.println("Threaded Echo Server Terminating");
    }

The actual work is performed in the run method as shown next. It is essentially the same implementation as the original echo server, except that the current thread is displayed to clarify which threads are being used:

    @Override
    public void run() {
        System.out.println("Connected to client using [" 
            + Thread.currentThread() + "]");
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(
                    clientSocket.getInputStream()));
                PrintWriter out = new PrintWriter(
                        clientSocket.getOutputStream(), true)) {
            String inputLine;
            while ((inputLine = br.readLine()) != null) {
                System.out.println("Client request [" 
                    + Thread.currentThread() + "]: " + inputLine);
                out.println(inputLine);
            }
            System.out.println("Client [" + Thread.currentThread() 
                + " connection terminated");
        } catch (IOException ex) {
            // Handle exceptions
        }
    }

Using the threaded server

The following output shows the interaction between the server and two clients. The original echo client was started twice. As you can see, each client interaction is performed with a different thread:

Threaded Echo Server

Waiting for connection.....

Waiting for connection.....

Connected to client using [Thread[Thread-0,5,main]]

Client request [Thread[Thread-0,5,main]]: Hello from client 1

Client request [Thread[Thread-0,5,main]]: Its good on this side

Waiting for connection.....

Connected to client using [Thread[Thread-1,5,main]]

Client request [Thread[Thread-1,5,main]]: Hello from client 2

Client request [Thread[Thread-1,5,main]]: Good day!

Client request [Thread[Thread-1,5,main]]: quit

Client [Thread[Thread-1,5,main] connection terminated

Client request [Thread[Thread-0,5,main]]: So long

Client request [Thread[Thread-0,5,main]]: quit

The following interaction is from the first client's perspective:

Simple Echo Client

Waiting for connection.....

Connected to server

Enter text: Hello from client 1

Server response: Hello from client 1

Enter text: Its good on this side

Server response: Its good on this side

Enter text: So long

Server response: So long

Enter text: quit

Server response: quit

The following interaction is from the second client's perspective:

Simple Echo Client

Waiting for connection.....

Connected to server

Enter text: Hello from client 2

Server response: Hello from client 2

Enter text: Good day!

Server response: Good day!

Enter text: quit

Server response: quit

This implementation permits multiple clients to be handled at a time. Clients are not blocked because another client is using the server. However, it also allows a large number of threads to be created. If there are too many threads in existence, then server performance can degrade. We will address these issues in Chapter 7, Network Scalability.

主站蜘蛛池模板: 和田市| 孟州市| 德州市| 晋中市| 台中市| 铁岭市| 长岛县| 方正县| 阿尔山市| 兴化市| 焉耆| 韶关市| 镇雄县| 吉安市| 江阴市| 宣化县| 玉溪市| 博罗县| 柯坪县| 周宁县| 宜兰市| 依兰县| 醴陵市| 方山县| 潮州市| 本溪市| 兴仁县| 射洪县| 五大连池市| 桃园县| 哈巴河县| 宜城市| 南阳市| 迭部县| 香港| 社会| 泽州县| 门头沟区| 石台县| 沙洋县| 濉溪县|