jetty SocketEndPoint分析

本文深入探讨了Jetty网络通信框架的核心组件设计,包括EndPoint、StreamEndPoint和SocketEndPoint的概念及其作用,详细解释了这些组件如何实现数据的读取、发送、地址获取等关键操作,展示了Jetty简洁而强大的设计风格。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里endPoint的概念可以按字面来当成是端点吧,因为TCP通信是双工的,那么就存在着两个端点。。。

这里我们先来看看SocketEndPint的继承体系:



这个够简单的吧,这几就是直线型的,那么这里我们先来看看EndPoint接口的定义吧:

//端点的定义
public interface EndPoint
{
    
	//关闭当前的端点
    void close() throws IOException;


    //读取数据,然后将其保存到buffer里面,返回表示实际读取的字节数目,-1表示已经读完了
    int fill(Buffer buffer) throws IOException;
    
    //将buffer里面的数据发送出去,返回实际发送的字节数目
    int flush(Buffer buffer) throws IOException;
    //连续写?
    int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException;

    //返回当前的本地地址ip
    public String getLocalAddr();
    
    //本地的主机名
    public String getLocalHost();

    //本地端口
    public int getLocalPort();
    //远程的ip地址
    public String getRemoteAddr();
    //远程的主机名字
    public String getRemoteHost();
    //远程的端口号
    public int getRemotePort();
    //是否是阻塞的
    public boolean isBlocking();
    //是否缓冲
    public boolean isBufferred();
    
    /* ------------------------------------------------------------ */
    public boolean blockReadable(long millisecs) throws IOException;

    /* ------------------------------------------------------------ */
    public boolean blockWritable(long millisecs) throws IOException;

    //是否已经打开
    public boolean isOpen();

    //返回底层的实现,是socket或者channel
    public Object getTransport();
    
    //是否有缓存的输入数据
    public boolean isBufferingInput();
    
    //是否有缓存的输出数据
    public boolean isBufferingOutput();
    
    //将缓存的输出全部输出
    public void flush() throws IOException;
    
}

它主要定义了一些对数据操作的方法,例如flush和fill,其中flush将buffer通过底层发送出去,而fill用于从底层的连接读取数据,然后将其填充到buffer里面去。。。。

当然还有一些其他的方法,例如获取本地和远程的ip的地址什么的,不过总的来说还是很简单的。。。

那么接下来来看看StreamEndPoint的定义吧,它是一个抽象类,实现了EndPoint中的大多数方法:

//基于流的endPoint
public class StreamEndPoint implements EndPoint
{
    InputStream _in;   //输入流
    OutputStream _out;  //输出流
    //构造函数
    public StreamEndPoint(InputStream in, OutputStream out) {
        _in=in;
        _out=out;
    }
    //是否是阻塞的,是
    public boolean isBlocking(){
        return true;
    }

    public boolean blockReadable(long millisecs) throws IOException {
        return true;
    }
    
    public boolean blockWritable(long millisecs) throws IOException {
        return true;
    }

    //是否已经打开
    public boolean isOpen(){
        return _in!=null;
    }

    //是否关闭
    public final boolean isClosed() {
        return !isOpen();
    }

    //关闭,说白了就是关闭底层的输入输出流
    public void close() throws IOException  {
        if (_in!=null)
            _in.close();
        _in=null;
        if (_out!=null)
            _out.close();
        _out=null;
    }

    //从inputstream中读取数据,存到buffer里面
    public int fill(Buffer buffer) throws IOException {
        // TODO handle null array()
        if (_in==null)
            return 0;
            
    	int space=buffer.space();  //当前buffer的空间
    	if (space<=0)
    	{
    	    if (buffer.hasContent())
    	        return 0;
    	    throw new IOException("FULL");
    	}
        
        int len = buffer.readFrom(_in,space);  //读取,space为最大值
    
    	return len;
    }

    //将buffer里面的数据输出到outputstream
    public int flush(Buffer buffer) throws IOException {
        // TODO handle null array()
        if (_out==null)
            return -1;
        int length=buffer.length();  //当前buffer的自己数
        if (length>0)
            buffer.writeTo(_out);
        buffer.clear();
        return length;
    }
    //这里就姑且认为是连续写吧
    public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException {
        int len=0;
        if (header!=null)
        {
            int tw=header.length();
            if (tw>0)
            {
                int f=flush(header);
                len=f;
                if (f<tw)
                    return len;
            }
        }
        
        if (buffer!=null)
        {
            int tw=buffer.length();
            if (tw>0)
            {
                int f=flush(buffer);
                if (f<0)
                    return len>0?len:f;
                len+=f;
                if (f<tw)
                    return len;
            }
        }
        
        if (trailer!=null)
        {
            int tw=trailer.length();
            if (tw>0)
            {
                int f=flush(trailer);
                if (f<0)
                    return len>0?len:f;
                len+=f;
            }
        }
        return len;
    }
    //获取本地的ip地址,这里其实要留给子类来具体的实现
    public String getLocalAddr() {
        return null;
    }
    public String getLocalHost() {
        return null;
    }
    //获取本地的端口
    public int getLocalPort() {
        return 0;
    }
    public String getRemoteAddr() {
        return null;
    }

