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!

客戶端: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
廣告

© . All rights reserved.