- 浏览: 986468 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
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方法开始:
看到这个方法是不是很熟悉,我们在SelectorProvider定义这篇文章中,有讲过SelectorProvider.provider()的加载SelectorProvider的实例过程:
我们直接贴过来:
//SelectorProvider
来看默认的DefaultSelectorProvider
//DefaultSelectorProvider
再来看WindowsSelectorProvider
//WindowsSelectorProvider
再来看SelectorProviderImpl
//SelectorProviderImpl
从上面可以看出open一个ServerSocketChannel实际上返回的是ServerSocketChannelImpl。
下面我们来看ServerSocketChannelImpl的socket地址绑定和连接监听和可选择通道的相关方法实现。
初始化需要关注的是这几点,
1.
//获取ServerSocket的文件描述符
2.
3.
分别来看
1.
//获取ServerSocket的文件描述符
//IOUtil
2.
//获取文件描述的id
//IOUtil
3.
//Net
从上面来看,ServerSocketChannelImpl的初始化主要是初始化ServerSocket通道线程thread,地址绑定,接受连接同步锁,默认创建ServerSocketChannelImpl的状态为未初始化,文件描述和文件描述id,如果使用本地地址,则获取本地地址。
来看地址绑定方法
绑定方法中与几点要关注,
1.
2.
//确定inetsocketaddress
//Net
3.
//绑定前工作
//NetHooks
4.
//实际地址绑定
//Net
5.
//开启监听,s如果参数i小于1,默认接受50个连接
//Net
从上面可以看出,bind首先检查ServerSocket是否关闭,是否绑定地址,
如果既没有绑定也没关闭,则检查绑定的socketaddress是否正确或合法;
然后通过Net工具类的bind(native)和listen(native),完成实际的
ServerSocket地址绑定和开启监听,如果绑定是开启的参数小于1,则默认接受50个连接。
再来看接受连接方法:
连接方法中有几点要关注,
1.
//获取本地线程数
2.
//ServerSocketChannelImpl
3.
//IOUtil
从上面来看,accept方法主要是调用accept0(native)方法接受连接,并根据接受来接
文件描述的地址构造SocketChannelImpl,并返回。
再看ServerSocketChannelImpl的其他方法
//配置阻塞模式
支持的默认配置选项
//DefaultOptionsHolder
//StandardSocketOptions
//设置选项的置为obj
//Net
//获取配置选项
//Net
再来看ServerSocketChannelImpl的其他方法
//ServerSocketAdaptor,可简单理解为ServerSocketChannelImpl的代理
在往下看之前,先看一下ServerSocketChannelImpl的socket的分发器
再来看ServerSocketChannelImpl的其他方法
总结:
ServerSocketChannelImpl的初始化主要是初始化ServerSocket通道线程thread,地址绑定,接受连接同步锁,默认创建ServerSocketChannelImpl的状态为未初始化,文件描述和文件描述id,如果使用本地地址,则获取本地地址。bind首先检查ServerSocket是否关闭,是否绑定地址,如果既没有绑定也没关闭,则检查绑定的socketaddress是否正确或合法;然后通过Net工具类的bind(native)和listen(native),完成实际的ServerSocket地址绑定和开启监听,如果绑定是开启的参数小于1,则默认接受50个连接。accept方法主要是调用accept0(native)方法接受连接,并根据接受来接
文件描述的地址构造SocketChannelImpl,并返回。
附:
//NativeDispatcher
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; }
发表评论
-
文件通道解析二(文件锁,关闭通道)
2017-05-16 23:17 1080文件通道解析一(读写操作,通道数据传输等):http://do ... -
文件通道解析一(读写操作,通道数据传输等)
2017-05-16 10:04 1174Reference定义(PhantomRefere ... -
文件通道创建方式综述
2017-05-15 17:39 1081Reference定义(PhantomReference,Cl ... -
文件读写方式简单综述后续(文件,流构造)
2017-05-14 23:04 1499Java Socket通信实例:http://donald-d ... -
文件读写方式简单综述
2017-05-14 11:13 1144Java Socket通信实例:http://donald-d ... -
FileChanne定义
2017-05-12 23:28 952文件读写方式简单综述:http://donald-draper ... -
SeekableByteChannel接口定义
2017-05-11 08:43 1249ByteChannel,分散聚集通道接口的定义(SocketC ... -
FileChannel示例
2017-05-11 08:37 1006前面我们看过socket通道,datagram通道,以管道Pi ... -
PipeImpl解析
2017-05-11 08:41 945ServerSocketChannel定义:http://do ... -
Pipe定义
2017-05-10 09:07 920Channel接口定义:http://donald-drape ... -
NIO-Pipe示例
2017-05-10 08:47 917PipeImpl解析:http://donald-draper ... -
DatagramChannelImpl 解析四(地址绑定,关闭通道等)
2017-05-10 08:27 796DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析三(多播)
2017-05-10 08:20 1937DatagramChannelImpl 解析一(初始化):ht ... -
NIO-UDP实例
2017-05-09 12:32 1596DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析二(报文发送与接收)
2017-05-09 09:03 1420DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析一(初始化)
2017-05-08 21:52 1425Channel接口定义:http://donald-drape ... -
MembershipKeyImpl 简介
2017-05-08 09:11 938MembershipKey定义:http://donald-d ... -
DatagramChannel定义
2017-05-07 23:13 1238Channel接口定义:http://donald-drape ... -
MulticastChanne接口定义
2017-05-07 13:45 1152NetworkChannel接口定义:ht ... -
MembershipKey定义
2017-05-06 16:20 933package java.nio.channels; i ...
相关推荐
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
内容概要:本文介绍了一种基于周期移位图卷积(CS-ViG)的新型框架——CS-ViG-UNet用于红外小弱目标检测的方法,它采用了图像块为节点构建的视觉图神经网络来增强对小弱目标识别的能力。研究提出了周期移位稀疏图注意力机制,以及结合了CNN与U形架构的CS-ViG模块,实现了对小弱目标的有效捕获,并在公共数据集Sirst-Aug和IRSTD-1K上达到了先进的性能。在硬件条件如RTX3090加速下,模型能够高效地进行大批量的实时检测任务。 适合人群:从事计算机视觉、特别是小目标检测领域的科研人员和技术开发者。 使用场景及目标:应用于复杂背景下,需要快速精确定位并分离出小弱目标的任务场合。适用于军事、航空航天等高端应用场景,以及民用安防监控设备等需要可靠小目标检测能力的需求。 其他说明:文中提供的链接可以访问更多的项目资料和技术支持页面。此外,在实际测试环境下展示了该方法与其他现有算法相比较的优越性和创新点。同时指出了当前仍存在的限制,比如多物体场景下的误检率以及高亮背景干扰等问题,并给出了改进方向。
两个微信体育课程预订小程序-Fitnessw_xApp
风储调频,储能调频,保证真实,模型如图,保证正常使用
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
并离网逆变器仿真模型 逆变器PQ控制,Vf控制,无功能量发生器SVG,有源电力滤波器APF仿真模型
一种磁盘分区恢复软件,可以从损坏的磁盘映像hand_disk中恢复可能的分区表
计算光波导的电磁模式matlab代码.rar
了解 MATLAB 图像处理的基础知识MATLAB代码.rar
labview源码参考示例,可供参考学习使用
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
labview源码参考示例,可供参考学习使用
内容概要:本文提出了一种新的深度学习架构——HCF-Net(Hierarchical Context Fusion Network),旨在提升红外图像中小目标物体的检测精度和鲁棒性。HCF-Net采用了多尺度特征提取、平行补丁注意力模块(PPA)、维度感知选择性集成模块(DASI)以及多扩张通道细化器(MDCR),有效解决了由于红外图像低对比度及背景复杂所导致的小目标检测困难的问题。该研究对SIRST数据集进行了广泛实验评估,表明HCF-Net性能优于现有主流传统和深网方法。HCF-Net通过优化下采样过程中的特征表示与细节捕捉,大幅提高了对微小目标位置识别及形状边界描写的准确性。此外,研究团队还在论文中探讨了相关领域的最新进展和其他基于卷积神经网络的技术。 适合人群:对于计算机视觉尤其是遥感成像与自动目标识别有浓厚兴趣的研究人员和技术爱好者。同时适用于从事国家安全、军事侦察、灾害监测等领域工作的专业人士。 使用场景及目标:应用于各种需要精确探测小型目标物的应用场合,比如海上搜索救援行动、消防监控、边境安防巡逻、天文观测系统等。其目的是提高这些应用场景中设备的工作效率和服务质量。 其他说明:文中还介绍了大量关于红外线成像特性的基础知识,并详细阐述了几种传统的滤波器和机器学习算法用于解决这一任务时面临的局限性;强调了深度学习相对于传统方法所具有的明显优势。
STM32驱动lcd1602显示adc采集电压显示程序源码。 主控芯片采用stm32f103,包括程序源码和protues仿真protues版本8.8. 需要做AD转的不要错过。 程序源码注释详细,非常适合单片机开发的人员。
微信小程序彩票页面_厚江
labview源码参考示例,可供参考学习使用
单相逆变器仿真模型 电压电流双闭环 双闭环PI控制 LC滤波 SPWM调制 输出交流电压220V 50Hz 图2为模型输出电压电流 功率波形 Matlab Simulink
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。