java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java Socket实现文件发送和接收

Java Socket实现文件发送和接收功能以及遇到的Bug问题

作者:I am Groot!

这篇文章主要介绍了Java Socket实现文件发送和接收功能以及遇到的Bug问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

Java Socket实现文件发送和接收功能

在Java中,如何用Socket实现文件的发送和接收功能?

我的第一版代码

文件发送:

public void sendFile(String filePath) {//过长、过多的密文信息直接发送文件
		File file = new File(filePath);
        try {
        	DataOutputStream d_out = new DataOutputStream(socket.getOutputStream());
            FileInputStream f_in = new FileInputStream(file);
            int all = 0;
            byte[] buffer = new byte[4096];
            int read = 0;
            while ((read = (f_in.read(buffer))) > 0) {
                d_out.write(buffer, 0, read);
                all += read;
            }
            System.out.println("Send file length: "+all);
            d_out.flush();
            f_in.close();
            d_out.close();//注意这一行
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

文件接收:

public void receiveFile(String filePath) {//接收文件
		try {
			DataOutputStream dosOutputStream = new DataOutputStream(new FileOutputStream(filePath));
			byte[] buf = new byte[4096];
			int len = 0;
			System.out.println("开始接收文件!");
			d_in = new DataInputStream(sock.getInputStream());
			while((len = d_in.read(buf)) != -1) { 
				dosOutputStream.write(buf, 0, len);
			}
			dosOutputStream.flush();
			System.out.println("文件接收结束!");
			//d_in.close();
			dosOutputStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

上面的写法的确实现了文件发送和接收的功能(Socket初始化这里没有给出,大家可以自行补充这部分,是可以运行的),但是这个实现方式存在一个很致命的问题,就是只能完成一次文件的发送和接收。

在此之后如果你想再调用文件的发送和接收方法,就会遇到如下"Socket is closed"这个问题:

为什么会遇到这一问题

首先肯定是因为Socket被我关闭了,但我并没有写"socket.close();"这样的代码呀,为什么还是被关闭了呢?

我们把注意力放到上面提到的文件发送的代码上,注意这一行:

d_out.close();

这里原本的目的是把DataOutputStream给关闭掉,结束我们的文件发送输出流。

但是当我们关闭DataOutputStream时,Socket也会随之关闭,这便有了后面想再次执行sendFile方法时,出现的"Socket is closed"问题。

所以为了能连续多次地发送、接收不同的文件,这一行代码肯定是不能要了。

把这行代码注释掉,修改后的代码为

文件发送:

public void sendFile(String filePath) {//过长、过多的密文信息直接发送文件
		File file = new File(filePath);
        try {
        	DataOutputStream d_out = new DataOutputStream(socket.getOutputStream());
            FileInputStream f_in = new FileInputStream(file);
            int all = 0;
            byte[] buffer = new byte[4096];
            int read = 0;
            while ((read = (f_in.read(buffer))) > 0) {
                d_out.write(buffer, 0, read);
                all += read;
            }
            System.out.println("Send file length: "+all);
            d_out.flush();
            f_in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

文件接收:

public void receiveFile(String filePath) {//接收文件
		try {
			DataOutputStream dosOutputStream = new DataOutputStream(new FileOutputStream(filePath));
			byte[] buf = new byte[4096];
			int len = 0;
			System.out.println("开始接收文件!");
			d_in = new DataInputStream(sock.getInputStream());
			while((len = d_in.read(buf)) != -1) { 
				dosOutputStream.write(buf, 0, len);
			}
			dosOutputStream.flush();
			System.out.println("文件接收结束!");
			//d_in.close();
			dosOutputStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

这样修改后又遇到了新的问题

那就是在接收文件时,发生了阻塞的现象:

控制台就一直卡在“开始接收文件!”这行输出这里,显然是因为文件接收的while循环被卡住了,但刚刚明明没有这个问题啊,为什么注释掉“sendFile”中的d_out.close();会使得“receiveFile”的while循环被卡住呢?

while((len = d_in.read(buf)) != -1) { 
    dosOutputStream.write(buf, 0, len);
}

这篇文章给出了比较好的解答:https://www.jb51.net/program/325734b3l.htm

原因如下

“只要客户端的DataOutputStream不close掉,那么服务端的DataInputStream read就永远不等于-1。即使文件的数据已经传完了,DataInputStream依旧会等着客户端DataOutputStream再传数据过来。最后只能通过判断文件的的大小来确认文件是否已经传输完成。”

这便是为什么在d_out.close();没有被注释前是没有这个Bug的:因为当我们将DataOutputStream close掉时,接收方的while循环也就结束了。

所以我们现在可以采用len的实际长度来判断是否已经传输完成,修改后的代码如下:

while((len = d_in.read(buf)) != -1) { 
    dosOutputStream.write(buf, 0, len);
	if(len < buf.length) break;
}

即:判断buf是否被填满,没有填满(len<buf.length)则代表已经接收完毕

经过测试,问题解决

最终代码如下:

文件发送:

​
public void sendFile(String filePath) {//发送文件
		File file = new File(filePath);
        try {
        	DataOutputStream d_out = new DataOutputStream(socket.getOutputStream());
            FileInputStream f_in = new FileInputStream(file);
            int all = 0;
            byte[] buffer = new byte[4096];
            int read = 0;
            while ((read = (f_in.read(buffer))) > 0) {
                d_out.write(buffer, 0, read);
                all += read;
            }
            System.out.println("Send file length: "+all);
            d_out.flush();
            f_in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

​

文件接收:

public void receiveFile(String filePath) {//接收文件
		try {
			DataOutputStream dosOutputStream = new DataOutputStream(new FileOutputStream(filePath));
			byte[] buf = new byte[4096];
			int len = 0;
			System.out.println("开始接收文件!");
			d_in = new DataInputStream(sock.getInputStream());
			while((len = d_in.read(buf)) != -1) { 
				dosOutputStream.write(buf, 0, len);
                if(len < buf.length) break;
			}
			dosOutputStream.flush();
			System.out.println("文件接收结束!");
			dosOutputStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文