请谨慎使用 avaliable 方法来申请缓冲区
2024-09-08 06:16:01
问题
今天开始尝试用 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 来做,如果过了一段时间还没有读入数据,那就不读了。比较稳妥的方法是,在请求头里面写好长度,这样就能知道要读多少了。
最新文章
- nginx反向代理+集群
- tool list
- 十步让 WebForm项目 变为 Mvc项目
- U6会计科目导入致对账不平
- linux命令行后台运行与调回
- 前端MVVM框架avalon - 模型转换1
- CentOS 7 安装 Nginx 反向代理 node
- Java KeyTool command
- Spring的声明式事务管理
- 树pao(雾)
- Count(广工14届竞赛)
- Lua程序设计(三)面向对象实现一个简单的类
- pyDay4
- 《剑指offer》第二十五题(合并两个排序的链表)
- linux yum 下载至本地及使用本地缓存安装包
- 传统项目利用Hystrix实现热点接口的服务隔离
- Eclipse在线安装hibernate tools插件
- 类似hibernate实现sql增删改错
- 完成了C++作业,本博客现在开始全面记录acm学习历程,真正的acm之路,现在开始
- Codeforces Round #499 (Div. 2)(1011)
热门文章
- svn add . 报错,不能add全部,因为有一些文件已经在版本库中了
- 弱肉强食——《哆啦A梦:大雄的新恐龙》观后感
- 不一样的资产安全 3D 可视化平台
- Java基础进阶:学生管理系统数组方式分包源码实现,教师管理系统集合和数组两种方式源码实现,图书馆管理系统源码实现,现附重难点,代码实现源码,课堂笔记,课后扩展及答案
- [.NET] - 基础知识 - 如何debug一个.NET application
- 容器编排系统K8s之StatefulSet控制器
- [leetcode]355. Design Twitter设计实现一个微博系统
- Mac苹果电脑单片机开发
- web前台界面的两种验证方式
- 熬夜肝了一周!总结了这套对标阿里P8的java秘籍,限时发布3天!