请谨慎使用 avaliable 方法来申请缓冲区
问题
今天开始尝试用 Java 写 http 服务器,开局就遇到 Bug。
我先写了一个多线程的、BIO 的 http 服务器,其中接收请求的部分,会将请求的第一行打印出来。
下面是浏览器发出的请求和控制台的输出情况。我们竟然收到了一个空的请求!!这是为什么呢?


我解析请求的部分代码如下。
// 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);
这是为什么呢?我们先打个断点看看是个什么状况。

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

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

emmm,太迷了。
分析
我们仔细看看上面第二个断点的截图,我们会发现 buffer 的值为 {},这意味着申请的空间是 0!这就意味着 available 返回的是 0。
这个函数的注释中写到,返回一个可以被读取的字节数的估计值。这个估计值并不是实际的长度,在网络请求中,这个值有可能是 0,因此,我们申请的空间就是 0,之后调用 read 方法自然也读不到任何东西。

调用链是这样子的:

解决方法
我们自己开一个固定大小的缓冲区,然后读取就好了,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 方法来申请缓冲区的更多相关文章
- 请谨慎使用 @weakify 和 @strongify
来源:酷酷的哀殿 链接:http://www.jianshu.com/p/d8035216b257 前言 相信大部分见过 @weakify 和 @strongify 的开发者都会喜欢上这两个宏.但是很 ...
- login控件“您的登录尝试不成功。请重试”的解决方法
原文:login控件"您的登录尝试不成功.请重试"的解决方法 遇到login控件“您的登录尝试不成功.请重试”报错之后,在网上找了很久,也按照如下帖子设置了 application ...
- [HMLY]13.请谨慎使用 @weakify 和 @strongify
前言 相信大部分见过 @weakify 和 @strongify 的开发者都会喜欢上这两个宏.但是很多人只知道它的强大威力,却没有意识到在特定环境下的危险性. 本文将通过代码测试的方式告诉读者,如何正 ...
- linux fork进程请谨慎多个进程/线程共享一个 socket连接,会出现多个进程响应串联的情况。
昨天组内同学在使用php父子进程模式的时候遇到了一个比较诡异的问题 简单说来就是:因为fork,父子进程共享了一个redis连接.然后父子进程在发送了各自的redis请求分别获取到了对方的响应体. 复 ...
- 送大家几个cnblogs号,供快捷评论,请谨慎使用
欢迎评论& 3461896724@qq.com互动 可以在我的首页看更多 #1先送大家几个号:(密码都是 MLdlight2020)请区分大小写(可以直接复制) 写过一篇 免费验证码接收网站& ...
- ios更新UI时请尝试使用performSelectorOnMainThread方法
最近开发项目时发现联网获取到数据后,使用通知方式让列表刷新会存在死机的问题. 经过上网查找很多文章,都建议使用异步更新的方式,可是依然崩溃. 最后尝试使用performSelectorOnMainTh ...
- 谨慎重载clone方法
本文涉及到的概念 1.浅拷贝和深拷贝 2..clone方法的作用和使用方式 3.拷贝构造器和拷贝工厂 1.浅拷贝和深拷贝 浅拷贝 一个类实现Cloneable接口,然后,该类的实例调用clone方 ...
- 喜提JDK的BUG一枚!多线程的情况下请谨慎使用这个类的stream遍历。
你好呀,我是歪歪. 前段时间在 RocketMQ 的 ISSUE 里面冲浪的时候,看到一个 pr,虽说是在 RocketMQ 的地盘上发现的,但是这个玩意吧,其实和 RocketMQ 没有任何关系. ...
- 关于discuz“终于解决“头像保存过程中发生网络错误,请重试"”的解决方法
1 php.ini里面allow_url_fopen = On2 将php.ini中的;upload_tmp_dir = 该行的注释符,即前面的分号“:”去掉,使该行在php.ini文档中起作用.up ...
随机推荐
- ceph存储集群的应用
1.ceph存储集群的访问接口 1.1ceph块设备接口(RBD) ceph块设备,也称为RADOS块设备(简称RBD),是一种基于RADOS存储系统支持超配(thin-provisioned). ...
- 如何最简单、通俗地理解Python的文件?
原文链接:https://www.zhihu.com/question/431437471/answer/1588566615 一.笔记 1) Python文件 ① Python文件后缀一般以 .py ...
- Ubuntu使用Nginx 部署你的静态网页
首先使用Putty 登录填写名称 unbutu 然后获取管理员权限 sudo -i 首先更新APT库sudo apt-get updatesudo apt-get upgrade 安装 git,su ...
- 10天,从.Net转Java,并找到月薪2W的工作(一)
大学学的是Java,但是工作一直都是.Net方面的工作. 看到各种各样的大厂都是招Java,工资比.Net高,岗位多.而.Net大多都是维护老系统,传统行业这类的工作.甚至发现工作经验不足我一半的薪水 ...
- Tensorflow2.0-mnist手写数字识别示例
Tensorflow2.0-mnist手写数字识别示例 读书不觉春已深,一寸光阴一寸金. 简介:通过CNN 卷积神经网络训练后识别出手写图片,测试图片mnist数据集中的0.1.2.4. ...
- Tomcat启动web项目静态页面中文乱码问题解决
1 首先查看静态页面在编辑器中是否正常, 如果是eclipse ,需要设置一下项目编码格式为utf-8, 如果是idea , 一般会自动识别, 也可以自己手动检查一下, 检查html上面是否有 ...
- (数据科学学习手札101)funcy:Python中的函数式编程百宝箱
本文示例文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 我们在使用Python完成日常任务时,经常会遇到 ...
- 任意文件上传——tcp
package chaoba; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; ...
- 计算-服务器最大并发量-http协议请求-以webSphere服务器为例-考虑线程池
请求的处理流程 广域网上有大量的并发用户同时访问Web服务器,Web服务器传递请求给应用服务器(Web容器),Web容器传递请求给EJB容器,然后EJB容器发送数据库连接请求给数据库. 请求的处理流程 ...
- promise引用自吕大豹
去年6月份, ES2015正式发布(也就是ES6,ES6是它的乳名),其中Promise被列为正式规范.作为ES6中最重要的特性之一,我们有必要掌握并理解透彻.本文将由浅到深,讲解Promise的基本 ...