跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 关于 NIO 网络编程的一个问题
未分類
7 12 月 2020

关于 NIO 网络编程的一个问题

关于 NIO 网络编程的一个问题

資深大佬 : Joker123456789 8

先上代码

ByteBuffer readBuffer = ByteBuffer.allocate(requestSize);// 这里是 1024*1024*1024 = 1G readBuffer.clear();  SocketChannel socketChannel = (SocketChannel) selectionKey.channel();  while (socketChannel.read(readBuffer) > 0) {}  /* 获取请求报文 */ readBuffer.flip(); byte[] bytes = new byte[readBuffer.limit()]; readBuffer.get(bytes); 

如上面代码所示,缓冲区 ByteBuffer 的容量设置成了 1G,但是上传一个 30M 左右的文件,经常会丢包,导致文件不全,然后 formData 解析时报错。

这个缓冲区的容量如果比文件大很多,则一点问题都没,但是我又不能把缓冲区设置的太大,否则会堆溢出。

麻烦熟悉 NIO 的 大神们指点一下

大佬有話說 (13)

  • 資深大佬 : BBCCBB

    这个 read(buf)方法返回 0 也是正常的现象, 各种情况会返回 0, 但是是正常现象, 所以这里这个 while 应该不对

    要自己定一个协议, 数据缓存起来, 只要 read 不是返回-1, 就继续往 buf 里写数据, 直到达到你定义的协议的包的结束点..

    比如定长的协议. |— length– | your data |, eg: 开头 4 个字节代表数据包长度, 读到这么长的数据才算完成读取.

    可以直接用 netty, 看看里面的 LengthFieldBasedFrameDecoder 实现, 直接用 netty 吧. 看懂里面的实现就行.

  • 資深大佬 : BBCCBB

    我百度的返回 0 的情况:

    其实 read 返回 0 有 3 种情况,一是某一时刻 socketChannel 中当前(注意是当前)没有数据可以读,这时会返回 0,其次是 bytebuffer 的 position 等于 limit 了,即 bytebuffer 的 remaining 等于 0,这个时候也会返回 0,最后一种情况就是客户端的数据发送完毕了(注意看后面的程序里有这样子的代码),这个时候客户端想获取服务端的反馈调用了 recv 函数,若服务端继续 read,这个时候就会返回 0 。

  • 主 資深大佬 : Joker123456789

    @BBCCBB 谢谢,我尝试了一下改成 -1,但是 这样一来就一直死循环了,只有强行取消本次请求 才会变成-1,否则到 0 就下不去了,有点头疼。

  • 資深大佬 : sagaxu

    socket 是个 stream,你有两个选择,
    1. 短连接,每次写入完 close,读的读到-1 结束
    2. 长连接,自定义协议确定边界,支持复用

    循环读,-1 就结束,0 继续等待可读通知,遇到边界就解出一个完整报文放入处理队列

  • 主 資深大佬 : Joker123456789

    @sagaxu

    我只能用第二种方案了,因为我是基于 NIO 在开发 http 服务,所以需要等待响应,客户端不能关闭的

    但是第二种方案有个问题,不知道边界如何确定,因为客户端传来的数据是变化多端的。

  • 資深大佬 : laminux29

    1.Buffer 只是个临时缓存,requestSize 没必要等于 file size,不然百度网盘的 SVIP 价格得翻几倍。你下载一个迅雷,以及其他 BT 软件,看看里面的硬盘缓存最大值是多少。

    一般来说 requestSize 的 sizes 是 4k 的倍数,老旧服务端一般是 4/8/16 KB,再有钱的 bat 也最多 1/2MB 。

    2.建议 debug,看看 ByteBuffer.allocate 之后里面到底是什么,有没有必要再做 clear()。

    3.里面很多方法都会抛异常,建议阅读文档,该处理的一定要处理。

    4.while (socketChannel.read(readBuffer) > 0) {} ,这也是没读文档造成的。先不说异常处理,read 方法有几种返回值,认真看一下文档。

    5.重新改正后,先找个 100 字节文档测试一下,java 端收到后立马 write file,然后与 source file 对比一下内容。没问题后再测试 100KB file 、100MB file 甚至几十 GB 的 file 。先 md5 对比,不一样后再找一款基于 byte 对比的软件,比如 BeyondCompare 、TextDiff 甚至 Ultra Edit 。

  • 資深大佬 : zacharyjia

    @Joker123456789 Http 的话,header 里面应该有当前请求的长度,可以根据它判断边界

  • 資深大佬 : cheng6563

    http 一是看 content-length 判断长度,
    如果没有 content-length 则是一行空行表示结束。

  • 資深大佬 : chenshun00

    NIO 开发 http,你这样解析 http 的呀,可以先链接一下 netty 的 http 协议是怎么做的。 这样的读取肯定是不行的.

  • 主 資深大佬 : Joker123456789

    @zacharyjia
    @cheng6563
    @laminux29
    @BBCCBB

    谢谢大佬们,已经解决了,通过查看读到的内容中有没有 rnrn 来判断头读完了没,如果读完了则获取到 Content-Length, 然后继续读 body,再判断已经读到的 body 的长度是否>= Content-Length 。

  • 資深大佬 : lei2j

    为啥不用 netty 呢

  • 主 資深大佬 : Joker123456789

    @lei2j 不想依赖第三方,netty 很好很强大,但是里面我用不到的东西也有很多,不够小。

  • 資深大佬 : shentar

    @Joker123456789 看起来需要用 select 啊,监听读写事件。还是要读一下 netty,jetty 的网络处理部分: https://codefine.site/652.html

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具