最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java?Socket實(shí)現(xiàn)文件發(fā)送和接收功能以及遇到的Bug問題

 更新時(shí)間:2024年08月12日 08:57:22   作者:I?am?Groot!  
這篇文章主要介紹了Java?Socket實(shí)現(xiàn)文件發(fā)送和接收功能以及遇到的Bug問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Java Socket實(shí)現(xiàn)文件發(fā)送和接收功能

在Java中,如何用Socket實(shí)現(xiàn)文件的發(fā)送和接收功能?

我的第一版代碼

文件發(fā)送:

public void sendFile(String filePath) {//過長(zhǎng)、過多的密文信息直接發(fā)送文件
		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("文件接收結(jié)束!");
			//d_in.close();
			dosOutputStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

上面的寫法的確實(shí)現(xiàn)了文件發(fā)送和接收的功能(Socket初始化這里沒有給出,大家可以自行補(bǔ)充這部分,是可以運(yùn)行的),但是這個(gè)實(shí)現(xiàn)方式存在一個(gè)很致命的問題,就是只能完成一次文件的發(fā)送和接收。

在此之后如果你想再調(diào)用文件的發(fā)送和接收方法,就會(huì)遇到如下"Socket is closed"這個(gè)問題:

為什么會(huì)遇到這一問題

首先肯定是因?yàn)镾ocket被我關(guān)閉了,但我并沒有寫"socket.close();"這樣的代碼呀,為什么還是被關(guān)閉了呢?

我們把注意力放到上面提到的文件發(fā)送的代碼上,注意這一行:

d_out.close();

這里原本的目的是把DataOutputStream給關(guān)閉掉,結(jié)束我們的文件發(fā)送輸出流。

但是當(dāng)我們關(guān)閉DataOutputStream時(shí),Socket也會(huì)隨之關(guān)閉,這便有了后面想再次執(zhí)行sendFile方法時(shí),出現(xiàn)的"Socket is closed"問題。

所以為了能連續(xù)多次地發(fā)送、接收不同的文件,這一行代碼肯定是不能要了。

把這行代碼注釋掉,修改后的代碼為

文件發(fā)送:

public void sendFile(String filePath) {//過長(zhǎng)、過多的密文信息直接發(fā)送文件
		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("文件接收結(jié)束!");
			//d_in.close();
			dosOutputStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

這樣修改后又遇到了新的問題

那就是在接收文件時(shí),發(fā)生了阻塞的現(xiàn)象:

控制臺(tái)就一直卡在“開始接收文件!”這行輸出這里,顯然是因?yàn)槲募邮盏膚hile循環(huán)被卡住了,但剛剛明明沒有這個(gè)問題啊,為什么注釋掉“sendFile”中的d_out.close();會(huì)使得“receiveFile”的while循環(huán)被卡住呢?

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

這篇文章給出了比較好的解答:http://m.fzitv.net/program/325734b3l.htm

原因如下

“只要客戶端的DataOutputStream不close掉,那么服務(wù)端的DataInputStream read就永遠(yuǎn)不等于-1。即使文件的數(shù)據(jù)已經(jīng)傳完了,DataInputStream依舊會(huì)等著客戶端DataOutputStream再傳數(shù)據(jù)過來。最后只能通過判斷文件的的大小來確認(rèn)文件是否已經(jīng)傳輸完成。”

這便是為什么在d_out.close();沒有被注釋前是沒有這個(gè)Bug的:因?yàn)楫?dāng)我們將DataOutputStream close掉時(shí),接收方的while循環(huán)也就結(jié)束了。

所以我們現(xiàn)在可以采用len的實(shí)際長(zhǎng)度來判斷是否已經(jīng)傳輸完成,修改后的代碼如下:

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

即:判斷buf是否被填滿,沒有填滿(len<buf.length)則代表已經(jīng)接收完畢

經(jīng)過測(cè)試,問題解決

最終代碼如下:

文件發(fā)送:

