- 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