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

Java Socket上的Read操作阻塞問題詳解

 更新時(shí)間:2021年10月27日 11:33:39   作者:fw0124  
這篇文章主要介紹了Java Socket上的Read操作阻塞問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Socket上的Read操作阻塞問題

從Socket上讀取對(duì)端發(fā)過來的數(shù)據(jù)一般有兩種方法

1)按照字節(jié)流讀取

        BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
        int r = -1;
        List<Byte> l = new LinkedList<Byte>();
        while ((r = in.read()) != -1) {
            l.add(Byte.valueOf((byte) r));
        }

2)按照字符流讀取

        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));        
        String s;
        while ((s = in.readLine()) != null) {
            System.out.println("Reveived: " + s);
        }

這兩個(gè)方法read()和readLine()都會(huì)讀取對(duì)端發(fā)送過來的數(shù)據(jù),如果無數(shù)據(jù)可讀,就會(huì)阻塞直到有數(shù)據(jù)可讀?;蛘叩竭_(dá)流的末尾,這個(gè)時(shí)候分別返回-1和null。

這個(gè)特性使得編程非常方便也很高效。

但是這樣也有一個(gè)問題,就是如何讓程序從這兩個(gè)方法的阻塞調(diào)用中返回。

總結(jié)一下,有這么幾個(gè)方法

1)發(fā)送完后調(diào)用Socket的shutdownOutput()方法關(guān)閉輸出流,這樣對(duì)端的輸入流上的read操作就會(huì)返回-1。

注意不能調(diào)用socket.getInputStream().close()。這樣會(huì)導(dǎo)致socket被關(guān)閉。

當(dāng)然如果不需要繼續(xù)在socket上進(jìn)行讀操作,也可以直接關(guān)閉socket。

但是這個(gè)方法不能用于通信雙方需要多次交互的情況。

2)發(fā)送數(shù)據(jù)時(shí),約定數(shù)據(jù)的首部固定字節(jié)數(shù)為數(shù)據(jù)長(zhǎng)度。這樣讀取到這個(gè)長(zhǎng)度的數(shù)據(jù)后,就不繼續(xù)調(diào)用read方法。

3)為了防止read操作造成程序永久掛起,還可以給socket設(shè)置超時(shí)。

如果read()方法在設(shè)置時(shí)間內(nèi)沒有讀取到數(shù)據(jù),就會(huì)拋出一個(gè)java.net.SocketTimeoutException異常。

例如下面的方法設(shè)定超時(shí)3秒。

socket.setSoTimeout(3000);

Socket編程---read方法阻塞問題

java通信項(xiàng)目簡(jiǎn)單寫了個(gè)聊天室,實(shí)現(xiàn)群聊私聊了,就大言不慚地往簡(jiǎn)歷上寫了對(duì)java網(wǎng)絡(luò)編程和多線程有了一定的了解。給客戶端各自開了線程,寫了句server.accept()、Socket client=new Socket("127.0.0.1",9999),就叫了解了? Too young too simple.

然而一問,BIO和NIO有什么區(qū)別?--- 納尼?什么玩意兒?

  • 那你說說你那個(gè)聊天室的流? --- 臥槽,這有什么好說的,get啊,輸入流用來讀的,輸出流用來寫數(shù)據(jù)給對(duì)方的
  • 可能知道我沒get到點(diǎn)吧,那你自己說一下你的通信項(xiàng)目吧 --- 哈哈,先創(chuàng)建一個(gè)ServerSocket對(duì)象,然后accept等客戶端來連,給每個(gè)客戶端都開一個(gè)線程各自處理
  • 奧,你是給每個(gè)客戶端都開了一個(gè)線程啊============ 結(jié)束會(huì)話

聊完了啊,可是我并不知道發(fā)生了什么,這特么到底要問啥啊?,F(xiàn)在一想,可能對(duì)方覺得我特么就是傻缺吧,一個(gè)只會(huì)碼而沒有思想的人。

那不管,先不說BIO和NIO,通過這個(gè),我倒是好像get到他是不是在跟我說流的阻塞問題。那么,總結(jié)一下吧。

講文件流的時(shí)候,我們會(huì)看到這兩個(gè)read方法,看一下API

如果只是使用一次,那么沒有數(shù)據(jù)讀的時(shí)候,會(huì)一直阻塞,然后想執(zhí)行下面那是不可能的了,直到有數(shù)據(jù)可讀;

如果用在while里,那么沒讀到文件末尾,也是一直阻塞的,直到被返回-1。

