在socket学习中 我们都知道要先创建一个websocket来作为服务器来与客户端建立链接,然后接收客户端发过来的请求的,但在学习过程中 却遇到了输入流在读取客户端发过来的数据时,一直阻塞住,不会执行后续代码的情况。
ServerSocket serverSocket = new ServerSocket(8080);
Socket accept = serverSocket.accept();
InputStream inputStream = accept.getInputStream();
byte[] buf = new byte[1024];
int len;
while ((len = inputStream.read(buf))>0) {
System.out.println(new String(buf, 0, len));
}
inputStream.close();
accept.close();
这里我们用浏览器去请求 http://localhost:8080/ 会发现 浏览器一直在转圈 程序一直在执行 未停下来
后续我们打断点发现 while ((len = inputStream.read(buf))>0) 代码一直卡在这一段 这里就是 inputStream.read 方法阻塞住了
分析:为什么会阻塞住呢 原因在于 我们的服务端会与浏览器(客户端) 建立个传输通道 从客户端读取到请求的信息 但是因为服务端 不清楚
浏览器还会不会发数据过来 所以通道一直未关闭 导致 一直阻塞住 一直在等客户端发数据
优化 :
Socket accept = serverSocket.accept();
InputStream inputStream = accept.getInputStream();
byte[] buf = new byte[1024];
int len;
while (inputStream.available() > 0) {
len = inputStream.read(buf);
System.out.println(new String(buf, 0, len));
}
这里我们用了 inputStream.available() 方法来判断 流输入的 输入情况 这个available方法 在于可以第一次初略获取 数据的大概总字节 然后下次判断时 就会获取到剩下的数据量 如果是数据后续的总量发生了变化 例如 下次判断时 又传输了新数据过来 总量这里也能判断出来
用这个方法也会更加保险 因为available 是不会读取数据的 在这里只是获取个长度 实际读取数据的还是read方法 这样可以保证read方法的正常执行 且不会因为无法判断通道保留情况而阻塞住程序执行(尤其在网络传输中 要注意 上述问题 在本地传输文件这些 其实直接read判断即可 因为文件大小大概率不会改变 )
**InputStream的available()方法的作用是返回此输入流在不受阻塞情况下能读取的字节数。网络流与文件流不同的关键就在于是否“受阻”二字,网络socket流在读取时如果没有内容read()方法是会受阻的,所以从socket初始化的输入流的available也是为零的,所以要read一字节后再使用,这样可用的字节数就等于 available + 1。但文件读取时read()一般是不会受阻的,因为文件流的可用字节数 available = file.length(),而文件的内容长度在创建File对象时就已知了。
所以调用网络流(socket)的available()方法前,一定记得要先调用read()方法,这样才能避免获取为0的不正确情况。
当然为了保证能读取到缓存中的字节数 可以使用下面代码保证read的读取 此情况为针对 建立了连接 但还未开始发数据 即判断完了
int buffLen=0;
while (buffLen==0)
{
buffLen=inputStream.available();
}
或者下面这种方式
do {
len=inputStream.read(buf);
request.append(new String(buf,0,len));
}while (inputStream.available()>0);
当然该段也是我个人的理解 如果有表述上的错误问题 欢迎指正。