日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
JavaSocket超時(shí)淺析

套接字或插座(socket)是一種軟件形式的抽象,用于表達(dá)兩臺(tái)機(jī)器間一個(gè)連接的“終端”。針對(duì)一個(gè)特定的連接,每臺(tái)機(jī)器上都有一個(gè)“套接字”,可以想象它們之間有一條虛擬的“線纜”。JAVA 有兩個(gè)基于數(shù)據(jù)流的套接字類:ServerSocket,服務(wù)器用它“偵聽”進(jìn)入的連接;Socket,客戶端用它初始一次連接。偵聽套接字只能接收新的連接請(qǐng)求,不能接收實(shí)際的數(shù)據(jù)包。

成都創(chuàng)新互聯(lián)公司是專業(yè)的明山網(wǎng)站建設(shè)公司,明山接單;提供網(wǎng)站設(shè)計(jì)、成都網(wǎng)站設(shè)計(jì),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行明山網(wǎng)站開發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!

套接字是基于TCP/IP實(shí)現(xiàn)的,它是用來(lái)提供一個(gè)訪問TCP的服務(wù)接口,或者說(shuō)套接字socket是TCP的應(yīng)用編程接口API,通過(guò)它應(yīng)用層就可以訪問TCP提供的服務(wù)。

在JAVA中,我們用 ServerSocket、Socket類創(chuàng)建一個(gè)套接字連接,從套接字得到的結(jié)果是一個(gè)InputStream以及OutputStream對(duì)象,以便將連接作為一個(gè)IO流對(duì)象對(duì)待。通過(guò)IO流可以從流中讀取數(shù)據(jù)或者寫數(shù)據(jù)到流中,讀寫IO流會(huì)有異常IOException產(chǎn)生。

套接字底層是基于TCP的,所以socket的超時(shí)和TCP超時(shí)是相同的。下面先討論套接字讀寫緩沖區(qū),接著討論連接建立超時(shí)、讀寫超時(shí)以及JAVA套接字編程的嵌套異常捕獲和一個(gè)超時(shí)例子程序的抓包示例。

1、socket讀寫緩沖區(qū)

一旦創(chuàng)建了一個(gè)套接字實(shí)例,操作系統(tǒng)就會(huì)為其分配緩沖區(qū)以存放接收和要發(fā)送的數(shù)據(jù)。

JAVA可以設(shè)置讀寫緩沖區(qū)的大小-setReceiveBufferSize(int size), setSendBufferSize(int size)。

向輸出流寫數(shù)據(jù)并不意味著數(shù)據(jù)實(shí)際上已經(jīng)被發(fā)送,它們只是被復(fù)制到了發(fā)送緩沖區(qū)隊(duì)列SendQ,就是在Socket的OutputStream上調(diào)用 flush()方法,也不能保證數(shù)據(jù)能夠立即發(fā)送到網(wǎng)絡(luò)。真正的數(shù)據(jù)發(fā)送是由操作系統(tǒng)的TCP協(xié)議棧模塊從緩沖區(qū)中取數(shù)據(jù)發(fā)送到網(wǎng)絡(luò)來(lái)完成的。

當(dāng)有數(shù)據(jù)從網(wǎng)絡(luò)來(lái)到時(shí),TCP協(xié)議棧模塊接收數(shù)據(jù)并放入接收緩沖區(qū)隊(duì)列RecvQ,輸入流InputStream通過(guò)read方法從RecvQ中取出數(shù)據(jù)。

2、socket連接建立超時(shí)

socket連接建立是基于TCP的連接建立過(guò)程。TCP的連接需要通過(guò)3次握手報(bào)文來(lái)完成,開始建立TCP連接時(shí)需要發(fā)送同步SYN報(bào)文,然后等待確認(rèn)報(bào)文SYN+ACK,***再發(fā)送確認(rèn)報(bào)文ACK。TCP連接的關(guān)閉通過(guò)4次揮手來(lái)完成,主動(dòng)關(guān)閉TCP連接的一方發(fā)送FIN報(bào)文,等待對(duì)方的確認(rèn)報(bào)文;被動(dòng)關(guān)閉的一方也發(fā)送FIN報(bào)文,然等待確認(rèn)報(bào)文。

