上一次,我们总结了常用buffer种类和方法,这一次我们来总结一下常用的Channel,我们将Channel根据不同的用途分为三种:网络Channel,文件Channel,管道Channel
一. 网络Channel
名称 | 描述 |
---|---|
ServerSocketChannel | 监听socket流的channel |
SocketChannel | 连接socket的channel |
DatagramChannel | 使用datagram连接socket的Channel |
AsynchronousServerSocketChannel | 监听socket流的channel(JDK7支持的AIO) |
AsynchronousSocketChannel | 连接socket异步的channel(JDK7支持的AIO) |
1. 对于ServerSocketChannel主要有open(),bind(SocketAddress),socket(),accept方法,接下来详细看一下方法的实现:
public static ServerSocketChannel open() throws IOException {
//可以看到open方法并没有在类中直接实现,而是通过静态代理的方式,在SelectorProvider中实现。
return SelectorProvider.provider().openServerSocketChannel();
}
//绑定监听端口
public abstract ServerSocketChannel bind(SocketAddress local, int backlog)
throws IOException;
//返回ServerSocket服务Socket
public abstract ServerSocket socket();
//接收Socket连接
public abstract SocketChannel accept() throws IOException;
举一个简单使用的例子:
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(8888));
while(true){
SocketChannel socketChannel = serverSocketChannel.accept();
}
- 接下来看一下SocketChannel的应用:
InetSocketAddress socketAddress = new InetSocketAddress("localhost", 8080);
channel = SocketChannel.open(socketAddress);
channel.write(charset.encode("GET " + "/ HTTP/1.1" + "\r\n\r\n"));
ByteBuffer buffer = ByteBuffer.allocate(1024);// 创建1024字节的缓冲
while (channel.read(buffer) != -1) {
buffer.flip();// flip方法在读缓冲区字节操作之前调用。
System.out.println(charset.decode(buffer));
// 使用Charset.decode方法将字节转换为字符串
buffer.clear();// 清空缓冲
}
SocketChannel主要方法由read()和write()方法,以便将缓冲区内容读出和写入。
DatagramChannel是可以收发UDP包的Channel
DatagramChannel channel = DatagramChannel.open(); // channel.socket().bind(new InetSocketAddress("localhost",8080)); channel.connect(new InetSocketAddress("localhost",8080)); ByteBuffer buf = ByteBuffer.allocate(1024); while(true){ int read = channel.read(buf); break; } channel.write(buf);
4.AsynchronousServerSocketChannel作为异步非阻塞的Channel,提供了异步的接收连接,来看一下方法定义:
public abstract Future<AsynchronousSocketChannel> accept();
通过方法定义我们可以看到AsynchronousServerSocketChannel使用Future来接收连接,使用Future的get()方法返回Channel。
- AsynchronousSocketChannel作为对应SocketChannel的异步Channel,同样提供了异步的连接、读和写方法:
public abstract Future<Void> connect(SocketAddress remote);
public abstract Future<Integer> read(ByteBuffer dst);
public abstract Future<Integer> write(ByteBuffer src);
二. 文件Channel
名称 | 描述 |
---|---|
FileChannel | 支持读、写、映射以及操作文件的管道 |
AsynchronousFileChannel | 支持异步读、写、映射以及操作文件的管道(JDK7支持的AIO) |
1. FileChannel支持读写文件,主要方法同样是read(Buffer)和write(Buffer),举个例子:
```
//1.打开文件
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
//2.读取文件
ByteBuffer buf = ByteBuffer.allocate(100);
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = null;
while(inChannel.read(buf) != -1){
buf.flip();
charBuffer = decoder.decode(buf);
System.out.print(charBuffer.toString());
buf.clear();
}
//3.写入文件
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
channel.write(buf);
}
//4.关闭
channel.close();
```
三. 管道Channel
PipeChannel拥有两个管道如下:
名称 | 描述 |
---|---|
Pipe.SinkChannel | Pipe的目的Channel |
Pipe.SourceChannel | Pipe的输入Channel |
SourceChannel相当于管道的头,SinkChannel相当于管道的尾,接下来看一个读写的例子:
public class PipeChannelTest {
public static void main(String[] args) {
try {
Pipe pipe = Pipe.open();
SourceChannel source = pipe.source();
SinkChannel sink = pipe.sink();
writeData(sink,"Hello World!");
readData(source);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void readData(SourceChannel source) {
ByteBuffer buffer = ByteBuffer.allocate(48);
Charset charset = Charset.forName("UTF-8");
CharBuffer charBuf = null;
try {
while(source.read(buffer)!=-1){
buffer.flip();
charBuf = charset.decode(buffer);
System.out.println(charBuf.toString());
buffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void writeData(SinkChannel sink, String data) throws IOException {
if(data== null)
throw new NullPointerException();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(data.getBytes());
buf.flip();
while(buf.hasRemaining()) {
sink.write(buf);
}
}
}