成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

阻塞、超時和關(guān)閉

focusj / 1001人閱讀

摘要:套接字的方法在沒有足夠的空間緩存?zhèn)鬏數(shù)臄?shù)據(jù)時可能阻塞,的方法和的構(gòu)造函數(shù)都會阻塞等待,直到連接建立。連接和寫數(shù)據(jù)類的構(gòu)造函數(shù)會嘗試根據(jù)參數(shù)中指定的主機(jī)和端口來建立連接,并阻塞等待,直到連接成功建立或發(fā)生了系統(tǒng)定義的超時。

Socket的I/O調(diào)用可能會因為多種原因阻塞,數(shù)據(jù)輸入方法read和receive方法在沒有數(shù)據(jù)可讀時會阻塞。

TCP套接字的write方法在沒有足夠的空間緩存?zhèn)鬏數(shù)臄?shù)據(jù)時可能阻塞,ServerSocket的accept方法和Socket的構(gòu)造函數(shù)都會阻塞等待,直到連接建立。同時,長的信息往返時間,高錯誤率的連接和慢速的(或已發(fā)生故障的)服務(wù)器,都可能導(dǎo)致需要很長的時間來建立連接。所有這些情況,只有在連接請求得到滿足后這些方法才會返回。

accept、read、receive方法,可以使用Socket類、ServerSocket類和DatagramSocket類的setSoTimeout方法,設(shè)置其阻塞的最長時間(以毫秒為單位)。如果在指定時間內(nèi)這些方法沒有返回,則將拋出一個InterruptedIOException異常。

對于Socket實例,在調(diào)用read方法前,還可以使用InputStream的available方法來檢測是否可讀的數(shù)據(jù)。

連接和寫數(shù)據(jù)

Socket類的構(gòu)造函數(shù)會嘗試根據(jù)參數(shù)中指定的主機(jī)和端口來建立連接,并阻塞等待,直到連接成功建立或發(fā)生了系統(tǒng)定義的超時。不過,系統(tǒng)定義的超時時間很長,而Java又沒有提供任何縮短它的方法,要改變這個情況,可以使用Socket類的無參數(shù)構(gòu)造函數(shù),它返回一個沒有建立連接的Socket實例,需要建立連接時,調(diào)用該實例的connect方法,并制定一個遠(yuǎn)程終端和超時時間(毫秒)。

write方法調(diào)用也會阻塞等待,直到最后一個字節(jié)成功寫入到TCP實現(xiàn)的本地緩存中。如果可用的緩存空間比要寫入的數(shù)據(jù)小,在write方法調(diào)用返回前,必須把一些數(shù)據(jù)成功傳輸?shù)竭B接的另一端。因此,write方法阻塞總時間最終還是取決于接收端的應(yīng)用程序。Java現(xiàn)在還沒有提供任何方法使write超時或由其他方法打斷的方法。一個可以在Socket實例上發(fā)送大量數(shù)據(jù)的協(xié)議可能會無限期地阻塞下去。

public class TimelimitEchoProtocol implements Runnable {
    private static final int BUFSIZE = 32;  // Size (bytes) buffer
    private static final String TIMELIMIT = "10000";  // Default limit (ms)
    private static final String TIMELIMITPROP = "Timelimit";  // Thread property
    private static int timelimit;
    private Socket clntSock;
    private Logger logger;
    public TimelimitEchoProtocol(Socket clntSock, Logger logger) {
        this.clntSock = clntSock;
        this.logger = logger;
        // Get the time limit from the System properties or take the default
        timelimit = Integer.parseInt(System.getProperty(TIMELIMITPROP,TIMELIMIT));
    }
    public static void handleEchoClient(Socket clntSock, Logger logger) {
        try {
            // Get the input and output I/O streams from socket
            InputStream in = clntSock.getInputStream();
            OutputStream out = clntSock.getOutputStream();
            int recvMsgSize;                        // Size of received message
            int totalBytesEchoed = 0;               // Bytes received from client
            byte[] echoBuffer = new byte[BUFSIZE];  // Receive buffer
            long endTime = System.currentTimeMillis() + timelimit;
            int timeBoundMillis = timelimit;
            clntSock.setSoTimeout(timeBoundMillis);
            // Receive until client closes connection, indicated by -1
            while ((timeBoundMillis > 0) &&     // catch zero values
                    ((recvMsgSize = in.read(echoBuffer)) != -1)) {
                out.write(echoBuffer, 0, recvMsgSize);
                totalBytesEchoed += recvMsgSize;
                timeBoundMillis = (int) (endTime - System.currentTimeMillis()) ;
                clntSock.setSoTimeout(timeBoundMillis);
            }
            logger.info("Client " + clntSock.getRemoteSocketAddress() +
                    ", echoed " + totalBytesEchoed + " bytes.");
        } catch (IOException ex) {
            logger.log(Level.WARNING, "Exception in echo protocol", ex);
        }
    }
    public void run() {
        handleEchoClient(this.clntSock, this.logger);
    }
}