正在等待TCP連接請(qǐng)求的一端有一個(gè)固定長(zhǎng)度的連接隊(duì)列,該隊(duì)列中的連接已經(jīng)被TCP接受(即三次握手已經(jīng)完成),但還沒有被應(yīng)用層所接受。TCP接受一個(gè)連接是將其放入這個(gè)連接隊(duì)列,而應(yīng)用層接受連接是將其從該隊(duì)列中移出。應(yīng)用層可以通過(guò)設(shè)置backlog變量來(lái)指明該連接隊(duì)列的***長(zhǎng)度,即已被TCP接受而等待應(yīng)用層接受的***連接數(shù)。

當(dāng)一個(gè)連接請(qǐng)求SYN到達(dá)時(shí),TCP確定是否接受這個(gè)連接。如果隊(duì)列中還有空間,TCP模塊將對(duì)SYN進(jìn)行確認(rèn)并完成連接的建立。但應(yīng)用層只有在三次握手中的第三個(gè)報(bào)文收到后才會(huì)知道這個(gè)新連接。如果隊(duì)列沒有空間,TCP將不理會(huì)收到的SYN。

如果應(yīng)用層不能及時(shí)接受已被TCP接受的連接,這些連接可能占滿整個(gè)連接隊(duì)列,新的連接請(qǐng)求可能不被響應(yīng)而會(huì)超時(shí)。如果一個(gè)連接請(qǐng)求SYN發(fā)送后,一段時(shí)間后沒有收到確認(rèn)SYN+ACK,TCP會(huì)重傳這個(gè)連接請(qǐng)求SYN兩次,每次重傳的時(shí)間間隔加倍,在規(guī)定的時(shí)間內(nèi)仍沒有收到SYN+ACK,TCP將放棄這個(gè)連接請(qǐng)求,連接建立就超時(shí)了。

JAVA Socket連接建立超時(shí)和TCP是相同的,如果TCP建立連接時(shí)三次握手超時(shí),那么導(dǎo)致Socket連接建立也就超時(shí)了??梢栽O(shè)置Socket連接建立的超時(shí)時(shí)間-

connect(SocketAddress endpoint, int timeout)

如果在timeout內(nèi),連接沒有建立成功,在TimeoutException異常被拋出。如果timeout的值小于三次握手的時(shí)間,那么Socket連接永遠(yuǎn)也不會(huì)建立。

不同的應(yīng)用層有不同的連接建立過(guò)程,Socket的連接建立和TCP一樣-僅僅需要三次握手就完成連接,但有些應(yīng)用程序需要交互很多信息后才能成功建立連接,比如Telnet協(xié)議,在TCP三次握手完成后,需要進(jìn)行選項(xiàng)協(xié)商之后,Telnet連接才建立完成。

3、socket讀超時(shí)

如果輸入緩沖隊(duì)列RecvQ中沒有數(shù)據(jù),read操作會(huì)一直阻塞而掛起線程,直到有新的數(shù)據(jù)到來(lái)或者有異常產(chǎn)生。調(diào)用setSoTimeout(int timeout)可以設(shè)置超時(shí)時(shí)間,如果到了超時(shí)時(shí)間仍沒有數(shù)據(jù),read會(huì)拋出一個(gè)SocketTimeoutException,程序需要捕獲這個(gè)異常,但是當(dāng)前的socket連接仍然是有效的。

如果對(duì)方進(jìn)程崩潰、對(duì)方機(jī)器突然重啟、網(wǎng)絡(luò)斷開,本端的read會(huì)一直阻塞下去,這時(shí)設(shè)置超時(shí)時(shí)間是非常重要的,否則調(diào)用read的線程會(huì)一直掛起。

TCP模塊把接收到的數(shù)據(jù)放入RecvQ中,直到應(yīng)用層調(diào)用輸入流的read方法來(lái)讀取。如果RecvQ隊(duì)列被填滿了,這時(shí)TCP會(huì)根據(jù)滑動(dòng)窗口機(jī)制通知對(duì)方不要繼續(xù)發(fā)送數(shù)據(jù),本端停止接收從對(duì)端發(fā)送來(lái)的數(shù)據(jù),直到接收者應(yīng)用程序調(diào)用輸入流的read方法后騰出了空間。

