NIO Channel SocketChannel ServerSocketChannel
ServerSocketChannel:
ServerSocketChannel是一个基于通道的socket监听器。它同我们所熟悉的java.net.ServerSocket执行相同的基本任务,不过它增加了通道语义,因此能够在非阻塞模式下运行。用静态的open( )工厂方法创建一个新的ServerSocketChannel对象,将会返回同一个未绑定的java.net.ServerSocket关联的通道。该对等ServerSocket可以通过在返回的ServerSocketChannel上调用socket( )方法来获取。作为ServerSocketChannel的对等体被创建的ServerSocket对象依赖通道实现。这些socket关联的SocketImpl能识别通道。通道不能被封装在随意的socket对象外面。由于ServerSocketChannel没有bind( )方法,因此有必要取出对等的socket并使用它来绑定到一个端口以开始监听连接。我们也是使用对等ServerSocket的API来根据需要设置其他的socket选项。
核心Api:
同它的对等体java.net.ServerSocket一样,ServerSocketChannel也有accept( )方法。一旦您创建了一个ServerSocketChannel并用对等socket绑定了它,然后您就可以在其中一个上调用accept( )。如果您选择在ServerSocket上调用accept( )方法,那么它会同任何其他的ServerSocket表现一样的行为:总是阻塞并返回一个java.net.Socket对象。如果您选择在ServerSocketChannel上调用accept( )方法则会返回SocketChannel类型的对象,返回的对象能够在非阻塞模式下运行 默认为阻塞状态。假设系统已经有一个安全管理器(security manager),两种形式的方法调用都执行相同的安全检查。如果以非阻塞模式被调用,当没有传入连接在等待时,ServerSocketChannel.accept( )会立即返回null。正是这种检查连接而不阻塞的能力实现了可伸缩性并降低了复杂性。可选择性也因此得到实现。我们可以使用一个选择器实例来注册一个ServerSocketChannel对象以实现新连接到达时自动通知的功能。即只有Channel类型的对象才能实现非阻塞操作。
代码示例如下:
/**
* configureBlocking Test
* @throws Exception
*/
@Test
public void serverSocketChannelTest() throws Exception {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(8080));
ssc.configureBlocking(false);
assert (ssc.validOps()==16);//return SelectionKey.OP_ACCEPT;
SocketChannel socketChannel = ssc.accept();
assert (socketChannel==null);
//ServerSocket socket =ssc.socket();
//socket.accept();//抛出异常,IllegalBlockingModeException,ssc.configureBlocking(false)之后方可执行
Thread socketThread = new Thread(()->{
while (true){
try {
SocketChannel socketChannel1 = ssc.accept();
if (socketChannel1!=null){
assert (socketChannel1.isBlocking());
break;
}
} catch (IOException e) {
e.printStackTrace();
}
} });
socketThread.start();
SocketChannel socket = SocketChannel.open();
socket.configureBlocking(false);
socket.connect(new InetSocketAddress("localhost",8080));
socketThread.join();
}
SocketChannel:
Socket和SocketChannel类封装点对点、有序的网络连接,类似于我们所熟知并喜爱的TCP/IP网络连接。SocketChannel扮演客户端发起同一个监听服务器的连接。直到连接成功,它才能收到数据并且只会从连接到的地址接收。
对应方法如下:
在SocketChannel上并没有一种connect( )方法可以让您指定超时(timeout)值,当connect( )方法在非阻塞模式下被调用时SocketChannel提供并发连接:它发起对请求地址的连接并且立即返回值。如果返回值是true,说明连接立即建立了(这可能是本地环回连接);如果连接不能立即建立,connect( )方法会返回false且并发地继续连接建立过程。
面向流的的socket建立连接状态需要一定的时间,因为两个待连接系统之间必须进行包对话以建立维护流socket所需的状态信息。跨越开放互联网连接到远程系统会特别耗时。假如某个SocketChannel上当前正由一个并发连接,isConnectPending( )方法就会返回true值。
Socket通道是线程安全的。并发访问时无需特别措施来保护发起访问的多个线程,不过任何时候都只有一个读操作和一个写操作在进行中(保证数据不丢失而不保证维持数据分组)。请记住,sockets是面向流的而非包导向的。它们可以保证发送的字节会按照顺序到达但无法承诺维持字节分组。某个发送器可能给一个socket写入了20个字节而接收器调用read( )方法时却只收到了其中的3个字节。剩下的17个字节还是传输中。由于这个原因,让多个不配合的线程共享某个流socket的同一侧绝非一个好的设计选择。
调用finishConnect( )方法来完成连接过程(非阻塞模式下必须调用,否则非阻塞模式下isConnected( )永远返回false),该方法任何时候都可以安全地进行调用。假如在一个非阻塞模式的SocketChannel对象上调用finishConnect( )方法,将可能出现下列情形之一:
connect( )方法尚未被调用。那么将产生NoConnectionPendingException异常。
连接建立过程正在进行,尚未完成。那么什么都不会发生,finishConnect( )方法会立即返回false值。
在非阻塞模式下调用connect( )方法之后,SocketChannel又被切换回了阻塞模式。那么如果有必要的话,调用线程会阻塞直到连接建立完成,finishConnect( )方法接着就会返回true值。
在初次调用connect( )或最后一次调用finishConnect( )之后,连接建立过程已经完成。那么SocketChannel对象的内部状态将被更新到已连接状态,finishConnect( )方法会返回true值,然后SocketChannel对象就可以被用来传输数据了。
连接已经建立。那么什么都不会发生,finishConnect( )方法会返回true值。
当通道处于中间的连接等待(connection-pending)状态时,您只可以调用finishConnect( )、isConnectPending( )或isConnected( )方法。一旦连接建立过程成功完成,isConnected( )将返回true值。
示例代码如下:
/**
* configureBlocking Test
* @throws Exception
*/
@Test
public void serverSocketChannelTest() throws Exception {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(8080));
ssc.configureBlocking(false);
assert (ssc.validOps()==16);//return SelectionKey.OP_ACCEPT;
SocketChannel socketChannel = ssc.accept();
assert (socketChannel==null);
//ServerSocket socket =ssc.socket();
//socket.accept();//抛出异常,IllegalBlockingModeException,ssc.configureBlocking(false)之后方可执行
Thread socketThread = new Thread(()->{
while (true){
try {
SocketChannel socketChannel1 = ssc.accept();
if (socketChannel1!=null){
assert (socketChannel1.isBlocking());
ByteBuffer [] buffers = NIOUtils.getByteBuffers("hello","world");
long size = socketChannel1.write(buffers);
System.out.println(size);
//socketChannel1.close();
break;
}
} catch (IOException e) {
e.printStackTrace();
}
} });
socketThread.start();
SocketChannel socket = SocketChannel.open();
socket.configureBlocking(false);
socket.connect(new InetSocketAddress("localhost",8080));
assert (socket.validOps()==13);
/*public final int validOps() {
return (SelectionKey.OP_READ
| SelectionKey.OP_WRITE
| SelectionKey.OP_CONNECT);
}*/
assert (!socket.isBlocking()); ByteBuffer[] readableBuffers = NIOUtils.getReadableByteBuffers(3);
assert (!socket.isConnected());
assert (socket.isConnectionPending());
while (true){
//TimeUnit.SECONDS.sleep(1);
assert (socket.finishConnect());//本地情况直接返回true
if (socket.isConnected()){
long size = socket.read(readableBuffers);
if (size!=0){
break;
}
}
}
socketThread.join();
System.out.println(readableBuffers[0]);
ByteBuffer buffer = ByteBuffer.allocate(5);
buffer.put("hello".getBytes());
assert (buffer.equals(readableBuffers[0]));
}
NIO Channel SocketChannel ServerSocketChannel的更多相关文章
- [翻译] java NIO Channel
原文地址:http://tutorials.jenkov.com/java-nio/channels.html JAVA NIO channels和流的概念很像,下面是他们的一些区别: 你可以对cha ...
- Java NIO Channel通道
原文链接:http://tutorials.jenkov.com/java-nio/channels.html Java NIO Channel通道和流非常相似,主要有以下几点区别: 通道可以读也可以 ...
- NIO Channel和Buffer
Java NIO 由以下几个核心部分组成: Buffer Channel Selector 传统的IO操作面向数据流,意味着每次从流中读一个或多个字节,直至完成,数据没有被缓存在任何地方.NIO操作面 ...
- Java (Socket,ServerSocket)与(SocketChannel,ServerSocketChannel)区别和联系
Socket 和ServerSocke 是一对 他们是java.net下面实现socket通信的类SocketChannel 和ServerSocketChannel是一对 他们是java.nio下面 ...
- NIO Channel 管道
Java NIO的通道类似流,但又有些不同: 既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. 通道可以异步地读写. 通道中的数据总是要先读到一个Buffer,或者总是要从一个Bu ...
- (三:NIO系列) Java NIO Channel
出处: Java NIO Channel 1.1. Java NIO Channel的特点 和老的OIO相比,通道和NIO流(非阻塞IO)主要有以下几点区别: (1)OIO流一般来说是单向的(只能读或 ...
- Java NIO Channel 使用
Java NIO 中的 Channel 分类: FileChannel SocketChannel ServerSocketChannel DatagramChannel channel 分类 Fil ...
- 【JAVA】【NIO】3、Java NIO Channel
Java NIO和流量相似,但有些差异: ·通道可读写,流仅支持单向.读或写 ·异步通道读取 ·通道读写器,他们是和Buffer交替 道的实现 下面是Java NIO中最重要的通道的实现: ·File ...
- Java NIO Channel和Buffer
Java NIO Channel和Buffer @author ixenos Channel和Buffer的关系 1.NIO速度的提高来自于所使用的结构更接近于OS执行I/O的方式:通道和缓冲器: 2 ...
随机推荐
- SpringBoot配置中@ConfigurationProperties和@Value的区别
基本特征 @ConfigurationProperties 与@Bean结合为属性赋值 与@PropertySource(只能用于properties文件)结合读取指定文件 与@Validation结 ...
- 解决vue-cli项目开发中跨域问题
一.开发环境中跨域 使用 Vue-cli 创建的项目,开发地址是 localhost:8080,需要访问非本机上的接口http://10.1.0.34:8000/queryRole.不同域名之间的访问 ...
- win10设置锁屏密码
1.点击右下角窗口键 2.选择点击设置 3.点击账户 4.点击登录选项 5.点击密码,添加密码 6.设置密码 7.使用快捷键“窗口键+l”锁屏,就会提示你输入密码
- 基于webpack的前端工程化开发解决方案探索(二):代码分割与图片加载
今天我们继续来进行webpack工程化开发的探索! 首先来验证上一篇文章 基于webpack的前端工程化开发解决方案探索(一):动态生成HTML 中的遗留问题:webpack将如何处理按需加载的 ...
- 设计的一些kubernetes面试题
公司现在上了一部分的业务至k8s,老实说,我心里很慌,在项目改造中,每天都会遇到很多问题,好友找我出一份k8s面试题,参考了网上的一些,再加上自己公司遇到的一些问题,整理如下: 参考链接:http:/ ...
- C语言知识点拾遗
sleep() abort() fflush() getimeofday() sigaction() Linux 进程学习(四)------ sigaction 函数 malloc() 如何实现一个m ...
- 0x01 Python logging模块
目录 Python logging 模块 前言 logging模块提供的特性 logging模块的设计过程 logger的继承 logger在逻辑上的继承结构 logging.basicConfig( ...
- WSL quick overview
简介 WSL,是Windows Subsystem for Linux的缩写,字面意义上理解就是WIndows下的Linux子系统.WSL 由Microsoft Windows内核团队创建,目前如果最 ...
- 网页代码编辑器Blocs for mac如何进行行的控制?
行是Blocs应用程序中的关键结构元素之一,它们是列和Bloc容器,它们构成了构建站点布局的基础.在本篇文章中,我们介绍的是网页代码编辑器Blocs for mac如何进行行的控制? ] 网页代码编辑 ...
- 详解Linux系统中10个最危险的命令
概述 大多数的朋友都是主要用的windows系统,基本用鼠标就可以完成所有的操作,但是在Linux系统中很多都是键盘+命令操作电脑的,Linux命令行使用很有趣,但有时候也很危险,尤其是在你不确定你自 ...