Codehighlighting" />

亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Java網(wǎng)絡(luò)編程從入門到精通(18):Socket類的ge

系統(tǒng) 2560 0
本文為原創(chuàng),如需轉(zhuǎn)載,請注明作者和出處,謝謝!


上一篇: Java網(wǎng)絡(luò)編程從入門到精通(17):Socket類的getter和setter方法(1)

二、
用于獲得和設(shè)置 Socket 選項的 getter setter 方法

Socket 選擇可以指定 Socket 類發(fā)送和接受數(shù)據(jù)的方式。在 JDK1.4 中共有 8 Socket 選擇可以設(shè)置。這 8 個選項都定義在 java.net.SocketOptions 接口中。定義如下:


<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> public final static int TCP_NODELAY = 0x0001 ;

public final static int SO_REUSEADDR = 0x04 ;

public final static int SO_LINGER = 0x0080 ;

public final static int SO_TIMEOUT = 0x1006 ;

public final static int SO_SNDBUF = 0x1001 ;

public final static int SO_RCVBUF = 0x1002 ;

public final static int SO_KEEPALIVE = 0x0008 ;

public final static int SO_OOBINLINE = 0x1003 ;

有趣的是,這 8 個選項除了第一個沒在 SO 前綴外,其他 7 個選項都以 SO 作為前綴。其實這個 SO 就是 Socket Option 的縮寫;因此,在 Java 中約定所有以 SO 為前綴的常量都表示 Socket 選項;當(dāng)然,也有例外,如 TCP_NODELAY 。在 Socket 類中為每一個選項提供了一對 get set 方法,分別用來獲得和設(shè)置這些選項。

1. TCP_NODELAY

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> public boolean getTcpNoDelay() throws SocketException
public void setTcpNoDelay( boolean on) throws SocketException

在默認(rèn)情況下,客戶端向服務(wù)器發(fā)送數(shù)據(jù)時,會根據(jù)數(shù)據(jù)包的大小決定是否立即發(fā)送。當(dāng)數(shù)據(jù)包中的數(shù)據(jù)很少時,如只有 1 個字節(jié),而數(shù)據(jù)包的頭卻有幾十個字節(jié)( IP +TCP 頭)時,系統(tǒng)會在發(fā)送之前先將較小的包合并到軟大的包后,一起將數(shù)據(jù)發(fā)送出去。在發(fā)送下一個數(shù)據(jù)包時,系統(tǒng)會等待服務(wù)器對前一個數(shù)據(jù)包的響應(yīng),當(dāng)收到服務(wù)器的響應(yīng)后,再發(fā)送下一個數(shù)據(jù)包,這就是所謂的 Nagle 算法;在默認(rèn)情況下, Nagle 算法是開啟的。

這種算法雖然可以有效地改善網(wǎng)絡(luò)傳輸?shù)男剩珜τ诰W(wǎng)絡(luò)速度比較慢,而且對實現(xiàn)性的要求比較高的情況下(如游戲、 Telnet 等),使用這種方式傳輸數(shù)據(jù)會使得客戶端有明顯的停頓現(xiàn)象。因此,最好的解決方案就是需要 Nagle 算法時就使用它,不需要時就關(guān)閉它。而使用 setTcpToDelay 正好可以滿足這個需求。當(dāng)使用 setTcpNoDelay(true) Nagle 算法關(guān)閉后,客戶端每發(fā)送一次數(shù)據(jù),無論數(shù)據(jù)包的大小都會將這些數(shù)據(jù)發(fā)送出去。

2. SO_REUSEADDR

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> public boolean getReuseAddress() throws SocketException
public void setReuseAddress( boolean on) throws SocketException