文件它是自己知道讀到文件末尾了,那么我們的Socket是兩端的通信,一直等待著對(duì)方傳來數(shù)據(jù)的,并不知道啥時(shí)候會(huì)完,所以就會(huì)一直不會(huì)等于-1,阻塞在while循環(huán)里了,下面的代碼就不會(huì)被執(zhí)行。

package SocketIO; 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
 
public class Server { 
	public static void main(String[] args) throws IOException {
		String m = "";
		ServerSocket ss =  new ServerSocket(9999);
		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"...connected...");
		m = ip+"...connected...";
		InputStream in = s.getInputStream();
		int len = 0;
		byte[] buf = new byte[1024];
		while((len=in.read(buf))!=-1){
			m += new String(buf);
		}
		System.out.println(m);
		
		OutputStream out = s.getOutputStream();
		out.write("飯菜馬上到".getBytes());
		out.flush();
		in.close();
		out.close();
		s.close();
		ss.close();
	}
}
package SocketIO; 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException; 
public class Client {
 
	public static void main(String[] args) throws UnknownHostException, IOException {
		Socket s = new Socket("127.0.0.1", 9999);
		OutputStream out = s.getOutputStream();
		out.write("我肚子餓了".getBytes());
		out.flush();
		String m = "";
		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int len = 0;
		while((len=in.read(buf))!=-1){
			m += new String(buf);
		}
		System.out.println(m);
		in.close();
		out.close();
		s.close();
	} 
}

當(dāng)客戶端連接上服務(wù)器時(shí),把“我肚子餓了”寫給服務(wù)器,服務(wù)器讀的時(shí)候不知道客戶端發(fā)沒發(fā)完,就一直阻塞在while循環(huán)里,故服務(wù)器的console只會(huì)輸出

,

而客戶端的console什么也不會(huì)輸出

那么,我們只用加一句,

客戶端寫完數(shù)據(jù)后,就直接把輸出流shutdown,那么服務(wù)器讀到的就會(huì)是-1,跳出循環(huán),繼續(xù)往下執(zhí)行。那為什么服務(wù)器寫完數(shù)據(jù)后不把輸出流shutdown,你沒看見所有的流都close了嗎?客戶端當(dāng)然會(huì)讀到-1,進(jìn)而輸出我們想看到的東東了。如果你還不服,你把close都注釋掉,看看效果(都注釋掉了客戶端讀的時(shí)候又阻塞了),再加上s.shutdownOutput()再看看效果(這會(huì)又恢復(fù)正常了)。

這個(gè)例子其實(shí)只是想說明socket編程中流的read方法是阻塞的。

那么,回到我們的聊天室來,我一個(gè)服務(wù)器要處理這么多個(gè)客戶端,如果一個(gè)客戶端的read方法阻塞了,那別的客戶端不都得等著它嗎?顯然,這是不可能的。那,一個(gè)客戶端給一個(gè)線程吧,讓它們自己阻塞自己的。

對(duì)于服務(wù)器端而言,給每個(gè)客戶端啟動(dòng)一個(gè)線程,然后在每個(gè)客戶端各自的線程里循環(huán)去讀客戶端發(fā)來的數(shù)據(jù),沒的話阻塞等待直到有,有的話轉(zhuǎn)發(fā),所以阻塞在循環(huán)里也無所謂,反正while循環(huán)之外我暫時(shí)也沒想著執(zhí)行。當(dāng)然,還是要把它結(jié)束掉。

對(duì)于服務(wù)器端,先讀后轉(zhuǎn)發(fā),嵌在一個(gè)循環(huán)里,不會(huì)有什么問題。

而對(duì)于客戶端而言,我要隨時(shí)監(jiān)聽去讀,又想著隨時(shí)去寫。那寫的操作不能在讀的循環(huán)里了啊,只能寫在外面。而讀的操作又是一直阻塞著的,豈會(huì)讓出時(shí)間讓你寫?那,大招來了。你把讀的操作放一個(gè)線程里不就得了,由它去阻塞,想怎么讀就怎么讀。那互不影響的話,我也想怎么寫就怎么寫啊。

寫的操作我就不截圖了,就是在主線程里完成的。

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

