📜  Java NIO-ServerSocket通道

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


Java NIO服务器套接字通道再次是用于连接套接字的面向流数据流的可选类型通道。服务器套接字通道可以通过调用其静态open()方法来创建,前提是尚不存在任何预先存在的套接字。通过调用open方法创建但尚未绑定。为了绑定套接字通道,必须调用bind()方法。

这里要提到的一点是,如果未绑定通道并且尝试尝试任何I / O操作,则此通道将引发NotYetBoundException,因此必须确保在执行任何IO操作之前将通道绑定。

通过调用ServerSocketChannel.accept()方法来侦听服务器套接字通道的传入连接。当accept()方法返回时,它将返回带有传入连接的SocketChannel。因此,accept()方法将阻塞直到传入连接到达为止。如果通道处于非阻塞模式,则如果没有挂起的连接,则accept方法将立即返回null。否则,它将无限期阻塞,直到有新连接可用或发生I / O错误为止。

新通道的套接字最初未绑定;必须先通过其套接字的bind方法之一将其绑定到特定地址,然后才能接受连接。此外,还可以通过调用系统级默认SelectorProvider对象的openServerSocketChannel方法来创建新通道。

就像套接字通道服务器一样,套接字通道可以使用read()方法读取数据。首先分配缓冲区。从ServerSocketChannel读取的数据存储在缓冲区中。其次,我们调用ServerSocketChannel.read()方法,并将其从ServerSocketChannel读取到缓冲区中。 read()方法的整数值返回将多少字节写入缓冲区

类似地,可以使用write()方法(使用buffer作为参数)将数据写入服务器套接字通道.Common在循环中使用write方法,因为需要重复执行write()方法,直到Buffer没有更多可用字节可以写入为止。

套接字通道的重要方法

  • bind(SocketAddress local) -此方法用于将套接字通道绑定到作为此方法的参数提供的本地地址。

  • accept() -此方法用于接受与此通道的套接字建立的连接。

  • connect(SocketAddress remote) -此方法用于将套接字连接到远程地址。

  • finishConnect() -此方法用于完成套接字通道的连接过程。

  • getRemoteAddress() -此方法返回通道套接字连接到的远程位置的地址。

  • isConnected() -如前所述,此方法返回套接字通道的连接状态,即是否已连接。

  • open() -使用open方法打开一个没有指定地址的套接字通道,此便捷方法的工作方式类似于调用open()方法,在生成的服务器套接字通道上调用connect方法,将其远程传递然后返回渠道。

  • read(ByteBuffer dst) -此方法用于通过套接字通道从给定的缓冲区读取数据。

  • setOption(SocketOption 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