通過這個選項,可以使多個 Socket 對象綁定在同一個端口上。其實這樣做并沒有多大意義,但當(dāng)使用 close 方法關(guān)閉 Socket 連接后, Socket 對象所綁定的端口并不一定馬上釋放;系統(tǒng)有時在 Socket 連接關(guān)閉才會再確認(rèn)一下是否有因為延遲面未到達的數(shù)據(jù)包,這完全是在底層處理的,也就是說對用戶是透明的;因此,在使用 Socket 類時完全不會感覺到。

這種處理機制對于隨機綁定端口的 Socket 對象沒有什么影響,但對于綁定在固定端口的 Socket 對象就可能會拋出 “Address already in use: JVM_Bind” 例外。因此,使用這個選項可以避免個例外的發(fā)生。

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> package mynet;

import java.net. * ;
import java.io. * ;

public class Test
{
public static void main(String[]args)
{
Socketsocket1
= new Socket();
Socketsocket2
= new Socket();
try
{
socket1.setReuseAddress(
true );
socket1.bind(
new InetSocketAddress( " 127.0.0.1 " , 88 ));
System.out.println(
" socket1.getReuseAddress(): "
+ socket1.getReuseAddress());
socket2.bind(
new InetSocketAddress( " 127.0.0.1 " , 88 ));
}
catch (Exceptione)
{
System.out.println(
" error: " + e.getMessage());
try
{
socket2.setReuseAddress(
true );
socket2.bind(
new InetSocketAddress( " 127.0.0.1 " , 88 ));
System.out.println(
" socket2.getReuseAddress(): "
+ socket2.getReuseAddress());
System.out.println(
" 端口88第二次綁定成功! " );
}
catch (Exceptione1)
{
System.out.println(e.getMessage());
}
}
}
}

上面的代碼的運行結(jié)果如下:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> socket1.getReuseAddress():true
error:Addressalreadyinuse:JVM_Bind
socket2.getReuseAddress():true
端口88第二次綁定成功!

使用SO_REUSEADDR選項時有兩點需要注意:
1. 必須在調(diào)用bind方法之前使用setReuseAddress方法來打開SO_REUSEADDR選項。因此,要想使用SO_REUSEADDR選項,就不能通過Socket類的構(gòu)造方法來綁定端口。
2. 必須將綁定同一個端口的所有的Socket對象的SO_REUSEADDR選項都打開才能起作用。如在例程4-12中,socket1和socket2都使用了setReuseAddress方法打開了各自的SO_REUSEADDR選項。

3. SO_LINGER

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> public int getSoLinger() throws SocketException
public void setSoLinger( boolean on, int linger) throws SocketException

這個 Socket 選項可以影響 close 方法的行為。在默認(rèn)情況下,當(dāng)調(diào)用 close 方法后,將立即返回;如果這時仍然有未被送出的數(shù)據(jù)包,那么這些數(shù)據(jù)包將被丟棄。如果將 linger 參數(shù)設(shè)為一個正整數(shù) n (n 的值最大是 65,535) ,在調(diào)用 close 方法后,將最多被阻塞 n 秒。在這 n 秒內(nèi),系統(tǒng)將盡量將未送出的數(shù)據(jù)包發(fā)送出去;如果超過了 n 秒,如果還有未發(fā)送的數(shù)據(jù)包,這些數(shù)據(jù)包將全部被丟棄;而 close 方法會立即返回。如果將 linger 設(shè)為 0 ,和關(guān)閉 SO_LINGER 選項的作用是一樣的。

如果底層的 Socket 實現(xiàn)不支持 SO_LINGER 都會拋出 SocketException 例外。當(dāng)給 linger 參數(shù)傳遞負數(shù)值時, setSoLinger 還會拋出一個 IllegalArgumentException 例外。可以通過 getSoLinger 方法得到延遲關(guān)閉的時間,如果返回 -1 ,則表明 SO_LINGER 是關(guān)閉的。例如,下面的代碼將延遲關(guān)閉的時間設(shè)為 1 分鐘:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> if (socket.getSoLinger() == - 1 )socket.setSoLinger( true , 60 );