試圖將總時間限制在10秒內(nèi),每次read調(diào)用結(jié)束后將重新計算剩余的timeout。

關(guān)閉套接字

網(wǎng)絡(luò)協(xié)議通常會明確指定了由誰來發(fā)起關(guān)閉連接。

對于HTTP協(xié)議,由于客戶端不知道文件大小,因此是由服務(wù)器端發(fā)起關(guān)閉套接字來指示文件的結(jié)束。

調(diào)用Socket的close方法將同時終止兩個方向的數(shù)據(jù)流,一旦一個終端(客戶端或服務(wù)端)關(guān)閉了套接字,它將無法再發(fā)送或接收數(shù)據(jù)。這就是意味著close方法只能夠在調(diào)用者完成通信之后用來給另一端發(fā)送信號。

Socket類的shutdownInput和shutdownOutput方法能夠?qū)⑤斎胼敵隽飨嗷オ毩⒌仃P(guān)閉,關(guān)閉之后,任何沒有發(fā)送的數(shù)據(jù)都將毫無提示地被丟棄,任何想從套接字的輸入流讀取數(shù)據(jù)的操作都將返回-1。同理,關(guān)閉之后,任何嘗試向輸出流寫數(shù)據(jù)的操作都將拋出一個IOException異常。

在客戶端調(diào)用了shutdownOutput之后,它還要從服務(wù)器讀取剩余的已經(jīng)壓縮的字節(jié)

public class CompressClient {
    public static final int BUFSIZE = 256;  // Size of read buffer
    public static void main(String[] args) throws IOException {
        if (args.length != 3) { // Test for correct # of args
            throw new IllegalArgumentException("Parameter(s):   ");
        }
        String server = args[0];               // Server name or IP address
        int port = Integer.parseInt(args[1]);  // Server port
        String filename = args[2];             // File to read data from
        // Open input and output file (named input.gz)
        FileInputStream fileIn = new FileInputStream(filename);
        FileOutputStream fileOut = new FileOutputStream(filename + ".gz");
        // Create socket connected to server on specified port
        Socket sock = new Socket(server, port);
        // Send uncompressed byte stream to server
        sendBytes(sock, fileIn);
        // Receive compressed byte stream from server
        InputStream sockIn = sock.getInputStream();
        int bytesRead;                      // Number of bytes read
        byte[] buffer = new byte[BUFSIZE];  // Byte buffer
        while ((bytesRead = sockIn.read(buffer)) != -1) {
            fileOut.write(buffer, 0, bytesRead);
            System.out.print("R");   // Reading progress indicator
        }
        System.out.println();      // End progress indicator line
        sock.close();     // Close the socket and its streams
        fileIn.close();   // Close file streams
        fileOut.close();
    }
    private static void sendBytes(Socket sock, InputStream fileIn)
            throws IOException {
        OutputStream sockOut = sock.getOutputStream();
        int bytesRead;                      // Number of bytes read
        byte[] buffer = new byte[BUFSIZE];  // Byte buffer
        while ((bytesRead = fileIn.read(buffer)) != -1) {
            sockOut.write(buffer, 0, bytesRead);
            System.out.print("W");   // Writing progress indicator
        }
        sock.shutdownOutput();     // Finished sending
    }
}
基于GZIP壓縮算法的壓縮協(xié)議
public class CompressProtocol implements Runnable {
    public static final int BUFSIZE = 1024;   // Size of receive buffer
    private Socket clntSock;
    private Logger logger;
    public CompressProtocol(Socket clntSock, Logger logger) {
        this.clntSock = clntSock;
        this.logger = logger;
    }
    public static void handleCompressClient(Socket clntSock, Logger logger) {
        try {
            // Get the input and output streams from socket
            InputStream in = clntSock.getInputStream();
            GZIPOutputStream out = new GZIPOutputStream(clntSock.getOutputStream());
            byte[] buffer = new byte[BUFSIZE];   // Allocate read/write buffer
            int bytesRead;                       // Number of bytes read
            // Receive until client closes connection, indicated by -1 return
            while ((bytesRead = in.read(buffer)) != -1)
                out.write(buffer, 0, bytesRead);
            out.finish();      // Flush bytes from GZIPOutputStream
            logger.info("Client " + clntSock.getRemoteSocketAddress() + " finished");
        } catch (IOException ex) {
            logger.log(Level.WARNING, "Exception in echo protocol", ex);
        }
        try {  // Close socket
            clntSock.close();
        } catch (IOException e) {
            logger.info("Exception = " +  e.getMessage());
        }
    }
    public void run() {
        handleCompressClient(this.clntSock, this.logger);
    }
}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/65903.html

