单线程服务器

原文作者:Jakob Jenkov 译者:李金平

下面代码展示java中一个单线程服务器的实现。单线程服务器通常不是一个服务器的最优选择,但是下面的代码能很好的说明一个服务器的生命周期。后续实现的多线程服务器代码将基于这个代码做修改。

下面是单线程服务器代码:

package servers;

import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class SingleThreadedServer implements Runnable{

    protected int          serverPort   = 8080;
    protected ServerSocket serverSocket = null;
    protected boolean      isStopped    = false;
    protected Thread       runningThread= null;

    public SingleThreadedServer(int port){
        this.serverPort = port;
    }

    public void run(){
        synchronized(this){
            this.runningThread = Thread.currentThread();
        }
        openServerSocket();

        <strong>while(! isStopped()){
            Socket clientSocket = null;
            try {
                clientSocket = this.serverSocket.accept();
            } catch (IOException e) {
                if(isStopped()) {
                    System.out.println("Server Stopped.") ;
                    return;
                }
                throw new RuntimeException(
                    "Error accepting client connection", e);
            }
            try {
                processClientRequest(clientSocket);
            } catch (IOException e) {
                //log exception and go on to next request.
            }
        }</strong>

        System.out.println("Server Stopped.");
    }

    private void processClientRequest(Socket clientSocket)
    throws IOException {
        InputStream  input  = clientSocket.getInputStream();
        OutputStream output = clientSocket.getOutputStream();
        long time = System.currentTimeMillis();

        output.write(("HTTP/1.1 200 OK/n/n<html><body>" +
                "Singlethreaded Server: " +
                time +
                "</body></html>").getBytes());
        output.close();
        input.close();
        System.out.println("Request processed: " + time);
    }

    private synchronized boolean isStopped() {
        return this.isStopped;
    }

    public synchronized void stop(){
        this.isStopped = true;
        try {
            this.serverSocket.close();
        } catch (IOException e) {
            throw new RuntimeException("Error closing server", e);
        }
    }

    private void openServerSocket() {
        try {
            this.serverSocket = new ServerSocket(this.serverPort);
        } catch (IOException e) {
            throw new RuntimeException("Cannot open port 8080", e);
        }
    }
}

下面是调用代码:

SingleThreadedServer server = new SingleThreadedServer(9000);
new Thread(server).start();

try {
    Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
System.out.println("Stopping Server");
server.stop();

当服务器启动后,你可以用一般的浏览器访问http://localhost:9000/

单线程服务器最核心的地方就是上面代码主循环里的黑体部分,我们再把它展示出来:

while(! isStopped()){
     Socket clientSocket = null;
     try {
         clientSocket = this.serverSocket.accept();
     } catch (IOException e) {
        if(isStopped()) {
            System.out.println("Server Stopped.") ;
            return;
        }
        throw new RuntimeException("Error accepting client connection", e);
     }
     try {
         processClientRequest(clientSocket);
     } catch (IOException e) {
         //log exception and go on to next request.
     }
 }

简短的说,服务器做了以下事情:

1 等待客户端请求
2 处理客户端请求
3 重复1,2

java服务器中的循环大多和这段循环很像,单线程服务器和多线程服务器的区别就在于单线程服务器处理客户端请求和Accept客户端连接使用的是同一个线程。而多线程服务器会把一个连接发给一个工作线程用来处理这个连接上的请求。

处理客户端连接上的请求和Accept客户端连接使用同一个线程不是一个好主意,客户端只有当服务器运行在serverSocket.accept()时,才能连接上服务器。服务器运行在serverSocket.accept()函数外的时间越长,客户端访问被拒绝的可能性就越大。这就是为什么多线程服务器将已建立连接的请求转发给工作线程的因。这样监听线程就能尽可能的运行在serverSocket.accept()之中。

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/113605.html

(0)
上一篇 2021年8月27日
下一篇 2021年8月27日

相关推荐

发表回复

登录后才能评论