4. SO_TIMEOUT

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> public int getSoTimeout() throws SocketException
public void setSoTimeout( int timeout) throws SocketException

這個 Socket 選項在前面已經(jīng)討論過。可以通過這個選項來設(shè)置讀取數(shù)據(jù)超時。當(dāng)輸入流的 read 方法被阻塞時,如果設(shè)置 timeout timeout 的單位是毫秒),那么系統(tǒng)在等待了 timeout 毫秒后會拋出一個 InterruptedIOException 例外。在拋出例外后,輸入流并未關(guān)閉,你可以繼續(xù)通過 read 方法讀取數(shù)據(jù)。

如果將 timeout 設(shè)為 0 ,就意味著 read 將會無限等待下去,直到服務(wù)端程序關(guān)閉這個 Socket 。這也是 timeout 的默認(rèn)值。如下面的語句將讀取數(shù)據(jù)超時設(shè)為 30 秒:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> socket1.setSoTimeout( 30 * 1000 );

當(dāng)?shù)讓拥? Socket 實現(xiàn)不支持 SO_TIMEOUT 選項時,這兩個方法將拋出 SocketException 例外。不能將 timeout 設(shè)為負數(shù),否則 setSoTimeout 方法將拋出 IllegalArgumentException 例外。

5. SO_SNDBUF

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> public int getSendBufferSize() throws SocketException
public void setSendBufferSize( int size) throws SocketException

在默認(rèn)情況下,輸出流的發(fā)送緩沖區(qū)是 8096 個字節(jié)( 8K )。這個值是 Java 所建議的輸出緩沖區(qū)的大小。如果這個默認(rèn)值不能滿足要求,可以用 setSendBufferSize 方法來重新設(shè)置緩沖區(qū)的大小。但最好不要將輸出緩沖區(qū)設(shè)得太小,否則會導(dǎo)致傳輸數(shù)據(jù)過于頻繁,從而降低網(wǎng)絡(luò)傳輸?shù)男省?

如果底層的 Socket 實現(xiàn)不支持 SO_SENDBUF 選項,這兩個方法將會拋出 SocketException 例外。必須將 size 設(shè)為正整數(shù),否則 setSendBufferedSize 方法將拋出 IllegalArgumentException 例外。

6. SO_RCVBUF


<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> public int getReceiveBufferSize() throws SocketException
public void setReceiveBufferSize( int size) throws SocketException

在默認(rèn)情況下,輸入流的接收緩沖區(qū)是 8096 個字節(jié)( 8K )。這個值是 Java 所建議的輸入緩沖區(qū)的大小。如果這個默認(rèn)值不能滿足要求,可以用 setReceiveBufferSize 方法來重新設(shè)置緩沖區(qū)的大小。但最好不要將輸入緩沖區(qū)設(shè)得太小,否則會導(dǎo)致傳輸數(shù)據(jù)過于頻繁,從而降低網(wǎng)絡(luò)傳輸?shù)男省?

如果底層的 Socket 實現(xiàn)不支持 SO_RCVBUF 選項,這兩個方法將會拋出 SocketException 例外。必須將 size 設(shè)為正整數(shù),否則 setReceiveBufferSize 方法將拋出 IllegalArgumentException 例外。

7. SO_KEEPALIVE

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> public boolean getKeepAlive() throws SocketException
public void setKeepAlive( boolean on) throws SocketException

如果將這個 Socket 選項打開,客戶端 Socket 每隔段的時間(大約兩個小時)就會利用空閑的連接向服務(wù)器發(fā)送一個數(shù)據(jù)包。這個數(shù)據(jù)包并沒有其它的作用,只是為了檢測一下服務(wù)器是否仍處于活動狀態(tài)。如果服務(wù)器未響應(yīng)這個數(shù)據(jù)包,在大約 11 分鐘后,客戶端 Socket 再發(fā)送一個數(shù)據(jù)包,如果在 12 分鐘內(nèi),服務(wù)器還沒響應(yīng),那么客戶端 Socket 將關(guān)閉。如果將 Socket 選項關(guān)閉,客戶端 Socket 在服務(wù)器無效的情況下可能會長時間不會關(guān)閉。 SO_KEEPALIVE 選項在默認(rèn)情況下是關(guān)閉的,可以使用如下的語句將這個 SO_KEEPALIVE 選項打開:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> socket1.setKeepAlive( true );

