- 浏览: 986404 次
文章分类
- 全部博客 (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 951文件读写方式简单综述:http://donald-draper ... -
SeekableByteChannel接口定义
2017-05-11 08:43 1249ByteChannel,分散聚集通道接口的定义(SocketC ... -
FileChannel示例
2017-05-11 08:37 1005前面我们看过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 936MembershipKey定义: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 932package java.nio.channels; i ...
相关推荐
【PHP入门】 PHP(Hypertext Preprocessor)是一种广泛使用的开源服务器端脚本语言,尤其适用于Web开发,能够嵌入HTML中。本篇笔记基于韩顺平老师的讲解,全面覆盖了从基础到精通的PHP知识体系。 1. **HTML基础** HTML,即超文本标记语言,用于创建网页内容。它包括各种标签来定义网页结构,如`<html>`、`<head>`、`<body>`等。HTML与CSS结合使用,可以实现页面样式控制。HTML5作为最新版本,引入了更多增强功能,如离线存储、拖放功能和媒体元素等。运行HTML有两种方式:本地运行(直接通过浏览器打开文件)和远程访问(通过HTTP协议在服务器上运行)。 2. **动态网页技术** 动态网页能够根据用户输入或服务器状态变化实时更新内容。PHP作为动态网页开发的重要技术之一,具有跨平台、安全性高、效率好、成本低、易于学习和丰富的开源社区支持等优点。PHP可以连接多种数据库,如MySQL,并在PHP4、PHP5和PHP6(及后续版本)中逐。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。
花生好坏缺陷识别数据集,7262张图片,支持yolov7格式的标注,识别准确率在95.7% 两种标签: Good,Bad 花生好坏缺陷识别数据集,7262张图片,支持yolo,coco json,pasical voc xml格式的标注,识别准确率在95.7% 详情查看地址:https://backend.blog.csdn.net/article/details/144983881
总务科(基建办)2024年工作总结.doc
该项目包含完整的前后端代码、数据库脚本和相关工具,简单部署即可运行。功能完善、界面美观、操作简单,具有很高的实际应用价值,非常适合作为Java毕业设计或Java课程设计使用。 所有项目均经过严格调试,确保可运行!下载后即可快速部署和使用。 1 适用场景: 毕业设计 期末大作业 课程设计 2 项目特点: 代码完整:详细代码注释,适合新手学习和使用 功能强大:涵盖常见的核心功能,满足大部分课程设计需求 部署简单:有基础的人,只需按照教程操作,轻松完成本地或服务器部署 高质量代码:经过严格测试,确保无错误,稳定运行 3 技术栈和工具 前端:HTML + Vue.js 后端框架:Spring Boot 开发环境:IntelliJ IDEA 数据库:MySQL(建议使用 5.7 版本,更稳定) 数据库可视化工具:Navicat 部署环境:Tomcat(推荐 7.x 或 8.x 版本),Maven
广东省高清卫星地图全图
本文聚焦智能聊天机器人于电商客服领域的应用,开篇点明研究背景,剖析电商发展促使客服需求暴增,传统客服乏力,智能机器人应运而生。接着详述电商客服发展脉络、现存痛点,如高峰拥堵、知识滞后、服务同质化等。核心技术涵盖自然语言处理、机器学习、知识图谱,系统采用微服务架构,各模块分工协作。开发流程包括精细调研、多元数据采集、模型选型调优等。创新应用体现于售前精准导购、沉浸式营销,售中订单跟踪、答疑,售后问题处理与回访。经量化指标与用户调研评估成效显著,虽有挑战,但未来借助新技术有望重塑电商服务生态,助力企业与消费者双赢。
该项目包含完整的前后端代码、数据库脚本和相关工具,简单部署即可运行。功能完善、界面美观、操作简单,具有很高的实际应用价值,非常适合作为Java毕业设计或Java课程设计使用。 所有项目均经过严格调试,确保可运行!下载后即可快速部署和使用。 1 适用场景: 毕业设计 期末大作业 课程设计 2 项目特点: 代码完整:详细代码注释,适合新手学习和使用 功能强大:涵盖常见的核心功能,满足大部分课程设计需求 部署简单:有基础的人,只需按照教程操作,轻松完成本地或服务器部署 高质量代码:经过严格测试,确保无错误,稳定运行 3 技术栈和工具 前端:HTML + Vue.js 后端框架:Spring Boot 开发环境:IntelliJ IDEA 数据库:MySQL(建议使用 5.7 版本,更稳定) 数据库可视化工具:Navicat 部署环境:Tomcat(推荐 7.x 或 8.x 版本),Maven
eap2025010741566905-1-1.pdf
双馈风机MATLAB simulink模型 多个模型打包发送
给小孩找的,看着还不错,分享出来~
该项目包含完整的前后端代码、数据库脚本和相关工具,简单部署即可运行。功能完善、界面美观、操作简单,具有很高的实际应用价值,非常适合作为Java毕业设计或Java课程设计使用。 所有项目均经过严格调试,确保可运行!下载后即可快速部署和使用。 1 适用场景: 毕业设计 期末大作业 课程设计 2 项目特点: 代码完整:详细代码注释,适合新手学习和使用 功能强大:涵盖常见的核心功能,满足大部分课程设计需求 部署简单:有基础的人,只需按照教程操作,轻松完成本地或服务器部署 高质量代码:经过严格测试,确保无错误,稳定运行 3 技术栈和工具 前端:HTML + Vue.js 后端框架:Spring Boot 开发环境:IntelliJ IDEA 数据库:MySQL(建议使用 5.7 版本,更稳定) 数据库可视化工具:Navicat 部署环境:Tomcat(推荐 7.x 或 8.x 版本),Maven
bcolz-1.2.1-cp38-cp38-win-amd64.whl.rar
内容概要:本文详尽阐述了自动驾驶技术中的域控制单元(DCU)及其重要性。首先介绍了ADAS(高级驾驶辅助系统)和AD(自动驾驶)的区别和发展现状。接着讨论了域控制单元作为高级ECU,在自动驾驶系统中扮演的重要角色,包括高性能计算、高效的数据处理能力和与其他子系统的紧密配合。文中详细解释了DCU的构成元素——收发器、SoC、MCU和电源管理等模块的工作原理和技术细节,同时也探讨了市场趋势和技术发展趋势,如高集成度、智能化、低功耗等方面。最后展望了DCU在未来域集中式EE架构下的广阔应用前景。 适用人群:从事汽车工程、自动驾驶技术和嵌入式软件开发的专业技术人员,以及对此领域感兴趣的科研工作者。 使用场景及目标:①帮助开发者深入了解自动驾驶系统组成尤其是DCU的设计理念和技术特征;②指导相关领域的研究者把握当前行业发展动态和技术前沿。 其他说明:本文不仅深入浅出地讲解了专业知识,而且引用了一些作者个人感悟的文字,增加了可读性和启发性。
内容概要:文章主要介绍了Java和Python这两种流行的编程语言之间的区别和联系。首先详细讲述了Java的基本特性,包括跨平台性、面向对象编程、类型安全、自动化内存管理和多线程支持等特点,并概述了其在企业级开发中的广泛应用。接着深入探讨了Python的特点,指出它的简明语法、灵活性以及丰富的生态体系,特别提到了其在数据分析、人工智能等前沿领域的优势。文中还比较了两者的应用场景和技术实现方式的不同之处。最后为初学者提出了基于个人职业发展目标来选择编程语言的建议。 适合人群:对编程有兴趣的学生、编程新手以及想要转换编程方向的技术人员。 使用场景及目标:有助于读者理解两种编程语言各自的优劣,便于在实际工作中或者个人兴趣发展中做出明智的选择。 其他说明:通过对比讲解,不仅展示了两种编程语言的共同点,还强调了它们各自独特的优势所在。这有助于加深读者对其本质特征的认识,从而更好地应对不同类型的编程任务和挑战。
Java 飞机订票系统实训报告,有数据库
easy-interceptor修改请求头和响应头.zip
Python身份证识别系统源码(精准度非常高).zip,个人大三大作业设计项目、经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以亲自搞定,主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。 Python身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系
Matlab领域上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作
功能:利用深度学习模型(LSTM 网络)对电商用户咨询文本进行意图分类,相比简单规则匹配,能处理更复杂、语义模糊的文本,精准识别用户需求。 技术要点:使用 TensorFlow 构建 LSTM 模型,包括文本预处理将文本数字化,Embedding 层将数字映射为向量,LSTM 层捕捉序列特征,Dense 层输出分类结果,通过训练优化模型参数,实现准确意图识别。
国产银河麒麟V10和统信系统(linux)没有root用户的解决办法。如何在没有root用户的情况下,开通和启用root用户