Java NIO - ServerSocket 通道

  • 简述

    Java NIO ServerSocketChannel又是一个可选类型的通道,用于面向流的数据流连接套接字。ServerSocketChannel可以通过调用其静态 open() 方法创建,前提是任何预先存在的套接字都不存在。ServerSocketChannel是通过调用 open 方法创建的,但尚未绑定。为了绑定SockerChannel bind() 方法将被调用。
    这里要提到的一点是,如果通道未绑定,并且尝试尝试尝试任何 I/O 操作,则此通道将引发 NotYet 绑定异常。因此,在执行任何 IO 操作之前,必须确保通道是有界的。
    ServerSocketChannel的传入连接通过调用ServerSocketChannel.accept() 方法进行侦听。当 accept() 方法返回时,它将返回一个带有传入连接的SockerChannel 。因此,accept() 方法将阻塞,直到传入连接到达。如果通道处于非阻塞模式,则如果没有挂起的连接,则 accept 方法将立即返回 null。否则,它将无限期地阻塞,直到新连接可用或发生 I/O 错误。
    新通道的套接字最初是未绑定的;它必须通过其套接字的绑定方法之一绑定到特定地址,然后才能接受连接。此外,新通道是通过调用系统范围默认选择器提供程序对象的开放服务器通道方法创建的。
    像SockerChannel 一样,ServerSocketChannel可以使用read()数据。首先分配缓冲区。从服务器插座通道读取的数据将存储到缓冲区中。其次,我们调用服务器平台通道.read() 方法,它将数据从服务器平台通道读取到缓冲区中。read() 方法的整数值返回写入缓冲区的字节数
    类似地,可以使用 write() 方法将数据写入ServerSocketChannel,并使用缓冲区作为参数。通常在 while 循环中使用写入方法,因为需要重复 write() 方法,直到 Buffer 没有其他字节可供写入。
  • SockerChannel 的重要方法

    • bind(SocketAddress local) − 此方法用于将SockerChannel 绑定到作为此方法的参数提供的本地地址。
    • accept() − 此方法用于接受与此通道的套接字建立的连接。
    • connect(SocketAddress remote) − 此方法用于将套接字连接到远程地址。
    • finishConnect() − 此方法用于完成连接SockerChannel 的过程。
    • getRemoteAddress() − 此方法返回通道套接字连接到的远程位置的地址。
    • isConnected() − 如前所述,此方法返回SockerChannel 的连接状态,即它是否连接。
    • open() − Open 方法用于打开没有指定地址的SockerChannel 。这种方便的方法的工作方式就好像是调用 open() 方法,在生成的ServerSocketChannel上调用 connect 方法,远程传递它,然后返回该通道。
    • read(ByteBuffer dst) − 此方法用于通过SockerChannel 从给定缓冲区读取数据。
    • setOption(SocketOption name, T value) − 此方法设置套接字选项的值。
    • socket() − 此方法检索与此通道关联的服务器套接字。
    • validOps() − 此方法返回一个操作集,用于标识此通道支持的操作。ServerSocketChannel仅支持接受新连接,因此此方法返回SelectionKey.OP_ACCEPT。
  • 以下示例显示了如何从 Java NIO 服务器登录通道发送数据。

    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();
       }
    }
    

    输出

    在服务器启动之前,运行客户端不会打印任何内容。
    
    

    服务器:SockerChannelServer.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();
       }
    }
    

    输出

    Running the server will print the following.
    
    Connection Set:  /127.0.0.1:49558
    File Received