开发者

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

目录
  • Java Socket实现文件发送和接收功能
    • 我的第一版代码
    • 为什么会遇到这一问题
    • 把这行代码注释掉,修改后的代码为
    • 这样修改后又遇到了新的问题
    • 原因如下
    • 经过测试,问题解决
  • 总结

    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.printS编程客栈tackTrace();
    		}
    	}

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

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

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

    为什么会遇到这一问题

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

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

    d_out.close();

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

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

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

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

    文件发送:

    public void sendFile(String filePath) {//过长、过多的密文信息直接发送文件
    		File file = new File(filePath);
            try {
    android        	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();
    		}
    	}

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

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

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

    控制台就一直卡在“开始接收文件!”这行输出这里,显然是因为文件接收的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 =python 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();
    		}
    	}

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