?
public void sendFile(String filePath) {//發(fā)送文件
		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("文件接收結(jié)束!");
			dosOutputStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳談HashMap和ConcurrentHashMap的區(qū)別(HashMap的底層源碼)

    詳談HashMap和ConcurrentHashMap的區(qū)別(HashMap的底層源碼)

    下面小編就為大家?guī)硪黄斦凥ashMap和ConcurrentHashMap的區(qū)別(HashMap的底層源碼)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • 詳解SpringBoot目錄結(jié)構(gòu)劃分

    詳解SpringBoot目錄結(jié)構(gòu)劃分

    代碼目錄結(jié)構(gòu)是一個(gè)在項(xiàng)目開發(fā)中非常重要的部分,本文主要介紹了詳解SpringBoot目錄結(jié)構(gòu)劃分,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-08-08
  • nacos配置實(shí)例權(quán)重不生效問題

    nacos配置實(shí)例權(quán)重不生效問題

    這篇文章主要介紹了nacos配置實(shí)例權(quán)重不生效問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Java InputStream的多種使用詳解

    Java InputStream的多種使用詳解

    這篇文章主要介紹了Java InputStream的多種使用詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Java多線程通信實(shí)現(xiàn)方式詳解

    Java多線程通信實(shí)現(xiàn)方式詳解

    這篇文章主要介紹了Java多線程通信實(shí)現(xiàn)方式詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Java this關(guān)鍵字的引用詳解

    Java this關(guān)鍵字的引用詳解

    每個(gè)類中都有一個(gè)本類的this引用,類似:類名 this;實(shí)例對(duì)象時(shí),this引用指向?qū)ο蟊旧?,其最主要的作用是讓類中的方法可以訪問本類中的另外一個(gè)方法或?qū)傩裕驗(yàn)檎{(diào)用一個(gè)方法或?qū)傩?非類方法/屬性)必須要有實(shí)例
    2022-03-03
  • Java SpringMVC實(shí)現(xiàn)國(guó)際化整合案例分析(i18n)

    Java SpringMVC實(shí)現(xiàn)國(guó)際化整合案例分析(i18n)

    本篇文章主要介紹了Java SpringMVC實(shí)現(xiàn)國(guó)際化整合案例分析(i18n),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Java基礎(chǔ)之JDK1.8新特性lambda表達(dá)式詳解

    Java基礎(chǔ)之JDK1.8新特性lambda表達(dá)式詳解

    函數(shù)式接口有且僅有一個(gè)抽象方法,但是可以有多個(gè)非抽象方法的接口,函數(shù)式接口可以被隱式轉(zhuǎn)換為lambda表達(dá)式,這篇文章主要介紹了Java基礎(chǔ)之lambda表達(dá)式(JDK1.8新特性),需要的朋友可以參考下
    2023-08-08
  • SpringBoot配置數(shù)據(jù)庫(kù)密碼加密的方法

    SpringBoot配置數(shù)據(jù)庫(kù)密碼加密的方法

    由于系統(tǒng)安全的考慮,配置文件中不能出現(xiàn)明文密碼的問題,本文就給大家詳細(xì)介紹下springboot配置數(shù)據(jù)庫(kù)密碼加密的方法,下面話不多說了,來一起看看詳細(xì)的介紹吧,需要的朋友可以參考下
    2023-08-08
  • Java常用類之字符串相關(guān)類使用詳解

    Java常用類之字符串相關(guān)類使用詳解

    String、StringBuilder、StringBuffer類是Java中常用的三個(gè)字符串相關(guān)類。本文將通過示例為大家講解一下他們的用法,需要的可以參考一下
    2022-08-08

最新評(píng)論

旬阳县| 湖北省| 岱山县| 新昌县| 唐海县| 阿勒泰市| 家居| 石嘴山市| 万源市| 锡林郭勒盟| 巧家县| 镇安县| 平顺县| 潼关县| 青岛市| 金阳县| 灵川县| 昌乐县| 南雄市| 图木舒克市| 东乡族自治县| 阳曲县| 盱眙县| 兴仁县| 汾西县| 罗源县| 三明市| 遂溪县| 尖扎县| 贡山| 镇安县| 遂平县| 博乐市| 静乐县| 讷河市| 南涧| 咸宁市| 铜鼓县| 沙河市| 蓝山县| 海南省|