JavaSocket的超時淺析是什么

這篇文章將為大家詳細(xì)講解有關(guān)Java Socket的超時淺析是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

為孟州等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及孟州網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都做網(wǎng)站、網(wǎng)站制作、孟州網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!

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

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

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

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

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

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

Java Socket的超時淺析是什么

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ò)來完成的。

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

2、socket連接建立超時

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

Java Socket的超時淺析是什么

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

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

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

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

connect(SocketAddress endpoint, int timeout)

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

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

3、socket讀超時

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

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

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

4、socket寫超時

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

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

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

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

5、雙重嵌套異常捕獲

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

import java.net.*;  import java.io.*;  public class SocketClientTest  {    public static final int PORT = 8088;    public static void main( String[] args ) throws Exception    {      InetAddress addr = InetAddress.getByName( "127.0.0.1" );      Socket socket = new Socket();      try     {        socket.connect( new InetSocketAddress( addr, PORT ), 30000 );        socket.setSendBufferSize(100);                BufferedWriter out = new BufferedWriter( new OutputStreamWriter( socket.getOutputStream() ) );        int i = 0;                while( true )        {          System.out.println( "client sent --- hello *** " + i++ );          out.write( "client sent --- hello *** " + i );          out.flush();                    Thread.sleep( 1000 );        }      }      finally     {        socket.close();      }    }  }
import java.io.*;  import java.net.ServerSocket;  import java.net.Socket;  public class SocketServerTest  {    public static final int PORT = 8088;    public static final int BACKLOG = 2;    public static void main( String[] args ) throws IOException    {      ServerSocket server = new ServerSocket( PORT, BACKLOG );      System.out.println("started: " + server);      try     {        Socket socket = server.accept();        try       {          BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );          String info = null;                    while( ( info = in.readLine() ) != null )          {            System.out.println( info );          }        }        finally       {          socket.close();        }      }      finally     {        server.close();      }    }  }

執(zhí)行上面的程序,在程序運(yùn)行一會兒之后,斷開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)程掛起

java.net.SocketException : Connection reset by peer: socket write error       at java.net.SocketOutputStream.socketWrite0( Native Method )       at java.net.SocketOutputStream.socketWrite( SocketOutputStream.java:92 )       at java.net.SocketOutputStream.write( SocketOutputStream.java:136 )       at sun.nio.cs.StreamEncoder.writeBytes( StreamEncoder.java:202 )       at sun.nio.cs.StreamEncoder.implFlushBuffer( StreamEncoder.java:272 )       at sun.nio.cs.StreamEncoder.implFlush( StreamEncoder.java:276 )       at sun.nio.cs.StreamEncoder.flush( StreamEncoder.java:122 )       at java.io.OutputStreamWriter.flush( OutputStreamWriter.java:212 )       at java.io.BufferedWriter.flush( BufferedWriter.java:236 )       at com.xtera.view.SocketClientTest.main( SocketClientTest.java:99 )

當(dāng)hello6被發(fā)送到server端后,網(wǎng)絡(luò)連接被斷開,這時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ā)送報文hello7之后,沒有收到確認(rèn)而超時重傳,再重傳幾次之后關(guān)閉了TCP連接,同時導(dǎo)致被阻塞的write方法異常返回。

通過抓包工具,我們可以看到超時重傳的報文。

Java Socket的超時淺析是什么

Java Socket的超時淺析是什么

關(guān)于Java Socket的超時淺析是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

網(wǎng)頁名稱:JavaSocket的超時淺析是什么
文章鏈接:http://www.muchs.cn/article2/jpdhoc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站排名、網(wǎng)站營銷響應(yīng)式網(wǎng)站、服務(wù)器托管

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

綿陽服務(wù)器托管