4、socket寫超時(shí)

socket的寫超時(shí)是基于TCP的超時(shí)重傳。超時(shí)重傳是TCP保證數(shù)據(jù)可靠性傳輸?shù)囊粋€(gè)重要機(jī)制,其原理是在發(fā)送一個(gè)數(shù)據(jù)報(bào)文后就開啟一個(gè)計(jì)時(shí)器,在一定時(shí)間內(nèi)如果沒有得到發(fā)送報(bào)文的確認(rèn)ACK,那么就重新發(fā)送報(bào)文。如果重新發(fā)送多次之后,仍沒有確認(rèn)報(bào)文,就發(fā)送一個(gè)復(fù)位報(bào)文RST,然后關(guān)閉TCP連接。***數(shù)據(jù)報(bào)文發(fā)送與復(fù)位報(bào)文傳輸之間的時(shí)間差大約為9分鐘,也就是說(shuō)如果9分鐘內(nèi)沒有得到確認(rèn)報(bào)文,就關(guān)閉連接。但是這個(gè)值是根據(jù)不同的TCP協(xié)議棧實(shí)現(xiàn)而不同。

如果發(fā)送端調(diào)用write持續(xù)地寫出數(shù)據(jù),直到SendQ隊(duì)列被填滿。如果在SendQ隊(duì)列已滿時(shí)調(diào)用write方法,則write將被阻塞,直到 SendQ有新的空閑空間為止,也就是說(shuō)直到一些字節(jié)傳輸?shù)搅私邮照咛捉幼值腞ecvQ中。如果此時(shí)RecvQ隊(duì)列也已經(jīng)被填滿,所有操作都將停止,直到接收端調(diào)用read方法將一些字節(jié)傳輸?shù)綉?yīng)用程序。

當(dāng)Socket的write發(fā)送數(shù)據(jù)時(shí),如果網(wǎng)線斷開、對(duì)端進(jìn)程崩潰或者對(duì)端機(jī)器重啟動(dòng),TCP模塊會(huì)重傳數(shù)據(jù),***超時(shí)而關(guān)閉連接。下次如再調(diào)用write會(huì)導(dǎo)致一個(gè)異常而退出。

Socket寫超時(shí)是基于TCP協(xié)議棧的超時(shí)重傳機(jī)制,一般不需要設(shè)置write的超時(shí)時(shí)間,也沒有提供這種方法。

5、雙重嵌套異常捕獲

如果ServerSocket、Socket構(gòu)造失敗,只需要僅僅捕獲這個(gè)構(gòu)造失敗異常而不需要調(diào)用套接字的close方法來(lái)釋放資源(必須保證構(gòu)造失敗后不會(huì)留下任何需要清除的資源),因?yàn)檫@時(shí)套接字內(nèi)部資源沒有被成功分配。如果構(gòu)造成功,必須進(jìn)入一個(gè)try finally語(yǔ)句塊里調(diào)用close釋放套接字。請(qǐng)參照下面例子程序。

 
 
 
 
  1. import java.net.*;  
  2. import java.io.*;  
  3. public class SocketClientTest  
  4. {  
  5.   public static final int PORT = 8088;  
  6.   public static void main( String[] args ) throws Exception  
  7.   {  
  8.     InetAddress addr = InetAddress.getByName( "127.0.0.1" );  
  9.     Socket socket = new Socket();  
  10.     try 
  11.     {  
  12.       socket.connect( new InetSocketAddress( addr, PORT ), 30000 );  
  13.       socket.setSendBufferSize(100);  
  14.         
  15.       BufferedWriter out = new BufferedWriter( new OutputStreamWriter( socket.getOutputStream() ) );  
  16.       int i = 0;  
  17.         
  18.       while( true )  
  19.       {  
  20.         System.out.println( "client sent --- hello *** " + i++ );  
  21.         out.write( "client sent --- hello *** " + i );  
  22.         out.flush();  
  23.           
  24.         Thread.sleep( 1000 );  
  25.       }  
  26.     }  
  27.     finally 
  28.     {  
  29.       socket.close();  
  30.     }  
  31.   }  
  32. }  
 
 
 
 
  1. import java.io.*;  
  2. import java.net.ServerSocket;  
  3. import java.net.Socket;  
  4. public class SocketServerTest  
  5. {  
  6.   public static final int PORT = 8088;  
  7.   public static final int BACKLOG = 2;  
  8.   public static void main( String[] args ) throws IOException  
  9.   {  
  10.     ServerSocket server = new ServerSocket( PORT, BACKLOG );  
  11.     System.out.println("started: " + server);  
  12.     try 
  13.     {  
  14.       Socket socket = server.accept();  
  15.       try 
  16.       {  
  17.         BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );  
  18.         String info = null;  
  19.           
  20.         while( ( info = in.readLine() ) != null )  
  21.         {  
  22.           System.out.println( info );  
  23.         }  
  24.       }  
  25.       finally 
  26.       {  
  27.         socket.close();  
  28.       }  
  29.     }  
  30.     finally 
  31.     {  
  32.       server.close();  
  33.     }  
  34.   }  

