摘要:套接字的方法在沒有足夠的空間緩存傳輸的數據時可能阻塞,的方法和的構造函數都會阻塞等待,直到連接建立。連接和寫數據類的構造函數會嘗試根據參數中指定的主機和端口來建立連接,并阻塞等待,直到連接成功建立或發生了系統定義的超時。
Socket的I/O調用可能會因為多種原因阻塞,數據輸入方法read和receive方法在沒有數據可讀時會阻塞。
TCP套接字的write方法在沒有足夠的空間緩存傳輸的數據時可能阻塞,ServerSocket的accept方法和Socket的構造函數都會阻塞等待,直到連接建立。同時,長的信息往返時間,高錯誤率的連接和慢速的(或已發生故障的)服務器,都可能導致需要很長的時間來建立連接。所有這些情況,只有在連接請求得到滿足后這些方法才會返回。
accept、read、receive方法,可以使用Socket類、ServerSocket類和DatagramSocket類的setSoTimeout方法,設置其阻塞的最長時間(以毫秒為單位)。如果在指定時間內這些方法沒有返回,則將拋出一個InterruptedIOException異常。
對于Socket實例,在調用read方法前,還可以使用InputStream的available方法來檢測是否可讀的數據。
連接和寫數據Socket類的構造函數會嘗試根據參數中指定的主機和端口來建立連接,并阻塞等待,直到連接成功建立或發生了系統定義的超時。不過,系統定義的超時時間很長,而Java又沒有提供任何縮短它的方法,要改變這個情況,可以使用Socket類的無參數構造函數,它返回一個沒有建立連接的Socket實例,需要建立連接時,調用該實例的connect方法,并制定一個遠程終端和超時時間(毫秒)。
write方法調用也會阻塞等待,直到最后一個字節成功寫入到TCP實現的本地緩存中。如果可用的緩存空間比要寫入的數據小,在write方法調用返回前,必須把一些數據成功傳輸到連接的另一端。因此,write方法阻塞總時間最終還是取決于接收端的應用程序。Java現在還沒有提供任何方法使write超時或由其他方法打斷的方法。一個可以在Socket實例上發送大量數據的協議可能會無限期地阻塞下去。
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秒內,每次read調用結束后將重新計算剩余的timeout。
關閉套接字網絡協議通常會明確指定了由誰來發起關閉連接。
對于HTTP協議,由于客戶端不知道文件大小,因此是由服務器端發起關閉套接字來指示文件的結束。
調用Socket的close方法將同時終止兩個方向的數據流,一旦一個終端(客戶端或服務端)關閉了套接字,它將無法再發送或接收數據。這就是意味著close方法只能夠在調用者完成通信之后用來給另一端發送信號。
Socket類的shutdownInput和shutdownOutput方法能夠將輸入輸出流相互獨立地關閉,關閉之后,任何沒有發送的數據都將毫無提示地被丟棄,任何想從套接字的輸入流讀取數據的操作都將返回-1。同理,關閉之后,任何嘗試向輸出流寫數據的操作都將拋出一個IOException異常。
在客戶端調用了shutdownOutput之后,它還要從服務器讀取剩余的已經壓縮的字節
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):基于GZIP壓縮算法的壓縮協議"); } 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 } }
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); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/65903.html
摘要:最后,我們會通過對源代碼的剖析深入了解線程池的運行過程和具體設計,真正達到知其然而知其所以然的水平。創建線程池既然線程池是一個類,那么最直接的使用方法一定是一個類的對象,例如。單線程線程池單線程線程 我們一般不會選擇直接使用線程類Thread進行多線程編程,而是使用更方便的線程池來進行任務的調度和管理。線程池就像共享單車,我們只要在我們有需要的時候去獲取就可以了。甚至可以說線程池更棒,...
摘要:線程池技術旨在解決兩個不同的問題在處理大量異步任務時可以提高性能,因為減少了線程的銷毀,新建,切換等消耗性能的操作。線程池還有能力統一管理,調度,監控,調優線程等,還提供了一下基本的統計,比如已完成的任務數量。線程數量,線程池的狀態。 了解ThreadPoolExecutor 先看一下線程池類的類圖關系: showImg(https://segmentfault.com/img/bV3...
摘要:的事件循環一個線程有唯一的一個事件循環。索引就是指否還有需要執行的事件,是否還有請求,關閉事件循環的請求等等。先來看一下定義的定義是在事件循環的下一個階段之前執行對應的回調。雖然是這樣定義的,但是它并不是為了在事件循環的每個階段去執行的。 Node中的事件循環 如果對前端瀏覽器的時間循環不太清楚,請看這篇文章。那么node中的事件循環是什么樣子呢?其實官方文檔有很清楚的解釋,本文先從n...
閱讀 1408·2023-04-26 01:58
閱讀 2282·2021-11-04 16:04
閱讀 1753·2021-08-31 09:42
閱讀 1765·2021-07-25 21:37
閱讀 1066·2019-08-30 15:54
閱讀 2074·2019-08-30 15:53
閱讀 3047·2019-08-29 13:28
閱讀 2687·2019-08-29 10:56