文章目录
NIO Channel
- Channel (java.nio.channels.Channel) 是 NIO 的三个核心组件之一,Channel 在NIO中代表通道,在JDK中是一个接口。
一、Channel和流
- Channel 可以是双向的,既可以通过Channel读数据,也可以写数据,流的话要么是输入流,要么是输出流
- 不能直接通过 Channel 读写数据,必须通过buffer操作,程序通过Buffer间接的和Channel打交道,程序永远不能绕过buffer直接操作Channel,而流是可以直接读写的
- Channel的读写可以是非阻塞的,而流是阻塞的
二、Channel的主要实现类
实现类 | 作用场景 |
---|---|
SocketChannel | 客户端用来发起 TCP连接的 的 Channel |
ServerSocketChannel | 服务端用于监听客户端TCP连接的Channel,每接受到一个连接,则会创建一个SocketChannel |
DatagramChannel | 通过 UDP 读写数据的 Channel |
FileChannel | 从文件读写数据的 Channel |
在 Netty 中主要涉及到的是 SocketChannel 和 ServerSocketChannel ,下面给出这两个的继承图,比较类似:
三、从Socket到Channel
- 最初的网络编程最熟悉的类是 Socket 和 ServerSocket,那么 Socket 和 ServerSocket VS SocketChannel 和 ServerSocketChannel ,这两组类之间的区别和联系是什么?
3.1 Socket和ServerSocket
- Socket 和 ServerSocke 是对应的,分别对应客户端和服务端,它们是 java.net 下面实现 Socket 通信的类,只支持阻塞通信(或者自己实现非阻塞通信),通常在 ServerSocket 实现的服务端是为每一个客户端分配一个线程(或者线程池),由此能够支持的客户端数量有限。
- 在阻塞IO的通信中我们就是使用这两个类,在文章: 03-BIO、NIO到Netty 的BIO示例中有给出,核心伪代码如下:
客户端:
{
Socket socket = new Socket(IP, PORT);
//后续数据读写:
socket.getOutputStream()
socket.getInputStream()
}
服务端:
{
ServerSocket serverSocket = new ServerSocket(PORT);
while (true) {
Socket socket = serverSocket.accept();
//线程池处理连接
threadPool.execute(new ServerHandler(socket));
}
}
- Socket:可以理解为客户端与服务端的一个连接,比如客户端 Socket socket=new Socket(ip,port);其中 socket 这个 Socket 对象就代表客户端和对应ip端口的一个连接;
- ServerSocket:可以理解为服务端等待客户端连接的一个Socket对象,比如服务端 ServerSocket serverSocket = new ServerSocket(port);其中 serverSocket 代表服务端监听在 port 的一个 Socket,这里并不代表一个连接,仅仅代表一个服务的监听,ServerSocket收到连接请求之后通过 accept方法可以打开一个Socket对象,与客户端进行通信。
3.2 SocketChannel和ServerSocketChannel
- SocketChannel 和 ServerSocketChannel 是对应的,分别对应客户端和服务端,他们是 java.nio 下面实现通信的类,支持异步通信(通过参数配置)
- 在NIO的通信中我们就是使用这两个类,在文章: 03-BIO、NIO到Netty 的NIO示例中有给出,核心伪代码如下:
{
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(new InetSocketAddress(port));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while(true){
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
//处理事件
}
}
- SocketChannel:可以理解为客户端与服务端的一个Tcp Channel通道,类比于Socket
- ServerSocketChannel:可以绑定端口等待监听,类比于 ServerSocket,ServerSocketChannel的accept方法会返回一个 SockerChannel
- SocketChannel和ServerSocketChannel的使用需要结合 Selector 组件,通过Selector 实现少量线程管理大量连接。
3.3 联系
- 下面图是这四个类大致的关系,我们看到从功能上来看 Socket 和 SocketChannel很类似,SocketChannel 和 ServerSocketChannel很类似,但是Channel提供了非阻塞的通信模式,因此可以简单地认为Channel是对Socket的升级。而且通过getChannel()方法和socket()方法,他们之间可以相互转换。
- 通信时,服务器必须先建立 ServerSocket 或者 ServerSocketChannel 监听并等待客户端的连接,客户端必须建立相对应的 Socket 或者 SocketChannel 来与服务器建立连接,服务器在接受到客户端的连接受,会生成一个 Socket 或者 SocketChannel 与此客户端通信,注意重新生成的连接所使用的端口与监听的端口是不一样的。
四、Netty Channel
- 前面描述的是 java.nio.channels.Channel,是JDK NIO 中的 Channel,和 Netty中的Channel还不一样,Netty中自己定义了 io.netty.channel.Channel,Netty的Channel 后续专门再分析,这里只提一下,在Netty中 io.netty.channel.Channel 接口的实现类 有些封装了 JDK的Channel,比如在 NioServerSocketChannel 中就封装了 NIO 中的ServerSocketChannel,SocketChannel和SelectionKey等组件,因此可以认为Netty重新定义了一套Channel接口以及相关的继承体系可以更好的组织类之间的关系,提供统一的API,但是其底层最终还是会用到JDK NIO的相关实现,最底层的通信类还是用的JDK的。