8. SO_OOBINLINE

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> public boolean getOOBInline() throws SocketException
public void setOOBInline( boolean on) throws SocketException

如果這個 Socket 選項打開,可以通過 Socket 類的 sendUrgentData 方法向服務(wù)器發(fā)送一個單字節(jié)的數(shù)據(jù)。這個單字節(jié)數(shù)據(jù)并不經(jīng)過輸出緩沖區(qū),而是立即發(fā)出。雖然在客戶端并不是使用 OutputStream 向服務(wù)器發(fā)送數(shù)據(jù),但在服務(wù)端程序中這個單字節(jié)的數(shù)據(jù)是和其它的普通數(shù)據(jù)混在一起的。因此,在服務(wù)端程序中并不知道由客戶端發(fā)過來的數(shù)據(jù)是由 OutputStream 還是由 sendUrgentData 發(fā)過來的。下面是 sendUrgentData 方法的聲明:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> public void sendUrgentData( int data) throws IOException

雖然 sendUrgentData 的參數(shù) data int 類型,但只有這個 int 類型的低字節(jié)被發(fā)送,其它的三個字節(jié)被忽略。下面的代碼 演示了如何使用 SO_OOBINLINE 選項來發(fā)送單字節(jié)數(shù)據(jù)。

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> package mynet;

import java.net. * ;
import java.io. * ;

class Server
{
public static void main(String[]args) throws Exception
{
ServerSocketserverSocket
= new ServerSocket( 1234 );
System.out.println(
" 服務(wù)器已經(jīng)啟動,端口號:1234 " );
while ( true )
{
Socketsocket
= serverSocket.accept();
socket.setOOBInline(
true );
InputStreamin
= socket.getInputStream();
InputStreamReaderinReader
= new InputStreamReader(in);
BufferedReaderbReader
= new BufferedReader(inReader);
System.out.println(bReader.readLine());
System.out.println(bReader.readLine());
socket.close();
}
}
}
public class Client
{
public static void main(String[]args) throws Exception
{
Socketsocket
= new Socket( " 127.0.0.1 " , 1234 );
socket.setOOBInline(
true );
OutputStreamout
= socket.getOutputStream();
OutputStreamWriteroutWriter
= new OutputStreamWriter(out);
outWriter.write(
67 ); // 向服務(wù)器發(fā)送字符"C"
outWriter.write( " helloworld\r\n " );
socket.sendUrgentData(
65 ); // 向服務(wù)器發(fā)送字符"A"
socket.sendUrgentData( 322 ); // 向服務(wù)器發(fā)送字符"B"
outWriter.flush();
socket.sendUrgentData(
214 ); // 向服務(wù)器發(fā)送漢字”中”
socket.sendUrgentData( 208 );
socket.sendUrgentData(
185 ); // 向服務(wù)器發(fā)送漢字”國”
socket.sendUrgentData( 250 );
socket.close();
}
}

由于運行上面的代碼 需要一個服務(wù)器類,因此,在 加了一個類名為 Server 的服務(wù)器類,關(guān)于服務(wù)端套接字的使用方法將會在后面的文章中詳細討論。在類 Server類 中只使用了 ServerSocket 類的 accept 方法接收客戶端的請求。并 從客戶端傳來的數(shù)據(jù)中讀取兩行字符串,并顯示在控制臺上。

測試

由于本例使用了 127.0.0.1 ,因Server Client類 必須在同一臺機器上運行。

運行 Server

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> javamynet.Server

運行 Client

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> javamynet.Client

