`
Donald_Draper
  • 浏览: 982403 次
社区版块
存档分类
最新评论

ServerSocketChannelImpl解析

    博客分类:
  • NIO
nio 
阅读更多
Channel接口定义:http://donald-draper.iteye.com/blog/2369111
AbstractInterruptibleChannel接口定义:http://donald-draper.iteye.com/blog/2369238
SelectableChannel接口定义:http://donald-draper.iteye.com/blog/2369317
SelectionKey定义:http://donald-draper.iteye.com/blog/2369499
SelectorProvider定义:http://donald-draper.iteye.com/blog/2369615
AbstractSelectableChannel定义:http://donald-draper.iteye.com/blog/2369742
NetworkChannel接口定义:http://donald-draper.iteye.com/blog/2369773
ServerSocketChannel定义:http://donald-draper.iteye.com/blog/2369836
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper):
http://donald-draper.iteye.com/blog/2370811
WindowsSelectorImpl解析二(选择操作,通道注册,通道反注册,选择器关闭等):
http://donald-draper.iteye.com/blog/2370862
在ServerSocketChannel定义这篇文章中,我们看了一下ServerSocketChannel的定义,ServerSocketChannel主要是绑定socket地址和监听通道连接请求。
今天先来看一下如何打开一个ServerSocketChannel,从ServerSocketChannel的
open方法开始:
public static ServerSocketChannel open() throws IOException {
       return SelectorProvider.provider().openServerSocketChannel();
}

看到这个方法是不是很熟悉,我们在SelectorProvider定义这篇文章中,有讲过SelectorProvider.provider()的加载SelectorProvider的实例过程:
我们直接贴过来:
//SelectorProvider
  
 public static SelectorProvider provider() {  
            synchronized (lock) {  
                if (provider != null)  
                    return provider;  
           //在与当前线程相同访问控制权限的环境中,加载SelectorProvider实例  
                return AccessController.doPrivileged(  
                    new PrivilegedAction<SelectorProvider>() {  
                        public SelectorProvider run() {  
                                if (loadProviderFromProperty())  
                        //获取系统配置的SelectorProvider  
                                    return provider;  
                                if (loadProviderAsService())  
                         //获取类加载路径下的SelectorProvider  
                                    return provider;  
                        //加载默认的SelectorProvider  
                                provider = sun.nio.ch.DefaultSelectorProvider.create();  
                                return provider;  
                            }  
                        });  
            }  
    }  


来看默认的DefaultSelectorProvider
//DefaultSelectorProvider
   
package sun.nio.ch;  
      
    import java.nio.channels.spi.SelectorProvider;  
      
    // Referenced classes of package sun.nio.ch:  
    //            WindowsSelectorProvider  
      
    public class DefaultSelectorProvider  
    {  
        private DefaultSelectorProvider()  
        {  
        }  
        public static SelectorProvider create()  
        {  
            //默认的WindowsSelectorProvider  
            return new WindowsSelectorProvider();  
        }  
    }  

再来看WindowsSelectorProvider
//WindowsSelectorProvider
  
 package sun.nio.ch;  
      
    import java.io.IOException;  
    import java.nio.channels.spi.AbstractSelector;  
      
    // Referenced classes of package sun.nio.ch:  
    //            SelectorProviderImpl, WindowsSelectorImpl  
      
    public class WindowsSelectorProvider extends SelectorProviderImpl  
    {  
      
        public WindowsSelectorProvider()  
        {  
        }  
        public AbstractSelector openSelector()  
            throws IOException  
        {  
           //默认的选择器实现类  
            return new WindowsSelectorImpl(this);  
        }  
    }  


再来看SelectorProviderImpl
//SelectorProviderImpl
 
  package sun.nio.ch;  
      
    import java.io.IOException;  
    import java.net.ProtocolFamily;  
    import java.nio.channels.*;  
    import java.nio.channels.spi.AbstractSelector;  
    import java.nio.channels.spi.SelectorProvider;  
      
    // Referenced classes of package sun.nio.ch:  
    //            DatagramChannelImpl, PipeImpl, ServerSocketChannelImpl, SocketChannelImpl  
      
    public abstract class SelectorProviderImpl extends SelectorProvider  
    {  
      
        public SelectorProviderImpl()  
        {  
        }  
        //打开一个报文通道  
        public DatagramChannel openDatagramChannel()  
            throws IOException  
        {  
            return new DatagramChannelImpl(this);  
        }  
        //根据协议,打开一个报文通道  
        public DatagramChannel openDatagramChannel(ProtocolFamily protocolfamily)  
            throws IOException  
        {  
            return new DatagramChannelImpl(this, protocolfamily);  
        }  
         //打开一个管道  
        public Pipe openPipe()  
            throws IOException  
        {  
            return new PipeImpl(this);  
        }  
       //打开一个选择器,待子类扩展  
        public abstract AbstractSelector openSelector()  
            throws IOException;  
       //打开一个监听socket通道  
        public ServerSocketChannel openServerSocketChannel()  
            throws IOException  
        {  
            return new ServerSocketChannelImpl(this);  
        }  
        //打开一个socket通道(连接)  
        public SocketChannel openSocketChannel()  
            throws IOException  
        {  
            return new SocketChannelImpl(this);  
        }  
}  

从上面可以看出open一个ServerSocketChannel实际上返回的是ServerSocketChannelImpl。
下面我们来看ServerSocketChannelImpl的socket地址绑定和连接监听和可选择通道的相关方法实现。
class ServerSocketChannelImpl extends ServerSocketChannel
    implements SelChImpl
{
    private static NativeDispatcher nd = new SocketDispatcher();//Socket分发器
    private final FileDescriptor fd;//文件描述
    private int fdVal;//文件描述的值
    private volatile long thread;//ServerSocket线程本地编号
    private final Object lock;//地址绑定,接受连接同步锁
    private final Object stateLock;//状态锁
    private static final int ST_UNINITIALIZED = -1;//未初始化
    private static final int ST_INUSE = 0;//正在使用中
    private static final int ST_KILLED = 1;//关闭状态
    private int state;//ServerSocket状态
    private SocketAddress localAddress;//绑定地址
    ServerSocket socket;//ServerSocket
    static final boolean $assertionsDisabled = !sun/nio/ch/ServerSocketChannelImpl.desiredAssertionStatus();
    static 
    {
        //加载nio和net资源库,我们在WindowsSelectorImpl相关文章中有讲
        Util.load();
        initIDs();
    }
    private static native void initIDs();
    
    ServerSocketChannelImpl(SelectorProvider selectorprovider)
        throws IOException
    {
        super(selectorprovider);
        thread = 0L;
        lock = new Object();
        stateLock = new Object();
        state = -1;//默认创建是的状态为未初始化
	//获取ServerSocket的文件描述符
        fd = Net.serverSocket(true);
	//获取文件描述的id
        fdVal = IOUtil.fdVal(fd);
        state = 0;
    }
    ServerSocketChannelImpl(SelectorProvider selectorprovider, FileDescriptor filedescriptor, boolean flag)
        throws IOException
    {
        super(selectorprovider);
        thread = 0L;
        lock = new Object();
        stateLock = new Object();
        state = -1;
        fd = filedescriptor;
        fdVal = IOUtil.fdVal(filedescriptor);
        state = 0;
        if(flag)
	     //如果使用本地地址,则获取本地地址
            localAddress = Net.localAddress(filedescriptor);
    }
}

初始化需要关注的是这几点,
1.
//获取ServerSocket的文件描述符
fd = Net.serverSocket(true);

2.
//获取文件描述的id       
fdVal = IOUtil.fdVal(fd);

3.
if(flag)
    //如果使用本地地址,则获取本地地址
    localAddress = Net.localAddress(filedescriptor);

分别来看
1.
//获取ServerSocket的文件描述符
fd = Net.serverSocket(true);

class Net
{
   private static volatile boolean checkedIPv6 = false;
    private static volatile boolean isIPv6Available;
    public static final int SHUT_RD = 0;//关闭读操作
    public static final int SHUT_WR = 1;//关闭写操作
    public static final int SHUT_RDWR = 2;//关闭读写操作
    static 
    {
        //加载nio和net资源库
        Util.load();
        initIDs();
    }
    private static native void initIDs();
    //默认协议
    static final ProtocolFamily UNSPEC = new ProtocolFamily() {
    public String name()
    {
        return "UNSPEC";
    }

    };
    //获取ServerSocket文件描述
    static FileDescriptor serverSocket(boolean flag)
    {
        return IOUtil.newFD(socket0(isIPv6Available(), flag, true));
    }
    private static native int socket0(boolean flag, boolean flag1, boolean flag2);
}

//IOUtil
class IOUtil
{
    static final int IOV_MAX = iovMax();
    static final boolean $assertionsDisabled = !sun/nio/ch/IOUtil.desiredAssertionStatus();
    static 
    {
        Util.load();
    }
    创建文件描述符
    static FileDescriptor newFD(int i)
    {
        FileDescriptor filedescriptor = new FileDescriptor();
        setfdVal(filedescriptor, i);
        return filedescriptor;
    }
}


2.
//获取文件描述的id      
fdVal = IOUtil.fdVal(fd);

//IOUtil
static native int fdVal(FileDescriptor filedescriptor);


3.
if(flag)
    //如果使用本地地址,则获取本地地址
    localAddress = Net.localAddress(filedescriptor);

//Net
static InetSocketAddress localAddress(FileDescriptor filedescriptor)
        throws IOException
{
    //根据local地址和port构造InetSocketAddress
    return new InetSocketAddress(localInetAddress(filedescriptor), localPort(filedescriptor));
}
 private static native int localPort(FileDescriptor filedescriptor)
     throws IOException;

 private static native InetAddress localInetAddress(FileDescriptor filedescriptor)
     throws IOException;

从上面来看,ServerSocketChannelImpl的初始化主要是初始化ServerSocket通道线程thread,地址绑定,接受连接同步锁,默认创建ServerSocketChannelImpl的状态为未初始化,文件描述和文件描述id,如果使用本地地址,则获取本地地址。
来看地址绑定方法
public ServerSocketChannel bind(SocketAddress socketaddress, int i)
        throws IOException
    {
        synchronized(lock)
        {
            if(!isOpen())
	       //如果socket关闭,则抛出ClosedChannelException
                throw new ClosedChannelException();
            if(isBound())
	        //如果已绑定,则抛出AlreadyBoundException
                throw new AlreadyBoundException();
	    //确定inetsocketaddress
            InetSocketAddress inetsocketaddress = socketaddress != null ? Net.checkAddress(socketaddress) : new InetSocketAddress(0);
            SecurityManager securitymanager = System.getSecurityManager();
            if(securitymanager != null)
	        //检查地址端口监听权限
                securitymanager.checkListen(inetsocketaddress.getPort());
	    //绑定前工作
            NetHooks.beforeTcpBind(fd, inetsocketaddress.getAddress(), inetsocketaddress.getPort());
	    //实际地址绑定
            Net.bind(fd, inetsocketaddress.getAddress(), inetsocketaddress.getPort());
	    //开启监听,如果参数i小于1,默认接受50个连接
            Net.listen(fd, i >= 1 ? i : 50);
            synchronized(stateLock)
            {
	        //更新ocalAddress
                localAddress = Net.localAddress(fd);
            }
        }
        return this;
    }

绑定方法中与几点要关注,
1.
if(isBound())
    //如果已绑定,则抛出AlreadyBoundException
    throw new AlreadyBoundException();

 public boolean isBound()
 {
     Object obj = stateLock;//同步stateLock
     JVM INSTR monitorenter ;//进入同步,try
     //地址不为空,则为已绑定
     return localAddress != null;
     Exception exception;//有异常,则抛出
     exception;
     throw exception;
 }

2.
//确定inetsocketaddress
InetSocketAddress inetsocketaddress = socketaddress != null ? Net.checkAddress(socketaddress) : new InetSocketAddress(0);

//Net
static InetSocketAddress checkAddress(SocketAddress socketaddress)
{
    if(socketaddress == null)//地址为空
        throw new NullPointerException();
    if(!(socketaddress instanceof InetSocketAddress))//非InetSocketAddress类型地址
        throw new UnsupportedAddressTypeException();
    InetSocketAddress inetsocketaddress = (InetSocketAddress)socketaddress;
    if(inetsocketaddress.isUnresolved())//地址不可识别
        throw new UnresolvedAddressException();
    InetAddress inetaddress = inetsocketaddress.getAddress();
    //非ip4和ip6地址
    if(!(inetaddress instanceof Inet4Address) && !(inetaddress instanceof Inet6Address))
        throw new IllegalArgumentException("Invalid address type");
    else
        return inetsocketaddress;
}

3.
//绑定前工作
NetHooks.beforeTcpBind(fd, inetsocketaddress.getAddress(), inetsocketaddress.getPort());

//NetHooks
package sun.net;

import java.io.FileDescriptor;
import java.io.IOException;
import java.net.InetAddress;
public final class NetHooks
{
    public NetHooks()
    {
    }
    //待扩展
    public static void beforeTcpBind(FileDescriptor filedescriptor, InetAddress inetaddress, int i)
        throws IOException
    {
    }
    public static void beforeTcpConnect(FileDescriptor filedescriptor, InetAddress inetaddress, int i)
        throws IOException
    {
    }
}

4.
//实际地址绑定
Net.bind(fd, inetsocketaddress.getAddress(), inetsocketaddress.getPort());

//Net
static void bind(FileDescriptor filedescriptor, InetAddress inetaddress, int i)
    throws IOException
{
    bind(UNSPEC, filedescriptor, inetaddress, i);
}
static void bind(ProtocolFamily protocolfamily, FileDescriptor filedescriptor, InetAddress inetaddress, int i)
    throws IOException
{
    boolean flag = isIPv6Available() && protocolfamily != StandardProtocolFamily.INET;
    bind0(flag, filedescriptor, inetaddress, i);
}
private static native void bind0(boolean flag, FileDescriptor filedescriptor, InetAddress inetaddress, int i)
        throws IOException;

5.
//开启监听,s如果参数i小于1,默认接受50个连接
Net.listen(fd, i >= 1 ? i : 50);

//Net
static native void listen(FileDescriptor filedescriptor, int i)
      throws IOException;

从上面可以看出,bind首先检查ServerSocket是否关闭,是否绑定地址,
如果既没有绑定也没关闭,则检查绑定的socketaddress是否正确或合法;
然后通过Net工具类的bind(native)和listen(native),完成实际的
ServerSocket地址绑定和开启监听,如果绑定是开启的参数小于1,则默认接受50个连接。
再来看接受连接方法:
 public SocketChannel accept()
        throws IOException
    {
        Object obj = lock;//同步lock锁
        JVM INSTR monitorenter ;//try
        int i;
        FileDescriptor filedescriptor;
        InetSocketAddress ainetsocketaddress[];
        if(!isOpen())
	    //通道关闭
            throw new ClosedChannelException();
        if(!isBound())
	    //为绑定地址
            throw new NotYetBoundException();
        Object obj1 = null;
        i = 0;
	//接受连接后创建SocketChannelImpl的文件描述
        filedescriptor = new FileDescriptor();
        ainetsocketaddress = new InetSocketAddress[1];
        SocketChannel socketchannel;
        begin();
        if(isOpen())
            break MISSING_BLOCK_LABEL_114;
        socketchannel = null;
        thread = 0L;
        end(i > 0);
        if(!$assertionsDisabled && !IOStatus.check(i))
            throw new AssertionError();
        return socketchannel;
	//获取本地线程数
        thread = NativeThread.current();
        do
	    //接受连接
            i = accept0(fd, filedescriptor, ainetsocketaddress);
        while(i == -3 && isOpen());
        thread = 0L;
        end(i > 0);
        if(!$assertionsDisabled && !IOStatus.check(i))
            throw new AssertionError();
        break MISSING_BLOCK_LABEL_233;
        Exception exception;
        exception;
        thread = 0L;
        end(i > 0);
        if(!$assertionsDisabled && !IOStatus.check(i))
            throw new AssertionError();
        else
            throw exception;
        if(i >= 1) goto _L2; else goto _L1
_L1:
        null;
        obj;
        JVM INSTR monitorexit ;
        return;
_L2:
        SocketChannelImpl socketchannelimpl;
	//接受连接的处理通道socketchannelimpl,默认为阻塞模式
        IOUtil.configureBlocking(filedescriptor, true);
        InetSocketAddress inetsocketaddress = ainetsocketaddress[0];
	//构建SocketChannelImpl,这个具体在SocketChannelImpl再说
        socketchannelimpl = new SocketChannelImpl(provider(), filedescriptor, inetsocketaddress);
        SecurityManager securitymanager = System.getSecurityManager();
        if(securitymanager != null)
            try
            {
	        //检查地址和port权限
                securitymanager.checkAccept(inetsocketaddress.getAddress().getHostAddress(), inetsocketaddress.getPort());
            }
            catch(SecurityException securityexception)
            {
                socketchannelimpl.close();
                throw securityexception;
            }
	//返回socketchannelimpl
        socketchannelimpl;
        obj;
        JVM INSTR monitorexit ;//退出try
        return;
        Exception exception1;//有异常,抛出
        exception1;
        throw exception1;
    }

连接方法中有几点要关注,
1.
//获取本地线程数
 thread = NativeThread.current();

package sun.nio.ch;
class NativeThread
{
    NativeThread()
    {
    }
    static long current()
    {
        return 0L;
    }
    static void signal(long l)
    {
    }
}

2.
do
    //接受连接
     i = accept0(fd, filedescriptor, ainetsocketaddress);
 while(i == -3 && isOpen());

//ServerSocketChannelImpl
 private native int accept0(FileDescriptor filedescriptor, FileDescriptor filedescriptor1, InetSocketAddress ainetsocketaddress[])
        throws IOException;

3.
SocketChannelImpl socketchannelimpl;
//接受连接的处理通道socketchannelimpl,默认为阻塞模式
IOUtil.configureBlocking(filedescriptor, true);
InetSocketAddress inetsocketaddress = ainetsocketaddress[0];
//构建SocketChannelImpl,这个具体在SocketChannelImpl再说
socketchannelimpl = new SocketChannelImpl(provider(), filedescriptor, inetsocketaddress);

//IOUtil
static native void configureBlocking(FileDescriptor filedescriptor, boolean flag)
    throws IOException;

从上面来看,accept方法主要是调用accept0(native)方法接受连接,并根据接受来接
文件描述的地址构造SocketChannelImpl,并返回。
再看ServerSocketChannelImpl的其他方法
//配置阻塞模式
protected void implConfigureBlocking(boolean flag)
     throws IOException
 {
     IOUtil.configureBlocking(fd, flag);
 }

支持的默认配置选项
 public final Set supportedOptions()
    {
        return DefaultOptionsHolder.defaultOptions;
    }

//DefaultOptionsHolder
private static class DefaultOptionsHolder
    {
         static final Set defaultOptions = defaultOptions();
        private static Set defaultOptions()
        {
            HashSet hashset = new HashSet(2);
            hashset.add(StandardSocketOptions.SO_RCVBUF);
            hashset.add(StandardSocketOptions.SO_REUSEADDR);
	    //返回不可修改的HashSet
            return Collections.unmodifiableSet(hashset);
        }
        private DefaultOptionsHolder()
        {
        }
    }

//StandardSocketOptions
//socket接受缓存大小
public static final SocketOption<Integer> SO_RCVBUF =
        new StdSocketOption<Integer>("SO_RCVBUF", Integer.class);
//是否可重用地址
public static final SocketOption<Boolean> SO_REUSEADDR =
        new StdSocketOption<Boolean>("SO_REUSEADDR", Boolean.class);
//StdSocketOption
 private static class StdSocketOption<T> implements SocketOption<T> {
     private final String name;
     private final Class<T> type;
     StdSocketOption(String name, Class<T> type) {
         this.name = name;
         this.type = type;
     }
     @Override public String name() { return name; }
     @Override public Class<T> type() { return type; }
     @Override public String toString() { return name; }
 }

//设置选项的置为obj
public volatile NetworkChannel setOption(SocketOption socketoption, Object obj)
        throws IOException
    {
        return setOption(socketoption, obj);
    }
public ServerSocketChannel setOption(SocketOption socketoption, Object obj)
        throws IOException
    {
        if(socketoption == null)
            throw new NullPointerException();
	//非通道支持选项,则抛出UnsupportedOperationException
        if(!supportedOptions().contains(socketoption))
            throw new UnsupportedOperationException((new StringBuilder()).append("'").append(socketoption).append("' not supported").toString());
        Object obj1 = stateLock;//同步状态lock
        JVM INSTR monitorenter ;//try
        if(!isOpen())
            throw new ClosedChannelException();
        Net.setSocketOption(fd, Net.UNSPEC, socketoption, obj);
        return this;
        Exception exception;//异常,则抛出
        exception;
        throw exception;
    }

//Net
static void setSocketOption(FileDescriptor filedescriptor, ProtocolFamily protocolfamily, SocketOption socketoption, Object obj)
        throws IOException
    {
        if(obj == null)
            throw new IllegalArgumentException("Invalid option value");
        Class class1 = socketoption.type();
	//非整形和布尔型,则抛出断言错误
        if(class1 != java/lang/Integer && class1 != java/lang/Boolean)
            throw new AssertionError("Should not reach here");
        if(socketoption == StandardSocketOptions.SO_RCVBUF || socketoption == StandardSocketOptions.SO_SNDBUF)
        {    //判断接受和发送缓冲区大小
            int i = ((Integer)obj).intValue();
            if(i < 0)
                throw new IllegalArgumentException("Invalid send/receive buffer size");
        }
	//缓冲区有数据,延迟关闭socket的的时间
        if(socketoption == StandardSocketOptions.SO_LINGER)
        {
            int j = ((Integer)obj).intValue();
            if(j < 0)
                obj = Integer.valueOf(-1);
            if(j > 65535)
                obj = Integer.valueOf(65535);
        }
	//UDP单播
        if(socketoption == StandardSocketOptions.IP_TOS)
        {
            int k = ((Integer)obj).intValue();
            if(k < 0 || k > 255)
                throw new IllegalArgumentException("Invalid IP_TOS value");
        }
	//UDP多播
        if(socketoption == StandardSocketOptions.IP_MULTICAST_TTL)
        {
            int l = ((Integer)obj).intValue();
            if(l < 0 || l > 255)
                throw new IllegalArgumentException("Invalid TTL/hop value");
        }
        OptionKey optionkey = SocketOptionRegistry.findOption(socketoption, protocolfamily);
        if(optionkey == null)
            throw new AssertionError("Option not found");
        int i1;
	//转换配置参数值
        if(class1 == java/lang/Integer)
        {
            i1 = ((Integer)obj).intValue();
        } else
        {
            boolean flag = ((Boolean)obj).booleanValue();
            i1 = flag ? 1 : 0;
        }
        boolean flag1 = protocolfamily == UNSPEC;
	//设置文件描述符的值
        setIntOption0(filedescriptor, flag1, optionkey.level(), optionkey.name(), i1);
    }

    private static native void setIntOption0(FileDescriptor filedescriptor, boolean flag, int i, int j, int k)
        throws IOException;


//获取配置选项
 
  public Object getOption(SocketOption socketoption)
        throws IOException
    {
        if(socketoption == null)
            throw new NullPointerException();
	//非通道支持选项,则抛出UnsupportedOperationException
        if(!supportedOptions().contains(socketoption))
            throw new UnsupportedOperationException((new StringBuilder()).append("'").append(socketoption).append("' not supported").toString());
        Object obj = stateLock;//同步状态lock
        JVM INSTR monitorenter ;//try
        if(!isOpen())
            throw new ClosedChannelException();
	//委托给Net
        return Net.getSocketOption(fd, Net.UNSPEC, socketoption);
        Exception exception;//异常,则抛出
        exception;
        throw exception;
    }

//Net
 static Object getSocketOption(FileDescriptor filedescriptor, ProtocolFamily protocolfamily, SocketOption socketoption)
        throws IOException
    {
        Class class1 = socketoption.type();
	//非整形和布尔型,则抛出断言错误
        if(class1 != java/lang/Integer && class1 != java/lang/Boolean)
            throw new AssertionError("Should not reach here");
        OptionKey optionkey = SocketOptionRegistry.findOption(socketoption, protocolfamily);
        if(optionkey == null)
            throw new AssertionError("Option not found");
        boolean flag = protocolfamily == UNSPEC;
	//获取文件描述的选项配置
        int i = getIntOption0(filedescriptor, flag, optionkey.level(), optionkey.name());
        if(class1 == java/lang/Integer)
            return Integer.valueOf(i);
        else
            return i != 0 ? Boolean.TRUE : Boolean.FALSE;
    }
    private static native int getIntOption0(FileDescriptor filedescriptor, boolean flag, int i, int j)
        throws IOException;

再来看ServerSocketChannelImpl的其他方法
//获取绑定地址
public SocketAddress localAddress()
    {
        Object obj = stateLock;//同步状态锁
        JVM INSTR monitorenter ;//try
        return localAddress;
        Exception exception;//有异常,则抛出
        exception;
        throw exception;
    }
 //获取Socket
 public ServerSocket socket()
    {
        Object obj = stateLock;//同步状态锁
        JVM INSTR monitorenter ;//try
        if(socket == null)
	    //创建ServerSocket适配器
            socket = ServerSocketAdaptor.create(this);
        return socket;
        Exception exception;//有异常,则抛出
        exception;
        throw exception;
    }

//ServerSocketAdaptor,可简单理解为ServerSocketChannelImpl的代理
public class ServerSocketAdaptor extends ServerSocket
{
    private final ServerSocketChannelImpl ssc;
    private volatile int timeout;
    static final boolean $assertionsDisabled = !sun/nio/ch/ServerSocketAdaptor.desiredAssertionStatus();
    private ServerSocketAdaptor(ServerSocketChannelImpl serversocketchannelimpl)
        throws IOException
    {
        timeout = 0;
        ssc = serversocketchannelimpl;
    }
    //根据ServerSocketChannelImpl创建ServerSocketAdaptor
    public static ServerSocket create(ServerSocketChannelImpl serversocketchannelimpl)
    {
        return new ServerSocketAdaptor(serversocketchannelimpl);
        IOException ioexception;
        ioexception;
        throw new Error(ioexception);
    }
    //绑定地址
     public void bind(SocketAddress socketaddress, int i)
        throws IOException
    {
        if(socketaddress == null)
            socketaddress = new InetSocketAddress(0);
        try
        {
            ssc.bind(socketaddress, i);
        }
        catch(Exception exception)
        {
            Net.translateException(exception);
        }
    }
}




在往下看之前,先看一下ServerSocketChannelImpl的socket的分发器
private static NativeDispatcher nd = new SocketDispatcher();//Socket分发器

class SocketDispatcher extends NativeDispatcher
{

    SocketDispatcher()
    {
    }
      static 
    {
        //加载nio,net资源库
        Util.load();
    }
    //读操作
    int read(FileDescriptor filedescriptor, long l, int i)
        throws IOException
    {
        return read0(filedescriptor, l, i);
    }
     static native int read0(FileDescriptor filedescriptor, long l, int i)
        throws IOException;
    long readv(FileDescriptor filedescriptor, long l, int i)
        throws IOException
    {
        return readv0(filedescriptor, l, i);
    }
     static native long readv0(FileDescriptor filedescriptor, long l, int i)
        throws IOException;
   //写操作
    int write(FileDescriptor filedescriptor, long l, int i)
        throws IOException
    {
        return write0(filedescriptor, l, i);
    }
    static native int write0(FileDescriptor filedescriptor, long l, int i)
        throws IOException;
    long writev(FileDescriptor filedescriptor, long l, int i)
        throws IOException
    {
        return writev0(filedescriptor, l, i);
    }
      static native long writev0(FileDescriptor filedescriptor, long l, int i)
        throws IOException;
    //预关闭文件描述符
    void preClose(FileDescriptor filedescriptor)
        throws IOException
    {
        preClose0(filedescriptor);
    }
    static native void preClose0(FileDescriptor filedescriptor)
        throws IOException;
    //关闭文件描述
    void close(FileDescriptor filedescriptor)
        throws IOException
    {
        close0(filedescriptor);
    }
    static native void close0(FileDescriptor filedescriptor)
        throws IOException;
}

再来看ServerSocketChannelImpl的其他方法
//实际关闭选择通道方法
protected void implCloseSelectableChannel()
        throws IOException
    {
        synchronized(stateLock)//通不状态锁
        {
            if(state != 1)
	        //如果状态没关闭,则本地Socket预先关闭
                nd.preClose(fd);
            long l = thread;
            if(l != 0L)
	        //本地线程不为null,则通知关闭
                NativeThread.signal(l);
            if(!isRegistered())
	        //如果通道反注册,则kill
                kill();
        }
    }
//关闭文件描述
    public void kill()
        throws IOException
    {
label0:
        {
            synchronized(stateLock)
            {
                if(state != 1)
                    break label0;
            }
            return;
        }
        if(state != -1)
            break MISSING_BLOCK_LABEL_34;
        state = 1;//置通道状态为关闭
        obj;
        JVM INSTR monitorexit ;
        return;
	//如果断言开启,如果通道打开或已注册,抛出断言错误
        if(!$assertionsDisabled && (isOpen() || isRegistered()))
            throw new AssertionError();
	//本地分发器关闭文件描述
        nd.close(fd);
        state = 1;
        obj;
        JVM INSTR monitorexit ;//退出同步
          goto _L1
        exception;
        throw exception;
_L1:
    }
 //获取文件描述
     public FileDescriptor getFD()
    {
        return fd;
    }
 //获取文件描述值
    public int getFDVal()
    {
        return fdVal;
    }
 //设置兴趣操作事件
 public void translateAndSetInterestOps(int i, SelectionKeyImpl selectionkeyimpl)
    {
        int j = 0;
        if((i & 16) != 0)
            j |= 1;
        selectionkeyimpl.selector.putEventOps(selectionkeyimpl, j);
    }


//设置就绪操作事件集
 public boolean translateAndSetReadyOps(int i, SelectionKeyImpl selectionkeyimpl)
 {
     return translateReadyOps(i, 0, selectionkeyimpl);
 }
//更新就绪操作事件集
  public boolean translateAndUpdateReadyOps(int i, SelectionKeyImpl selectionkeyimpl)
 {
     return translateReadyOps(i, selectionkeyimpl.nioReadyOps(), selectionkeyimpl);
 }
 //根据就绪事件集当前状态j,设置就绪事件为i
  public boolean translateReadyOps(int i, int j, SelectionKeyImpl selectionkeyimpl)
    {
        int k = selectionkeyimpl.nioInterestOps();//兴趣事件集
        int l = selectionkeyimpl.nioReadyOps();//就绪事件集
        int i1 = j;
	//就绪事件为读1写4连接8,接受连接事件16,不是这四种事件,则返回false
        if((i & 32) != 0)
            return false;
	//8+16,接受连接,并建立连接
        if((i & 24) != 0)
        {
            i1 = k;
            selectionkeyimpl.nioReadyOps(i1);
            return (i1 & ~l) != 0;
        }
        if((i & 1) != 0 && (k & 16) != 0)
            i1 |= 16;//接受连接
        selectionkeyimpl.nioReadyOps(i1);
        return (i1 & ~l) != 0;
    }



总结:

ServerSocketChannelImpl的初始化主要是初始化ServerSocket通道线程thread,地址绑定,接受连接同步锁,默认创建ServerSocketChannelImpl的状态为未初始化,文件描述和文件描述id,如果使用本地地址,则获取本地地址。bind首先检查ServerSocket是否关闭,是否绑定地址,如果既没有绑定也没关闭,则检查绑定的socketaddress是否正确或合法;然后通过Net工具类的bind(native)和listen(native),完成实际的ServerSocket地址绑定和开启监听,如果绑定是开启的参数小于1,则默认接受50个连接。accept方法主要是调用accept0(native)方法接受连接,并根据接受来接
文件描述的地址构造SocketChannelImpl,并返回。

附:
//NativeDispatcher
package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;

abstract class NativeDispatcher
{

    NativeDispatcher()
    {
    }
    abstract void close(FileDescriptor filedescriptor)
        throws IOException;

    void preClose(FileDescriptor filedescriptor)
        throws IOException
    {
    }
    abstract int read(FileDescriptor filedescriptor, long l, int i)
        throws IOException;

    int pread(FileDescriptor filedescriptor, long l, int i, long l1, Object obj)
        throws IOException
    {
        throw new IOException("Operation Unsupported");
    }
    abstract long readv(FileDescriptor filedescriptor, long l, int i)
        throws IOException;

    abstract int write(FileDescriptor filedescriptor, long l, int i)
        throws IOException;
    int pwrite(FileDescriptor filedescriptor, long l, int i, long l1, Object obj)
        throws IOException
    {
        throw new IOException("Operation Unsupported");
    }
    abstract long writev(FileDescriptor filedescriptor, long l, int i)
        throws IOException;
}
  • 大小: 49.6 KB
0
1
分享到:
评论

相关推荐

    交互修改.rp

    交互修改

    14230-2.pdf

    ISO14230-2标准文档,定义了K线通讯方式和数据格式,对于汽车诊断非常有用

    基于python的求职招聘网站 python+django+vue搭建的求职招聘管理系统 - 毕业设计 - 课程设计.zip

    学习作者过程中,遇到问题可以咨询解决方案前台地址http://job.gitapp.cn后台地址http://job.gitapp.cn/admin后台管理帐号用户名admin123 密码admin123功能介绍平台采用B/S结构,前端采用主流的Python语言进行开发,前端采用主流的V​​ue.js进行开发。整个平台包括前台和后台两个部分。前台功能包括首页、岗位详情页、简历中心、用户设置模块。后台功能包括总览、岗位管理、公司管理、分类管理、标签管理、评论管理、用户管理、运营管理、日志管理、系统信息模块。代码结构服务器目录编号web目录是前端代码部署运行执行步骤(1)安装python 3.8(2) 安装依赖。进入server目录下,执行 pip install -r requests.txt(3)安装mysql 5.7数据库,并创建数据库,创建SQL如下CREATE DATABASE IF NOT EXISTS xxx DEFAULT CHARSET utf8 COLLATE utf8_general_ci(4)恢复

    4602-职业规划设计书PPT护理.pptx

    4602-职业规划设计书PPT护理

    非常好的SqlServer查询性能优化教程资料100%好用.zip

    非常好的SqlServer查询性能优化教程资料100%好用.zip

    基于Springboot+Vue+Python深度神经网络学习算法水质管理预测系统设计毕业源码案例设计.zip

    基于Springboot+Vue+Python深度神经网络学习算法水质管理预测系统设计毕业源码案例设计Springboot_Vue_Python_水质管理_预测基于Springboot+Vue+Python深度神经网络学习算法水质管理预测系统设计毕业源码案例设计程序开发软件Eclipse/Idea + WebStorm/VsCode + Pycharm 数据库mysql 开发技术Springboot + Vue + Python 这个是一个水质管理和预报系统,它是一个全栈Web应用程序,使用机器学习和深度神经网络算法来预测未来的水质。系统一共有2个身份包括管理员和用户。管理员登录后可以查询最新水质检测数据,也可以上报新的水质数据,可以查询管理历史水质数据,查询历史水质趋势图,训练自己的模型参数,选择一个算法模型结果预测下个月的水质信息,管理所有的用户信息用户登录后比管理员就少了个用户管理功能。管理员账号密码 admin/123 用户账号密码user1/123

    微信小程序云开发毕业设计「单词天天斗」,好友,匹配,人机对战,单词本科毕设打字稿原创微信小程序.zip

    单词天天斗 (毕业设计/实战小程序/微信小程序完整项目)介绍该项目基于「微信小程序」原生框架和「微信小程序云开发」实现单词对战类小程序,支持好友对战、随机匹配、人机对战透明不同模式的「对战模式」另外提供「每日对战」词汇」、「生词本」、「排行榜」、「设置」等功能,实现完整的业务闭环。单词库包含从小学、初中、高中、四六级、考研、雅思等常需掌握的词汇,支持自定义词库,支持自定义拓展无限本单词书。技术栈主要为微信小程序、云开发、TypeScript等,从头搭建项目,基于git管理代码版本,使用eslint作为代码格式校验,并对页面进行组件化拆分,前端和云函数均采用TypeScript。实践小程序能力,如用户信息获取、用户登录、全局状态管理、路由、wxs、npm包、播放音频、回复、转发分享、动画、云数据库等。项目提供完整设计稿,项目演示可查看微信小程序「单词天天斗」,扫码体验 ↓这些人毕设参考项目文档齐全、题目合适、技术广度大、业务闭环,包含项目解析文档和教程,这是一个非常适合作为毕设学习的小程序项目。无化部署运营无论你是想通过小程序现变,还是想给自己的「英语课程教材」

    利用ReST与ReAct自改进多步骤推理的大规模语言模型代理

    内容概要:本文提出了结合强化自我训练(ReST)和响应动作链路(ReAct)的方法来构建并改善大规模语言模型代理的性能,尤其是在需要多步骤推理以解决复杂自然语言查询的任务上。文中定义了一个能够在外部工具/ API /环境交互中表现出色的代理,并提出了一种通过迭代训练以前的轨迹来进行连续自我提升和精炼的技术路径。 适合人群:对大型语言模型研究及应用有兴趣的研究人员和工程师。 使用场景及目标:本方法主要适用于处理需要多个信息检索步骤才能完成的问题解决任务,如基于复杂开放性问答系统的发展。具体目标是在减少所需参数量的前提下提高此类系统的准确性、鲁棒性和效率。 其他说明:作者展示了仅经过两轮迭代优化,即可以从一个大的预训练模型蒸馏出性能相当但大小减少两个数量级的小型化模型。此外,在整个过程中没有使用人类标记的数据进行直接监督。

    毕业设计Android,一款水果健康百科app.zip

    毕业设计Android,一款水果健康百科app斯戈利毕业设计Android,一款水果健康百科app

    移动互联网发展和岗位分析.pptx

    移动互联网发展和岗位分析.pptx

    数控加工程序设计.pptx

    数控加工程序设计.pptx

    毕业设计基于STM32的智能停车场设计.zip

    毕业设计基于STM32的智能停车场设计基于STM32的智能停车场设计项目介绍该项目为毕业设计。基于STM32F1平台的智能停车场,板卡划分为主板、控制台指示板及场内红外检测板,支持短信定时报告停车场状态与远程控制、进出场自动电梯停车杆并播报欢迎消息、检测车位和环境温湿度并在屏幕实时显示状态。目前阶段正在进行电路验证设计与打样阶段。预计2月上旬至中旬完成电路设计并进入编码阶段。目前功能概述车辆进场与退场时,语音播报相应的欢迎语句并自动升起停车杆。待车辆完全驶入停车场后,自动降下停车杆。通过红外方式检测车位停车状态,并在门口控制台和相应车位显示停车状态。屏幕显示当前可用车票和当前温湿度每1小时通过短信报告目前停车场车位情况、1小时内车辆进出数量。短信下发控制指令。后续阶段功能车辆停车计费功能。冲卡检测并自动报警功能。加入实时时钟,通过短信安排时间。用户使用场景功能列表模块 功能 商品分类STM32F103VET6 微型系统板 毕业设计使用的开发板 单片机F103VESIM800L模块 支持GPRS短信收发的功能 12864液晶屏

    基于SpringBoot+Vue.js的轻小说在线阅读网站前后端分离全部资料+详细文档.zip

    【资源说明】 基于SpringBoot+Vue.js的轻小说在线阅读网站前后端分离全部资料+详细文档.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

    “腾达”游戏分享网站的设计与实现_97c7a2s2.zip

    “腾达”游戏分享网站的设计与实现_97c7a2s2

    大数据与会计 (9).docx

    大数据与会计 (9)

    数学建模matlabppt课件市公开课一等奖百校联赛特等奖课件.pptx

    数学建模matlabppt课件市公开课一等奖百校联赛特等奖课件.pptx

    城市轨道交通通信信号技术_.docx

    城市轨道交通通信信号技术_

    【毕业设计+开题答辩】-基于JAVA_JSP电子书下载系统-【源代码+截图+数据库+论文+视频讲解】

    本文中的项目资源均整理自互联网,若侵犯了您的权益,请及时联系博主,博主会及时处理。 项目资源中使用的技术和系统用处不一定准确和全面,我只是大致的浏览了一下,具体使用技术建议参考代码和视频讲解。 资源中的各内容不一定每一个都非常的完美,可能会有少许错误,建议多看几个,选其中一个自己觉得不错的,用来做毕设或者开题等等。 资源中所列论文可以参考,但是不建议且强烈不建议直接照搬照抄,因为毕竟要查重,避免引起不必要的麻烦。

    压力表计算机软件及应用it计算机专业资料.pptx

    压力表计算机软件及应用it计算机专业资料.pptx

    钢材器材破损铁锈检测69-YOLO(v5至v9)、COCO、CreateML、Darknet、Paligemma、TFRecord、VOC数据集合集.rar

    钢材器材破损铁锈检测69-YOLO(v5至v9)、COCO、CreateML、Darknet、Paligemma、TFRecord、VOC数据集合集.rar钢重用-V4 2024-03-27 5:01 PM ============================= *与您的团队在计算机视觉项目上合作 *收集和组织图像 *了解和搜索非结构化图像数据 *注释,创建数据集 *导出,训练和部署计算机视觉模型 *使用主动学习随着时间的推移改善数据集 对于最先进的计算机视觉培训笔记本,您可以与此数据集一起使用 该数据集包括1094张图像。 钢元素以可可格式注释。 将以下预处理应用于每个图像: *像素数据的自动取向(带有Exif-Arientation剥离) *调整大小为416x416(拉伸) 应用以下扩展来创建每个源图像的3个版本: *水平翻转的50%概率 *以下90度旋转之一的同等概率:无,顺时针,逆时针方向 * -15%至+15%之间的随机BRIGTHNESS调整 * 0到0.8像素之间的随机高斯模糊

Global site tag (gtag.js) - Google Analytics