相關(guān)文章

  • SpringCloud Config統(tǒng)一配置中心問題分析解決與客戶端動(dòng)態(tài)刷新實(shí)現(xiàn)

    SpringCloud Config統(tǒng)一配置中心問題分析解決與客戶端動(dòng)態(tài)刷新實(shí)現(xiàn)

    springcloud config是一個(gè)解決分布式系統(tǒng)的配置管理方案。它包含了 client和server兩個(gè)部分,server端提供配置文件的存儲(chǔ)、以接口的形式將配置文件的內(nèi)容提供出去,client端通過接口獲取數(shù)據(jù)、并依據(jù)此數(shù)據(jù)初始化自己的應(yīng)用
    2022-10-10
  • struts2實(shí)現(xiàn)多文件上傳

    struts2實(shí)現(xiàn)多文件上傳

    這篇文章主要為大家詳細(xì)介紹了struts2實(shí)現(xiàn)多文件上傳,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • 數(shù)據(jù)定位在java購(gòu)物車系統(tǒng)中的應(yīng)用

    數(shù)據(jù)定位在java購(gòu)物車系統(tǒng)中的應(yīng)用

    實(shí)現(xiàn)"加入購(gòu)物車"功能,數(shù)據(jù)定位至關(guān)重要,它通過用戶ID和商品ID等標(biāo)識(shí)符實(shí)現(xiàn)快速查詢和數(shù)據(jù)一致性,主鍵、外鍵和聯(lián)合索引等數(shù)據(jù)庫(kù)技術(shù),以及Redis緩存和并發(fā)控制策略如樂觀鎖或分布式鎖,共同保障了購(gòu)物車系統(tǒng)的查詢效率和數(shù)據(jù)安全,這些機(jī)制對(duì)高并發(fā)和大數(shù)據(jù)量的場(chǎng)景尤為重要
    2024-10-10
  • SpringBoot應(yīng)用啟動(dòng)流程源碼解析

    SpringBoot應(yīng)用啟動(dòng)流程源碼解析

    這篇文章主要介紹了SpringBoot應(yīng)用啟動(dòng)流程源碼解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • SpringBoot從配置文件中獲取屬性的四種方法總結(jié)

    SpringBoot從配置文件中獲取屬性的四種方法總結(jié)

    這篇文章主要介紹了SpringBoot從配置文件中獲取屬性的四種方法總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Java HTTP協(xié)議收發(fā)MQ 消息代碼實(shí)例詳解

    Java HTTP協(xié)議收發(fā)MQ 消息代碼實(shí)例詳解

    這篇文章主要通過實(shí)例代碼為大家詳細(xì)介紹了如何在Java 環(huán)境下使用 HTTP 協(xié)議收發(fā) MQ 消息,需要的朋友可以參考下
    2017-04-04
  • java基礎(chǔ)詳細(xì)筆記之異常處理

    java基礎(chǔ)詳細(xì)筆記之異常處理

    異常是程序中的一些錯(cuò)誤,但并不是所有的錯(cuò)誤都是異常,并且錯(cuò)誤有時(shí)候是可以避免的,下面這篇文章主要給大家介紹了關(guān)于java基礎(chǔ)詳細(xì)筆記之異常處理的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • rocketmq client 日志的問題處理方式

    rocketmq client 日志的問題處理方式

    這篇文章主要介紹了rocketmq client 日志的問題處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • mybatis-plus實(shí)體類中出現(xiàn)非數(shù)據(jù)庫(kù)映射字段解決辦法

    mybatis-plus實(shí)體類中出現(xiàn)非數(shù)據(jù)庫(kù)映射字段解決辦法

    這篇文章主要介紹了mybatis-plus實(shí)體類中出現(xiàn)非數(shù)據(jù)庫(kù)映射字段解決辦法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • 全面剖析java中的注解(Annotation)

    全面剖析java中的注解(Annotation)

    一個(gè)詞就可以描述注解,那就是元數(shù)據(jù),即一種描述數(shù)據(jù)的數(shù)據(jù)。所以,可以說注解就是源代碼的元數(shù)據(jù)。文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評(píng)論

涟水县| 子洲县| 会宁县| 屯昌县| 甘德县| 西乡县| 云林县| 成安县| 集贤县| 迁安市| 凤山市| 永昌县| 桂平市| 四会市| 偃师市| 英德市| 湖北省| 闽清县| 体育| 凯里市| 通江县| 汉寿县| 梨树县| 沙河市| 赤水市| 望奎县| 福海县| 丽水市| 云梦县| 会昌县| 扶风县| 兴义市| 陈巴尔虎旗| 遂溪县| 侯马市| 台前县| 玉田县| 双鸭山市| 天镇县| 会同县| 丰台区|