Tomcat源码学习一 Tomcat实现基石Socket

来源:互联网 发布:科比 知乎 编辑:程序博客网 时间:2024/05/16 16:11

Tomcat源码学习一 Tomcat实现基石Socket

简述

Tomcat是什么?相信做Java Web的都应该用过Tomcat,它是Web轻量级的应用服务器,或者说是一个Servlet容器。 通过浏览器(Http协议)请求我们的Servlet类配置的路径这个过程是怎样的?Tomcat通过传输层的Socket实现了一个ServerSocket类,等待浏览器的请求并将请求信息封装成Request实例,发送给相应的Servlet,并且将返回结果封装成Response返回给浏览器。HttpServletRequest,HttpServletResponse 两个接口。相信大家都不会陌生,是Http协议的请求和响应。在servlet-api.jar包里这两个接口的实例是怎么来得。这就得在Tomcat源码中寻找答案了。

1.Socket简单实现

Socket又称套接字,是Tcp/Ip传输层的一种应用。下面模拟一个打电话场景.
/** * 电话服务端 * step 1 创建serverSocket * step 2 绑定地址和端口 * step 3 accept 等待客户端连接 * */public class CallServer {    public static ServerSocket serverSocket;    public static Socket socket;    public static BufferedReader reader =null;    public static PrintWriter writer = null;    public CallServer(String host,int port) {        try {            //  创建serverSocket            serverSocket = new ServerSocket();            // 地址和端口            SocketAddress endpoint = new InetSocketAddress(InetAddress.getByName(host),port);            // 最大连接数            int backlog = 5;            //  绑定地址和端口            serverSocket.bind(endpoint,5);            // 阻塞式     等待客户端连接            socket = serverSocket.accept();            System.out.println("Server---------李四 已经连接 接收李四消息!");            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));            String msg=null;            while((msg = reader.readLine())!=null){                System.out.println(msg);            }            writer = new PrintWriter(socket.getOutputStream());            writer.write("hello lisi");            writer.flush();            writer.close();            reader.close();            socket.close();            serverSocket.close();        } catch (IOException e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        CallServer zhangsan = new CallServer("127.0.0.1",8080);    }}
/** * 电话客户端 */public class CallClient {    private static Socket socket;    public static BufferedReader reader =null;    public static PrintWriter writer = null;    public CallClient(String host,int port) {        try {            socket = new Socket();            // 地址和端口            SocketAddress endpoint = new InetSocketAddress(InetAddress.getByName(host),port);            socket.connect(endpoint);            System.out.println("Client---------已经接通张三 接收张三消息!");            writer = new PrintWriter(socket.getOutputStream());            writer.write("hello zhangsan");            writer.flush();            //关闭输出流单项关闭 输出流 不加输出流不关闭,server不会接受到消息            socket.shutdownOutput();            //关闭 输出流会直接关闭socket            //writer.close();            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));            String msg=null;            while((msg = reader.readLine())!=null){                System.out.println(msg);            }            writer.close();            reader.close();            socket.close();        } catch (IOException e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        CallClient lisi = new CallClient("127.0.0.1",8080);    }}
注意:1.在客户端或者服务端通过socket.shutdownOutput()都是单向关闭的,即关闭客户端的输出流并不会关闭服务端的输出流,所以是一种单方向的关闭流2.通过socket.shutdownOutput()关闭输出流,但socket仍然是连接状态,连接并未关闭3.如果直接关闭输入或者输出流,即:in.close()或者out.close(),会直接关闭socket

2.Tomcat Socket源码阅读

2.1 AbstractEndpoint.init()

抽象终端类 用来处理底层 socket 链接。它有三个实现类,分别是3中不同的连接方法。NioEndpoint,AprEndpoint,JIoEndpoint 首相看AbstractEndpoint初始化方法。
    // Endpoint 初始化    public final void init() throws Exception {        testServerCipherSuitesOrderSupport();        if (bindOnInit) {            //绑定端口 其实现serverSocket的bind            bind();            bindState = BindState.BOUND_ON_INIT;        }    }

2.2 JIoEndpoint.bind()

public void bind() throws Exception {        //初始化接收器线程数        if (acceptorThreadCount == 0) {            acceptorThreadCount = 1;        }        // 初始化最大连接数        if (getMaxConnections() == 0) {            // User hasn't set a value - use the default            setMaxConnections(getMaxThreadsInternal());        }        if (serverSocketFactory == null) {            if (isSSLEnabled()) {            //创建ssl serverSocketFactory                serverSocketFactory =                    handler.getSslImplementation().getServerSocketFactory(this);            } else {                serverSocketFactory = new DefaultServerSocketFactory(this);            }        }        if (serverSocket == null) {            try {                if (getAddress() == null) {                //创建 serverSocket                    serverSocket = serverSocketFactory.createSocket(getPort(),                            getBacklog());                } else {                    serverSocket = serverSocketFactory.createSocket(getPort(),                            getBacklog(), getAddress());                }            } catch (BindException orig) {                String msg;                if (getAddress() == null)                    msg = orig.getMessage() + " <null>:" + getPort();                else                    msg = orig.getMessage() + " " +                            getAddress().toString() + ":" + getPort();                BindException be = new BindException(msg);                be.initCause(orig);                throw be;            }        }    }

2.3 Acceptor 接收器类

protected class Acceptor extends AbstractEndpoint.Acceptor {        @Override        public void run() {            int errorDelay = 0;            // 循环,直到接收到关闭命令为止            while (running) {                // 如果端点暂停,则循环                while (paused && running) {                    state = AcceptorState.PAUSED;                    try {                        Thread.sleep(50);                    } catch (InterruptedException e) {                    }                }                if (!running) {                    break;                }                state = AcceptorState.RUNNING;                try {                    ////当前连接数                    countUpOrAwaitConnection();                    Socket socket = null;                    try {                        // 此处用来接收 请求 监听客户端连接                        // /取出队列中的连接请求                        socket = serverSocketFactory.acceptSocket(serverSocket);                    } catch (IOException ioe) {                        countDownConnection();                        // 必要时引入延迟                        errorDelay = handleExceptionWithDelay(errorDelay);                        throw ioe;                    }                    // 成功接受,重置错误延迟                    errorDelay = 0;                    // Configure the socket                    if (running && !paused && setSocketOptions(socket)) {                        // TODO 监听到连接后(即浏览器向服务器发起一次请求)                        ////处理请求                        // Hand this socket off to an appropriate processor                        if (!processSocket(socket)) {                            countDownConnection();                            // 关闭 socket 链接                            closeSocket(socket);                        }                    } else {                        countDownConnection();                        closeSocket(socket);                    }                } catch (IOException x) {                    if (running) {                        log.error(sm.getString("endpoint.accept.fail"), x);                    }                } catch (NullPointerException npe) {                    if (running) {                        log.error(sm.getString("endpoint.accept.fail"), npe);                    }                } catch (Throwable t) {                    ExceptionUtils.handleThrowable(t);                    log.error(sm.getString("endpoint.accept.fail"), t);                }            }            state = AcceptorState.ENDED;        }    }

总结

Tomcat实现的基石是Socket,在这里只是简单的分析。也只是冰山一角。其中Socket编程还有很多知识,像Tcp/Ip协议,长连接,短连接等。
原创粉丝点击