Java NIO 学习笔记(四)----文件通道和网络通道 (2)

可以看到,基本和 FileChannel 的读写方式一致,首先分配缓冲区,然后调用 read() 方法。 此方法将数据从 SocketChannel 读入 Buffer 。 read() 方法返回的 int 代表写入了多少字节数据。 如果返回 -1 ,则到达流的末尾(连接已关闭)。调用 SocketChannel 对象的 write(Buffer buffer) 方法则可以将 Buffer 的数据写入 SocketChannel。

SocketChannel 的非阻塞模式

可以将 SocketChannel 设置为非阻塞模式,可以在异步模式下调用 connect(),read() 和 write() 方法。

connect()

如果 SocketChannel 处于非阻塞模式调用 connect() 方法,则可能会在建立连接之前返回。 要确定是否成功建立了连接,可以调用 finishConnect() 方法,它当且仅当已连接此通道的套接字时才返回 true 。
如下所示:

socketChannel.configureBlocking(false); socketChannel.connect(new InetSocketAddress("http://baidu.com", 80)); while(! socketChannel.finishConnect() ){ //wait, or do something else... } write()

在非阻塞模式下,write() 方法可能在没有写入任何内容的情况下返回。 因此,需要在循环中调用 write() 方法。

while(buffer.hasRemaining()) { // 只要缓冲区还有数据 channel.write(buffer);// 就将缓冲区数据写入通道 } read()

在非阻塞模式下,read() 方法可能在没有读取任何数据的情况下返回。 因此,需要注意返回的 int ,它代表读取了多少字节。

带有选择器的非阻塞模式

使用 Selector 时,SocketChannel 的非阻塞模式效果更好。 通过使用选择器注册一个或多个 SocketChannel ,可以向选择器询问已准备好进行读取,写入的通道。后面会有更详细的提起,这里先不讲。

ServerSocketChannel

ServerSocketChannel 是一个可以侦听传入 TCP 连接的通道,就像标准 ServerSocket 一样。 这是一个例子:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(9999)); while (true) { SocketChannel socketChannel = serverSocketChannel.accept(); // 监听传入的连接 //do something with socketChannel... } serverSocketChannel.close();

ServerSocketChannel 可以设置为非阻塞模式。 在非阻塞模式下,accept() 方法调用后会立即返回,如果有连接传入,则返回 SocketChannel 对象,如果没有连接传入,则返回 null。 因此,必须检查返回的 SocketChannel 是否为空。如下:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(9999)); serverSocketChannel.configureBlocking(false); while (true) { SocketChannel socketChannel = serverSocketChannel.accept(); // 监听传入的连接 if(socketChannel != null){ //do something with socketChannel... } } DatagramChannel 数据包通道

DatagramChannel 是可以发送和接收 UDP 数据包的通道。 由于 UDP 是一种无连接的网络协议,因此不能像在其他通道中那样读取和写入 DatagramChannel 。 而是通过发送和接收数据包的方式通信。

接收数据

DatagramChannel 是通过 receive() 方法接收数据的。 receive() 方法将接收到的数据包的内容复制到给定的 Buffer 中。 如果接收的数据包包含的数据多于缓冲区可以包含的数据,则会悄悄丢弃多出的数据。一个示例如下:

ByteBuffer receiveBuffer = ByteBuffer.allocate(128); DatagramChannel serverChannel = DatagramChannel.open(); serverChannel.socket().bind(new InetSocketAddress(9999)); receiveBuffer.clear(); // 清除缓冲区,准备写入数据 serverChannel.receive(receiveBuffer); receiveBuffer.flip(); // 反转缓冲区以准备被读取 System.out.println(new String(receiveBuffer.array(), 0, receiveBuffer.limit())); 发送数据 ByteBuffer sendBuffer = ByteBuffer.allocate(128); sendBuffer.clear(); // 清除缓冲区,准备写入数据 byte[] sendData = "string from cilent".getBytes(); sendBuffer.put(sendData); DatagramChannel clientChannel = DatagramChannel.open(); int sendSuccess = clientChannel.send(sendBuffer, new InetSocketAddress("127.0.0.1", 9999)); System.out.println("sendSuccess: " + sendSuccess); clientChannel.close();

此示例将字符串发送到 UDP 本机的 9999 端口, 由于 UDP 不对数据传送做出任何保证,因此不会通知对方是否收到了发送的数据包。

连接到特定地址

可以将 DatagramChannel“连接”到网络上的特定地址。 由于 UDP 是无连接的,因此这种连接到地址的方式不会像 TCP 通道那样创建真正的连接。 它只会锁定 DatagramChannel ,让其只能从一个特定地址发送和接收数据包。一个示例:

channel.connect(new InetSocketAddress("baidu.com", 80));

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwwgs.html