开发者社区> 问答> 正文

怎样使用socketchannel进行精确读取?:报错

使用SocketChannel可以在非阻塞模式下进行读写,每次读取缓存的分配空间,然后等待下一次的读取。我的问题是,假设在某一次server发送的tcp流中,我必须进行两次读写。即第一次读取该流的一部分,剩下的等到下一次再读(区分标记是有一行为空,即读到空行时结束)。这个在代码中应该怎么控制呢?

我知道一种办法就是一次全读进来,然后按自己需求分成两部分,后半部分和下次读进行合并。因为这前半部分和后半部分的处理逻辑不一样(代码中,是解析前半部分的要求然后为后半部分开启线程新建http连接,所以传递起来比较费事)。

SocketChannel对应的socket可以获得InputStream,进而可以获得BufferefReader,进而可以精确读取行。因为程序依赖于Selector.select()查询。所以在把SocketChannel切换为Blocking模式,获得对应socket进行读写一次后,还要将其恢复为non-Blocking模式。具体代码如下:

if (selector.select(getTimeout()) != 0) {
     Iterator<SelectionKey> it = selector.selectedKeys()
       .iterator();
     while (it.hasNext()) {
      SelectionKey key = it.next();
      it.remove();
      if (key.isReadable()) {
       if (key.equals(proxykey)) {
        SocketChannel channel = (SocketChannel) key
          .channel();
        channel.configureBlocking(true);
        InputStream ins = Channels
          .newInputStream(channel);
        InputStreamReader is = new InputStreamReader(
          ins, "utf-8");
        BufferedReader in = new BufferedReader(is);
        String res = in.readLine();
        while (!res.equals("")) {
         System.out.println("========" + res);
         res = in.readLine();
        }
        channel.configureBlocking(false);

       }
      }
     }
    }

方法理论上应该是可以的,但是我实现的有问题,请教大家问题出在哪里,或者进行精确读取的方法

展开
收起
kun坤 2020-06-07 21:24:15 471 0
1 条回答
写回答
取消 提交回答
  • 这个问题解决了吗?

    我也遇到了同样的问题.....

    ######

    引用来自“ijtihat”的答案

    这个问题解决了吗?

    我也遇到了同样的问题.....

    后来就是这样做了,在上面将channel设置为阻塞模式之前,先要取消其对应的SelectionKey:
    key.cancel();
    selector.selectNow();

    在阻塞模式下处理完后,channel重新注册到selector:
    channel.configureBlocking(false);
    channel.register(selector,SelectionKey.OP_READ);


    如果你有一些参数需要带着的话,可以看一下key.attach()方法

    ######在消息中包含消息长度,channel读取时,用一个容量为4字节的bytebuffer读出长度值length,再新建一个容量为length的bytebuffer把消息读到。当然,用同一个bytebuffer设置limit来可以实现一样效果。
    2020-06-07 21:24:19
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载