从SocketChannel读取数据

本文介绍如何使用Java NIO中的SocketChannel进行非阻塞数据读取,并提供了完整的代码示例,展示了直接在ByteBuffer中操作及转换为String的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SocketChannel的读取方式也比较特殊,请看代码。可以直接在ByteBuffer里面操作。也可以转化为byte[]再转为中文String

  1. package net.java2000.nio;
  2. import java.io.IOException;
  3. import java.net.InetSocketAddress;
  4. import java.nio.ByteBuffer;
  5. import java.nio.channels.SocketChannel;
  6. /**
  7.  * 从SocketChannel读取数据。
  8.  * 
  9.  * @author 赵学庆,Java世纪网(java2000.net)
  10.  * 
  11.  */
  12. public class SocketChannelRead {
  13.   public static SocketChannel createSocketChannel(String hostName, int port)
  14.       throws IOException {
  15.     SocketChannel sChannel = SocketChannel.open();
  16.     sChannel.configureBlocking(false);
  17.     sChannel.connect(new InetSocketAddress(hostName, port));
  18.     return sChannel;
  19.   }
  20.   public static void main(String[] args) {
  21.     ByteBuffer buf = ByteBuffer.allocateDirect(1024);
  22.     byte[] buff = new byte[1024];
  23.     try {
  24.       buf.clear();
  25.       SocketChannel socketChannel = createSocketChannel("163.net"25);
  26.       while (!socketChannel.finishConnect()) {
  27.         System.out.println("等待非阻塞连接建立....");
  28.         try {
  29.           Thread.sleep(10);
  30.         } catch (InterruptedException e) {
  31.           e.printStackTrace();
  32.         }
  33.       }
  34.       int numBytesRead;
  35.       while ((numBytesRead = socketChannel.read(buf)) != -1) {
  36.         if (numBytesRead == 0) {
  37.           // 如果没有数据,则稍微等待一下
  38.           try {
  39.             Thread.sleep(1);
  40.           } catch (InterruptedException e) {
  41.             e.printStackTrace();
  42.           }
  43.           continue;
  44.         }
  45.         // 转到最开始
  46.         buf.flip();
  47.         while (buf.remaining() > 0) {
  48.           System.out.print((char) buf.get());
  49.         }
  50.         // 也可以转化为字符串,不过需要借助第三个变量了。
  51.         // buf.get(buff, 0, numBytesRead);
  52.         // System.out.println(new String(buff, 0, numBytesRead, "UTF-8"));
  53.         // 复位,清空
  54.         buf.clear();
  55.       }
  56.     } catch (IOException e) {
  57.       e.printStackTrace();
  58.     }
  59.   }
  60. }

运行效果
等待非阻塞连接建立....
等待非阻塞连接建立....
220 Coremail SMTP(Anti Spam) System (163net[040302])


### 非阻塞读取数据的定义 非阻塞读取是一种I/O模式,其中调用方不会因为等待资源而被挂起。当尝试从某个流或套接字中读取数据时,如果没有数据可供读取,则函数立即返回而不是让程序进入等待状态[^1]。这种行为通常通过设置特定标志位来启用。 ### 原理 非阻塞读取的核心在于操作系统如何处理未准备好数据的情况。对于标准输入/输出设备或其他网络连接,如果当前没有待处理的数据包到达,系统会立刻通知应用程序这一情况而非使其陷入停滞。具体来说: - 当执行 `read` 或类似的 I/O 调用时,如果目标缓冲区为空,则该操作迅速完成并携带错误码(如 Linux 下常见的 `EWOULDBLOCK`),表明此时无有效负载可获取。 - 这种机制允许开发者设计更加灵活高效的事件驱动架构,在单一线程内管理多个并发任务而不必担心因某单一活动而导致整体延迟增加[^1]。 ### 实现方法 以下是几种常见平台上的实现策略: #### UNIX/Linux 平台下的 C/C++ 示例 可以通过将文件描述符配置成非阻塞模式来达成目的。下面展示了一个简单的例子说明如何调整 socket 的属性以及相应地捕获可能发生的异常状况: ```c #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> void set_nonblocking(int sockfd){ int flags; /* 获取现有的flags */ if((flags = fcntl(sockfd, F_GETFL, NULL)) == -1 ){ perror("Error getting flags"); exit(EXIT_FAILURE); } /* 设置为NONBLOCKING MODE*/ if(fcntl(sockfd ,F_SETFL,flags | O_NONBLOCK)==-1){ perror("Error setting non-blocking mode"); exit(EXIT_FAILURE); } } ``` 之后就可以像之前那样正常调用 `recv()` 函数来进行接收动作了,只不过现在即使没有任何新消息传进来也不会造成进程暂停运行[^1]。 #### Java NIO 中的应用实例 Java 新型 IO 库也支持创建非阻塞通道用于高效的数据交换过程。这里给出一段关于 ServerSocketChannel 使用非阻塞方式监听客户端请求的小片段作为参考: ```java import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.ServerSocketChannel; public class NonBlockingServer { public static void main(String[] args)throws IOException{ // 创建server端channel,并将其设为non-blocking state. ServerSocketChannel serverChannel=ServerSocketChannel.open(); serverChannel.configureBlocking(false); InetSocketAddress address=new InetSocketAddress("localhost",8080); serverChannel.socket().bind(address); while(true){ SocketChannel clientConnection=serverChannel.accept(); if(clientConnection!=null){ System.out.println("New connection accepted."); // 处理新的客户链接... }else{ // 继续做其他事情... } } } } ``` 在这个版本里,服务器并不会一直停留在 accept 方法上直至有人敲门访问它才会继续往下走;相反的是即便暂时无人造访也能顺利循环回到起点重新检测是否有潜在的新访客到来[^2]。 ### 总结 无论是哪种编程环境还是具体的API接口形式,采用非阻塞技术都能够显著提升系统的响应速度和服务质量,尤其是在面对大量短时间交互频繁的任务集合时候效果尤为明显。不过需要注意的是,由于每次轮询都需要消耗一定计算能力,因此实际部署过程中还需要权衡效率与能耗之间的关系。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值