📜  Java NIO-套接字通道

📅  最后修改于: 2020-11-14 10:11:59             🧑  作者: Mango


Java NIO套接字通道是一个可选类型的通道,这意味着可以使用选择器对其进行多路复用,用于面向流的数据流连接套接字。可以通过调用其静态open()方法来创建套接字通道,前提是尚未存在任何预先存在的套接字套接字通道是通过调用open方法但尚未连接而创建的。要连接套接字,必须调用channel ()方法。这里要提到的一点是如果未连接通道并且尝试了任何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方法,将其远程传递,然后返回该通道。

  • 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