    public String getRemoteHost() {
        return null;
    }
    public int getRemotePort() {
        return 0;
    }

    public Object getTransport() {
        return null;
    }
    public InputStream getInputStream() {
        return _in;
    }
    public void setInputStream(InputStream in) {
        _in=in;
    }
    public OutputStream getOutputStream() {
        return _out;
    }
    public void setOutputStream(OutputStream out) {
        _out=out;
    }

    public void flush() throws IOException {   
        _out.flush();
    }

    public boolean isBufferingInput() {
        return false;
    }

    public boolean isBufferingOutput() {
        return false;
    }

    public boolean isBufferred() {
        return false;
    }

}

其实从类型的名字就能够看出,它是基于流的,那么它有两个属性inputStream和outputSteam就很正常了,那么它所实现的I/O操作都需要由他们来实现才可以。。。

而且上面具体的方法实现也都很简单,可以看看fill方法,无非就是从inputstream里读取数据然后保存到buffer里面。。。

那么最后我们来看看SocketEndPoint的定义吧:

public class SocketEndPoint extends StreamEndPoint
{
    Socket _socket;
    InetSocketAddress _local;   //本地的地址
    InetSocketAddress _remote;   //远程地址
    //构造函数
    public SocketEndPoint(Socket socket)
    	throws IOException	  {
        super(socket.getInputStream(),socket.getOutputStream());
        _socket=socket;
    }

    //用于判断当前是否打开的,需要底层的socket打开的才表示打开的
    public boolean isOpen() {
        return super.isOpen() && _socket!=null && !_socket.isClosed() && !_socket.isInputShutdown() && !_socket.isOutputShutdown();
    }

    //说白了就是关闭底层的socket
    public void close() throws IOException {
        if (!_socket.isClosed() && !_socket.isOutputShutdown()) {
            try {
                _socket.shutdownOutput();
            }
            catch(IOException e) {
                Log.ignore(e);
            }
            catch(UnsupportedOperationException e) {
                Log.ignore(e);
            }
        }
        _socket.close();
        _in=null;
        _out=null;
        
    }
    //获取本地的地址
    public String getLocalAddr() {
        if (_local==null)
            _local=(InetSocketAddress)_socket.getLocalSocketAddress();
        
       if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
           return Portable.ALL_INTERFACES;
        
        return _local.getAddress().getHostAddress();
    }


    public String getLocalHost() {
        if (_local==null)
            _local=(InetSocketAddress)_socket.getLocalSocketAddress();
        
       if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
           return Portable.ALL_INTERFACES;
        
        return _local.getAddress().getCanonicalHostName();
    }

    //返回本地端口
    public int getLocalPort() {
        if (_local==null)
            _local=(InetSocketAddress)_socket.getLocalSocketAddress();
        return _local.getPort();
    }

    //返回远程的ip地址
    public String getRemoteAddr() {
        if (_remote==null)
            _remote=(InetSocketAddress)_socket.getRemoteSocketAddress();
        
        InetAddress addr = _remote.getAddress();
        return ( addr == null ? null : addr.getHostAddress() );
    }

    //返回远程的主机名
    public String getRemoteHost()  {
        if (_remote==null)
            _remote=(InetSocketAddress)_socket.getRemoteSocketAddress();
        
        return _remote.getAddress().getCanonicalHostName();
    }

    //返回远程的端口地址
    public int getRemotePort() {
        if (_remote==null)
            _remote=(InetSocketAddress)_socket.getRemoteSocketAddress();
        return _remote.getPort();
    }

    //返回底层用于通信的socket
    public Object getTransport() {
        return _socket;
    }
}

这个类从名字也都能看出个大概了,底层的连接用的是socket,那么父类中的stream直接从socket中获取就可以了,然后还是先了一些其他的方法,例如获取本地和远程的地址什么的。。。


看到这里觉得jetty的整个设计还是挺简练的。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值