Java NIO - Socket 套接字通道
Java NIO 套接字通道是一种可选类型的通道,这意味着它可以使用选择器进行多路复用,用于面向流的数据流连接套接字。可以通过调用其静态open()方法来创建套接字通道,前提是任何预先存在的套接字都不存在。套接字通道是通过调用 open 方法创建的,但尚未连接。为了连接套接字通道,需要调用connect()方法。这里要提到的一点是,如果通道未连接并且尝试进行任何 I/O 操作,则此通道将抛出 NotYetConnectedException。因此,在执行任何 IO 操作之前,必须确保通道已连接。一旦通道连接,它将保持连接状态,直到关闭。可以通过调用其isConnected方法确定套接字通道的状态。
可以通过调用其finishConnect()来完成套接字通道的连接方法。可以通过调用 isConnectionPending 方法来确定连接操作是否正在进行中。默认情况下,套接字通道支持非阻塞连接。它还支持异步关闭,这类似于 Channel 类中指定的异步关闭操作。
套接字通道可供多个并发线程安全使用。它们支持并发读取和写入,但在任何给定时间最多只有一个线程可以读取,最多只有一个线程可以写入。connect 和 finishConnect 方法相互同步,并且在调用其中一个方法时尝试启动读取或写入操作将被阻止,直到该调用完成。
套接字通道的重要方法
bind(SocketAddress local) −此方法用于将套接字通道绑定到作为此方法的参数提供的本地地址。
connect(SocketAddress remote) − 此方法用于将套接字连接到远程地址。
finishConnect() − 此方法用于完成套接字通道的连接过程。
getRemoteAddress() − 此方法返回通道套接字所连接的远程位置的地址。
isConnected() −如前所述,此方法返回套接字通道的连接状态,即是否已连接。
open() 和 open((SocketAddress remote) − Open 方法用于打开未指定地址的套接字通道,而参数化的 open 方法用于打开指定远程地址的通道并连接到该通道。此便捷方法的工作原理类似于调用 open() 方法,在生成的套接字通道上调用 connect 方法,将其传递给 remote,然后返回该通道。
read(ByteBuffer dst) − 此方法用于通过套接字通道从给定缓冲区读取数据。
isConnectionPending() − 此方法告知此通道上是否正在进行连接操作。
示例
以下示例显示了如何从 Java NIO 发送数据SocketChannel。
C:/Test/temp.txt
Hello World!
Client: 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(); } }
输出
运行客户端不会打印任何内容,直到服务器启动。
Server: 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