这里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的整个设计还是挺简练的。。。。