執(zhí)行上面的程序,在程序運(yùn)行一會(huì)兒之后,斷開client和server之間的網(wǎng)絡(luò)連接,在機(jī)器上輸出如下:

Server上的輸出:

Echoing:client sent -----hello0
Echoing:client sent -----hello1
Echoing:client sent -----hello2
Echoing:client sent -----hello3
Echoing:client sent -----hello4
Echoing:client sent -----hello5
Echoing:client sent -----hello6 

---->> 斷開了網(wǎng)絡(luò)連接之后沒有數(shù)據(jù)輸出

Client上的輸出:

socket default timeout = 0
socket = Socket[addr=/10.15.9.99,port=8088,localport=4691]
begin to read
client sent --- hello *** 0
client sent --- hello *** 1
client sent --- hello *** 2
client sent --- hello *** 3
client sent --- hello *** 4
client sent --- hello *** 5
client sent --- hello *** 6
client sent --- hello *** 7
client sent --- hello *** 8 
client sent --- hello *** 9
client sent --- hello *** 10 

---->> 斷開網(wǎng)絡(luò)連接后客戶端進(jìn)程掛起

 
 
 
 
  1. java.net.SocketException : Connection reset by peer: socket write error  
  2.  
  3.     at java.net.SocketOutputStream.socketWrite0( Native Method )  
  4.  
  5.     at java.net.SocketOutputStream.socketWrite( SocketOutputStream.java:92 )  
  6.  
  7.     at java.net.SocketOutputStream.write( SocketOutputStream.java:136 )  
  8.  
  9.     at sun.nio.cs.StreamEncoder.writeBytes( StreamEncoder.java:202 )  
  10.  
  11.     at sun.nio.cs.StreamEncoder.implFlushBuffer( StreamEncoder.java:272 )  
  12.  
  13.     at sun.nio.cs.StreamEncoder.implFlush( StreamEncoder.java:276 )  
  14.  
  15.     at sun.nio.cs.StreamEncoder.flush( StreamEncoder.java:122 )  
  16.  
  17.     at java.io.OutputStreamWriter.flush( OutputStreamWriter.java:212 )  
  18.  
  19.     at java.io.BufferedWriter.flush( BufferedWriter.java:236 )  
  20.  
  21.     at com.xtera.view.SocketClientTest.main( SocketClientTest.java:99 )  

當(dāng)hello6被發(fā)送到server端后,網(wǎng)絡(luò)連接被斷開,這時(shí)server端不能接收任何數(shù)據(jù)而掛起。client端仍然繼續(xù)發(fā)送數(shù)據(jù),實(shí)際上hello7、hello8、hello9、hello10都被復(fù)制到SendQ隊(duì)列中,write方法立即返回。當(dāng)client的SendQ隊(duì)列被填滿之后,write方法就被阻塞。TCP模塊在發(fā)送報(bào)文hello7之后,沒有收到確認(rèn)而超時(shí)重傳,再重傳幾次之后關(guān)閉了TCP連接,同時(shí)導(dǎo)致被阻塞的write方法異常返回。

通過(guò)抓包工具,我們可以看到超時(shí)重傳的報(bào)文。

原文鏈接:http://blog.csdn.net/sureyonder/article/details/5633647


本文題目:JavaSocket超時(shí)淺析
本文URL:http://m.5511xx.com/article/djcjecg.html