在服務(wù)端控制臺的輸出結(jié)果

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> 服務(wù)器已經(jīng)啟動,端口號: 1234
ABChelloworld
中國

在ClienT類中使用了 sendUrgentData 方法向服務(wù)器發(fā)送了字符 'A'(65) 'B'(66) 。但發(fā)送'B'時 實際發(fā)送的是 322 ,由于 sendUrgentData 只發(fā)送整型數(shù)的低字節(jié)。因此,實際發(fā)送的是 66 。十進制整型 322 的二進制形式如圖 1 所示。

圖1 十進制整型322的二進制形式

從圖1可以看出,雖然322分布在了兩個字節(jié)上,但它的低字節(jié)仍然是66。

在Client類中使用 flush 將緩沖區(qū)中的數(shù)據(jù)發(fā)送到服務(wù)器。我們可以從輸出結(jié)果發(fā)現(xiàn)一個問題,在Client類中 先后向服務(wù)器發(fā)送了 'C' "hello world"r"n" 'A' 'B' 。而在服務(wù)端程序的控制臺上顯示的卻是 ABChello world 。這種現(xiàn)象說明使用 sendUrgentData 方法發(fā)送數(shù)據(jù)后,系統(tǒng)會立即將這些數(shù)據(jù)發(fā)送出去;而使用 write 發(fā)送數(shù)據(jù),必須要使用 flush 方法才會真正發(fā)送數(shù)據(jù)。

在Client類中 向服務(wù)器發(fā)送 " 中國 " 字符串。由于 " " 是由 214 208 兩個字節(jié)組成的;而 " " 是由 185 250 兩個字節(jié)組成的;因此,可分別發(fā)送這四個字節(jié)來傳送 " 中國 " 字符串。

注意: 在使用setOOBInline方法打開SO_OOBINLINE選項時要注意是必須在客戶端和服務(wù)端程序同時使用setOOBInline方法打開這個選項,否則無法命名用sendUrgentData來發(fā)送數(shù)據(jù)。

下一篇: Java網(wǎng)絡(luò)編程從入門到精通(19):套接字(Socket)的異常



國內(nèi)最棒的Google Android技術(shù)社區(qū)(eoeandroid),歡迎訪問!

《銀河系列原創(chuàng)教程》 發(fā)布

《Java Web開發(fā)速學(xué)寶典》 出版,歡迎定購

Java網(wǎng)絡(luò)編程從入門到精通(18):Socket類的getter和setter方法(2)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 欧美精品1区2区 | 免费两性的视频网站 | 国产精品视频免费 | 五月婷婷激情五月 | 天天干天天舔天天射 | 久久综合亚洲一区二区三区 | 麻豆国产在线观看一区二区 | 麻豆69 | 久久国产美女免费观看精品 | 国产成人精品一区二三区在线观看 | 日本制服丝袜在线 | 欧美精品一区二区在线观看 | 四虎永久免费在线 | 国产精品亚洲专区在线观看 | 国内精品伊人久久久久7777人 | 人人综合 | 婷婷色中文字幕 | 亚洲欧美日产综合一区二区三区 | 毛片链接| 亚洲精品综合欧美一区二区三区 | 毛片免费观看成人 | 亚洲图片一区二区 | 国产麻豆精品在线 | 亚洲精品久久婷婷爱久久婷婷 | 久久综合97色综合网 | 国产精品久久久久999 | 亚洲一区二区日韩欧美gif | 亚洲欧美片 | 欧美成成人免费 | 九天玄帝诀免费完整观看 | 欧美成人午夜视频在线观看 | 欧美日韩成人在线 | 米奇影院7777 | 久久96国产精品久久久 | 亚欧洲精品在线视频免费观看 | 亚洲精彩视频在线观看 | 99精品国产三级在线观看 | a毛片在线播放 | 亚洲激情视频网 | 久久久久久天天夜夜天天 | 欧美日韩三区 |