相關(guān)文章

  • 從0到1玩轉(zhuǎn)線程池

    摘要:提交任務(wù)當(dāng)創(chuàng)建了一個線程池之后我們就可以將任務(wù)提交到線程池中執(zhí)行了。提交任務(wù)到線程池中相當(dāng)簡單,我們只要把原來傳入類構(gòu)造器的對象傳入線程池的方法或者方法就可以了。 我們一般不會選擇直接使用線程類Thread進(jìn)行多線程編程,而是使用更方便的線程池來進(jìn)行任務(wù)的調(diào)度和管理。線程池就像共享單車,我們只要在我們有需要的時候去獲取就可以了。甚至可以說線程池更棒,我們只需要把任務(wù)提交給它,它就會在合...

    darkerXi 評論0 收藏0
  • Java線程池從使用到閱讀源碼(3/10)

    摘要:最后,我們會通過對源代碼的剖析深入了解線程池的運(yùn)行過程和具體設(shè)計,真正達(dá)到知其然而知其所以然的水平。創(chuàng)建線程池既然線程池是一個類,那么最直接的使用方法一定是一個類的對象,例如。單線程線程池單線程線程 我們一般不會選擇直接使用線程類Thread進(jìn)行多線程編程,而是使用更方便的線程池來進(jìn)行任務(wù)的調(diào)度和管理。線程池就像共享單車,我們只要在我們有需要的時候去獲取就可以了。甚至可以說線程池更棒,...

    468122151 評論0 收藏0
  • ThreadPoolExecutor線程池源碼分析

    摘要:線程池技術(shù)旨在解決兩個不同的問題在處理大量異步任務(wù)時可以提高性能,因為減少了線程的銷毀,新建,切換等消耗性能的操作。線程池還有能力統(tǒng)一管理,調(diào)度,監(jiān)控,調(diào)優(yōu)線程等,還提供了一下基本的統(tǒng)計,比如已完成的任務(wù)數(shù)量。線程數(shù)量,線程池的狀態(tài)。 了解ThreadPoolExecutor 先看一下線程池類的類圖關(guān)系: showImg(https://segmentfault.com/img/bV3...

    stormzhang 評論0 收藏0
  • Node中的事件循環(huán)

    摘要:的事件循環(huán)一個線程有唯一的一個事件循環(huán)。索引就是指否還有需要執(zhí)行的事件,是否還有請求,關(guān)閉事件循環(huán)的請求等等。先來看一下定義的定義是在事件循環(huán)的下一個階段之前執(zhí)行對應(yīng)的回調(diào)。雖然是這樣定義的,但是它并不是為了在事件循環(huán)的每個階段去執(zhí)行的。 Node中的事件循環(huán) 如果對前端瀏覽器的時間循環(huán)不太清楚,請看這篇文章。那么node中的事件循環(huán)是什么樣子呢?其實官方文檔有很清楚的解釋,本文先從n...

    lwx12525 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<