刚刚看关于文件上传的课程,记录自己对于read方法阻塞的理解。如有问题,希望大家指正。
read方法调用后,会阻塞(程序暂停在read方法使用处)。
阻塞后,read方法有多种情况会解除阻塞:
情况如下:
1.检测到有输入数据可用。
一般在使用中,OutputStream.write(),InputStream.read()一一对应,
不会出现阻塞
2.接收到结束标记
A.调用socket类的方法//void shutdownOutput() 禁用此套接字的输出流。
可以在输出流后加上结束标记,使得输入流使用read()函数不会阻塞。
B.FileInoutStresm的read() 在输入文件时,文件末尾自带结束标记。
3.发送的对象被释放(不会报错)
输出流被释放,输入流的read()会返回-1 ,不会阻塞
4.与发送方断开连接(会报错)
譬如:服务器被关闭,客户端的read()会因报错而停止
贴一下我遇到阻塞的代码及阻塞原因
原因:while会一直调用read,read在收不到数据后就会阻塞,不会返回-1
//IPS 是InputStream 对象
while( (len= IPS.read(bytes))!=-1) {
//7.fos是FileOutputStream对象 将接收的数据导入硬盘
fos.write(bytes,0,len);
}
下面是对程序的分析
整个程序中上述阻塞代码相同形式有三处。客户端有两处,服务器一处。
三处只有服务器的那一部分会产生阻塞。
客户端第一处:是对文件的输入,文件读取完会返回-1.
客户端第二处:服务器程序的资源释放后,read()返回-1
服务器处:在客户端程序输出完文件数据后,加上shutdownOutput() ,
人为加上结束标记,解决问题。
服务器程序main函数
public class FileUoloadServer {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//1.创建一个服务器serversocket对象,和系统指定的端口号
ServerSocket sever = new ServerSocket(7777);
//2.使用serversocket对象中的accept方法,获取获取客户端请求的socket
Socket socket = sever.accept();
//3.使用socket对象中的方法getInputStream() 获取网路字节输入流InputStream对象
InputStream IPS = socket.getInputStream();
//4.判断文件夹是否存在,不存在就创建
File file = new File("d:\\upload");
if(!file.exists()) {
file.mkdir();
}
//5.使用本地字节输出流fileoutputstream对象,构造方法绑定输出路径
FileOutputStream fos = new FileOutputStream(file+File.separator+"fileUpload.JPG");
//6.使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件
int len =0;
byte[] bytes = new byte[1024];
while( (len= IPS.read(bytes))!=-1) {
//7.使用本地字节输出流fileoutputstream对象中的write方法,把读取的文件保存到服务器硬盘上
fos.write(bytes,0,len);
}
//8.使用socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象
//9.使用网络字节输出流OutputStream对象中的的方法write,给客户端发送数据。
OutputStream OPS = socket.getOutputStream();
OPS.write("上传成功".getBytes());
//10.释放资源(serversocket/socket/fileoutputstram)
sever.close();
socket.close();
fos.close();
}
}
客户端main函数
public class FileUploadClient {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//1.创建一个本地字节输入流fileinputstream对象,构造方法绑定文件
FileInputStream fis = new FileInputStream("E:\\fileUoload.JPG");
//2.创建一个客户端socket对象,构造方法绑定服务器的ip和端口
Socket soc = new Socket("127.0.0.1",7777);
//3.使用socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象
OutputStream OPS = soc.getOutputStream();
//4.使用本地字节流fileinputstream对象中的read,读取本地文件
int len = 0;
byte[] bytes = new byte[1024];
while( (len= fis.read(bytes))!=-1)
{
//5.使用网络字节输出流OutputStream对象中的的方法write,把读取的文件上传给服务器。
OPS.write(bytes,0,len);
}
//void shutdownOutput() 禁用此套接字的输出流。
soc.shutdownOutput();
//6.使用socket对象中的方法getInputStream() 获取网路字节输入流InputStream对象
InputStream IPS = soc.getInputStream();
while( (len= IPS.read(bytes))!=-1)
{
//7.使用网络字节输入流InputStream对象中的方法read,读取服务器回写的数据
System.out.println(new String(bytes,0,len));
}
//8.释放socket fileinputstream
fis.close();
soc.close();
}
}