- Java NIO 教程
- Java NIO - 首页
- Java NIO - 概述
- Java NIO - 环境设置
- Java NIO vs JAVA IO
- Java NIO - 通道
- Java NIO - 文件通道
- Java NIO - 数据报通道
- Java NIO - 套接字通道
- Java NIO - 服务器套接字通道
- Java NIO - 散射
- Java NIO - 聚集
- Java NIO - 缓冲区
- Java NIO - 选择器
- Java NIO - 管道
- Java NIO - 路径
- Java NIO - 文件
- Java NIO - AsynchronousFileChannel
- Java NIO - 字符集
- Java NIO - 文件锁
- Java NIO 有用资源
- Java NIO - 快速指南
- Java NIO - 有用资源
- Java NIO - 讨论
Java NIO - ServerSocket 通道
Java NIO 服务器套接字通道也是一种可选择的通道类型,用于连接套接字的面向流的数据流。如果不存在任何预先存在的套接字,则可以通过调用其静态open()方法创建服务器套接字通道。服务器套接字通道是通过调用 open 方法创建的,但尚未绑定。为了绑定套接字通道,必须调用bind()方法。
这里需要提到的一点是,如果通道未绑定且尝试执行任何 I/O 操作,则此通道将抛出 NotYetBoundException。因此,必须确保在执行任何 I/O 操作之前绑定通道。
服务器套接字通道的传入连接通过调用 ServerSocketChannel.accept() 方法来监听。当 accept() 方法返回时,它返回一个带有传入连接的 SocketChannel。因此,accept() 方法会阻塞,直到到达传入连接。如果通道处于非阻塞模式,则如果没有任何待处理的连接,accept 方法将立即返回 null。否则,它将无限期地阻塞,直到新的连接可用或发生 I/O 错误。
新通道的套接字最初未绑定;必须通过其套接字的 bind 方法之一将其绑定到特定地址,然后才能接受连接。此外,新通道是通过调用系统范围的默认 SelectorProvider 对象的 openServerSocketChannel 方法创建的。
像套接字通道一样,服务器套接字通道可以使用read()方法读取数据。首先分配缓冲区。从 ServerSocketChannel 读取的数据存储到缓冲区中。其次,我们调用 ServerSocketChannel.read() 方法,它将数据从 ServerSocketChannel 读取到缓冲区中。read() 方法的整数值返回写入缓冲区的字节数。
同样,可以使用write()方法将数据写入服务器套接字通道,并使用缓冲区作为参数。通常在 while 循环中使用 write 方法,因为需要重复 write() 方法,直到缓冲区没有更多可写的字节。
套接字通道的重要方法
bind(SocketAddress local) − 此方法用于将套接字通道绑定到作为此方法参数提供的本地地址。
accept() − 此方法用于接受与此通道的套接字建立的连接。
connect(SocketAddress remote) − 此方法用于将套接字连接到远程地址。
finishConnect() − 此方法用于完成连接套接字通道的过程。
getRemoteAddress() − 此方法返回通道的套接字连接到的远程位置的地址。
isConnected() − 正如前面提到的,此方法返回套接字通道的连接状态,即它是否已连接。
open() − open 方法用于为未指定的地址打开套接字通道。此便捷方法的工作方式如同调用 open() 方法、对生成的服务器套接字通道调用 connect 方法、将其传递给 remote,然后返回该通道。
read(ByteBuffer dst) − 此方法用于通过套接字通道从给定的缓冲区读取数据。
setOption(SocketOption<T> name, T value) − 此方法设置套接字选项的值。
socket() − 此方法检索与此通道关联的服务器套接字。
validOps() − 此方法返回一个操作集,该操作集标识此通道支持的操作。服务器套接字通道仅支持接受新连接,因此此方法返回 SelectionKey.OP_ACCEPT。
示例
以下示例演示如何从 Java NIO ServerSocketChannel 发送数据。
C:/Test/temp.txt
Hello World!
客户端:SocketChannelClient.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
public class SocketChannelClient {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocket = null;
SocketChannel client = null;
serverSocket = ServerSocketChannel.open();
serverSocket.socket().bind(new InetSocketAddress(9000));
client = serverSocket.accept();
System.out.println("Connection Set: " + client.getRemoteAddress());
Path path = Paths.get("C:/Test/temp1.txt");
FileChannel fileChannel = FileChannel.open(path,
EnumSet.of(StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.WRITE)
);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(client.read(buffer) > 0) {
buffer.flip();
fileChannel.write(buffer);
buffer.clear();
}
fileChannel.close();
System.out.println("File Received");
client.close();
}
}
输出
运行客户端在服务器启动之前不会打印任何内容。
服务器:SocketChannelServer.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
public class SocketChannelServer {
public static void main(String[] args) throws IOException {
SocketChannel server = SocketChannel.open();
SocketAddress socketAddr = new InetSocketAddress("localhost", 9000);
server.connect(socketAddr);
Path path = Paths.get("C:/Test/temp.txt");
FileChannel fileChannel = FileChannel.open(path);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(fileChannel.read(buffer) > 0) {
buffer.flip();
server.write(buffer);
buffer.clear();
}
fileChannel.close();
System.out.println("File Sent");
server.close();
}
}
输出
运行服务器将打印以下内容。
Connection Set: /127.0.0.1:49558 File Received