java.nio.channels.SocketChannel
SocketChannel功能
从SocketChannel类的注释可以看到以下几点: 1.socket channel是面向流的连接socket的一个可选通道。 2.通过调用#open()方法创建socket channel。根据不同参数,为不同的socket创建channel。 3.socket channel支持非阻塞连接。创建套接字通道,和建立到远程套接字的链接的过程可以通过#connect方法初始化,再由#finishConnect方法完成。 4.socket channel支持异步关闭,类似于在Channel类中指定的异步关闭操作。 5.socket channel对于多个并发线程来说是安全的。如果方法正在执行,读或写的操作会被阻塞。
public abstract class SocketChannel
extends AbstractSelectableChannel
implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel
{
......
}
SocketChannel提供的方法
1.open() 方法
1). 新的SocketChannel通过调用系统默认的java.nio.channels.spi.SelectorProvider对象的openSocketChannel方法创建的 2). 第一次获取SelectorProvider对象按照一下顺序: ??(1). 查看系统属性java.nio.channels.spi.selectorprovider是否存在,存在即它将当作为具体provider类的完全限定名。 ??(2). 如果一个provider类已经打包安装在一个jar文件中,同时这个jar文件对系统类加载器是可见的,并且这个jar文件在它的资源目录META-INF/services中包含一个名为java.nio.channels.spi.SelectorProvider的provider配置文件,然后取该文件中指定的第一个类名。 ??(3). 最后,如果在上面没有指定provider,系统默认的provider类就会实例化。 3). 调用SocketChannelImpl.openSocketChannel()方法,new SocketChannelImpl(this),对自身进行实例构造。
public static SocketChannel open() throws IOException {
return SelectorProvider.provider().openSocketChannel();
}
public static SelectorProvider provider() {
synchronized (lock) {
if (provider != null)
return provider;
return AccessController.doPrivileged(
new PrivilegedAction<SelectorProvider>() {
public SelectorProvider run() {
if (loadProviderFromProperty())
return provider;
if (loadProviderAsService())
return provider;
provider = sun.nio.ch.DefaultSelectorProvider.create();
return provider;
}
});
}
}
public SocketChannel openSocketChannel() throws IOException {
return new SocketChannelImpl(this);
}
2.bind()方法
1). SocketChannel抽象类将bind()方法重写为抽象方法,采用模版方法的设计模式要求子类必须实现
@Override
public abstract SocketChannel bind(SocketAddress local)
throws IOException
@Override
2). SocketChannelImpl类对bind()方法的实现
private final ReentrantLock readLock = new ReentrantLock();
private final ReentrantLock writeLock = new ReentrantLock();
public SocketChannel bind(SocketAddress local) throws IOException {
readLock.lock();
try {
writeLock.lock();
try {
synchronized (stateLock) {
ensureOpen();
if (state == ST_CONNECTIONPENDING)
throw new ConnectionPendingException();
if (localAddress != null)
throw new AlreadyBoundException();
if (isUnixSocket()) {
localAddress = unixBind(local);
} else {
localAddress = netBind(local);
}
}
} finally {
writeLock.unlock();
}
} finally {
readLock.unlock();
}
return this;
}
private SocketAddress netBind(SocketAddress local) throws IOException {
InetSocketAddress isa;
if (local == null) {
isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
} else {
isa = Net.checkAddress(local, family);
}
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkListen(isa.getPort());
}
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(family, fd, isa.getAddress(), isa.getPort());
return Net.localAddress(fd);
}
3). 进行地址绑定
static void bind(ProtocolFamily family, FileDescriptor fd,
InetAddress addr, int port) throws IOException
{
boolean preferIPv6 = isIPv6Available() &&
(family != StandardProtocolFamily.INET);
if (addr.isLinkLocalAddress()) {
addr = IPAddressUtil.toScopedAddress(addr);
}
bind0(fd, preferIPv6, exclusiveBind, addr, port);
}
private static native void bind0(FileDescriptor fd, boolean preferIPv6,
boolean useExclBind, InetAddress addr,
int port)
throws IOException;
|