• 欢迎访问开心洋葱网站,在线教程,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站,欢迎加入开心洋葱 QQ群
  • 为方便开心洋葱网用户,开心洋葱官网已经开启复制功能!
  • 欢迎访问开心洋葱网站,手机也能访问哦~欢迎加入开心洋葱多维思维学习平台 QQ群
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏开心洋葱吧~~~~~~~~~~~~~!
  • 由于近期流量激增,小站的ECS没能经的起亲们的访问,本站依然没有盈利,如果各位看如果觉着文字不错,还请看官给小站打个赏~~~~~~~~~~~~~!

请谨慎使用 avaliable 方法来申请缓冲区

其他 楷哥 3022次浏览 0个评论

问题

今天开始尝试用 Java 写 http 服务器,开局就遇到 Bug。

我先写了一个多线程的、BIO 的 http 服务器,其中接收请求的部分,会将请求的第一行打印出来。

下面是浏览器发出的请求和控制台的输出情况。我们竟然收到了一个空的请求!!这是为什么呢?

请谨慎使用 avaliable 方法来申请缓冲区

请谨慎使用 avaliable 方法来申请缓冲区

我解析请求的部分代码如下。

// request
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] buffer = new byte[bis.available()];
int len = bis.read(buffer);
String firstLine = new String(buffer).split("\n")[0];
System.out.println("".equals(firstLine) ? "EMPTY" : firstLine);

这是为什么呢?我们先打个断点看看是个什么状况。

请谨慎使用 avaliable 方法来申请缓冲区

刷新浏览器,重新请求一下试试。惊奇的发现,bug 消失了。。

请谨慎使用 avaliable 方法来申请缓冲区

如果把断点打在后面几行,bug 又出现了。

请谨慎使用 avaliable 方法来申请缓冲区

emmm,太迷了。

分析

我们仔细看看上面第二个断点的截图,我们会发现 buffer 的值为 {},这意味着申请的空间是 0!这就意味着 available 返回的是 0。

这个函数的注释中写到,返回一个可以被读取的字节数的估计值。这个估计值并不是实际的长度,在网络请求中,这个值有可能是 0,因此,我们申请的空间就是 0,之后调用 read 方法自然也读不到任何东西。

请谨慎使用 avaliable 方法来申请缓冲区

调用链是这样子的:

请谨慎使用 avaliable 方法来申请缓冲区

解决方法

我们自己开一个固定大小的缓冲区,然后读取就好了,read 方法会阻塞直到数据流进来。

// request
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] buffer = new byte[BUFFER_SIZE];
int len = bis.read(buffer);
System.out.println(new String(buffer).split("\n")[0]);

那这个方法就没有问题了吗?其实还是有问题的,比如 POST 提交文件的时候,显然文件的大小并不是只有 BUFFER_SIZE 那么小而已。我们还需要想办法来获取一个未知长度的 InputStream。未知长度的处理方法,可以使用 timeout 来做,如果过了一段时间还没有读入数据,那就不读了。比较稳妥的方法是,在请求头里面写好长度,这样就能知道要读多少了。


开心洋葱 , 版权所有丨如未注明 , 均为原创丨未经授权请勿修改 , 转载请注明请谨慎使用 avaliable 方法来申请缓冲区
喜欢 (0)

您必须 登录 才能发表评论!

加载中……