【Java 网络编程】客户端 Socket 配置 ( 超时时间 | 端口复用 | Nagle 算法 | 心跳包机制 | 连接关闭机制 | 缓冲区大小 | 性能权重设置 | 紧急数据设置 )
文章目錄
- I 設(shè)置讀取超時(shí)時(shí)間
- II Socket 復(fù)用綁定端口設(shè)置
- III 開(kāi)啟 Nagle 算法 ( 沾包 )
- IV 心跳包機(jī)制
- V 連接關(guān)閉處理
- VI Socket 緊急數(shù)據(jù)內(nèi)斂設(shè)置
- VII Socket 設(shè)置緩沖區(qū)大小
- VIII Socket 連接性能參數(shù)設(shè)置
I 設(shè)置讀取超時(shí)時(shí)間
1. 設(shè)置 Socket 超時(shí)時(shí)間 , 該超時(shí)時(shí)間沒(méi)有實(shí)際的概念 , 用于設(shè)置與阻塞相關(guān)操作的超時(shí)時(shí)間 , TCP 連接中有兩個(gè)需要阻塞的操作 :
- ① 連接服務(wù)器操作 ;
- ② 等待讀取服務(wù)器發(fā)送給客戶端的數(shù)據(jù) ;
連接超時(shí)時(shí)間可以單獨(dú)設(shè)置 , 這里設(shè)置的讀取超時(shí)時(shí)間 ;
2. 單位 : 毫秒 ( ms ) ;
3. 設(shè)置一個(gè)非 0 的超時(shí)時(shí)間 , 當(dāng)與 Socket 對(duì)象關(guān)聯(lián)的 InputStream 輸入流執(zhí)行 read() 操作時(shí) , 其阻塞時(shí)間為這個(gè)超時(shí)時(shí)間 , 如果超過(guò)了該時(shí)間還沒(méi)有收到任何數(shù)據(jù) , 就會(huì)拋出異常 ;
socket.setSoTimeout(3000);II Socket 復(fù)用綁定端口設(shè)置
設(shè)置是否可以復(fù)用 Socket 綁定的地址和端口號(hào) : setReuseAddress( true ) ;
socket.setReuseAddress(true);Socket 連接在建立時(shí) , 會(huì)使用之前綁定本地的 IP 地址和端口號(hào) , 這個(gè)端口號(hào)在使用之后 , 2 分鐘之內(nèi)不允許再次使用 ; 進(jìn)行了該設(shè)置之后 , 可以在連接關(guān)閉之后 , 馬上使用該本地 IP 地址和端口號(hào) ;
III 開(kāi)啟 Nagle 算法 ( 沾包 )
1. 前提 : TCP 發(fā)送數(shù)據(jù)后 , 接收方會(huì)反饋已經(jīng)接受到的數(shù)據(jù) ;
2. 示例 : 客戶端如果向服務(wù)器端發(fā)送 1 字節(jié)數(shù)據(jù) , 服務(wù)器端需要反饋 ACK 信息 , ACK 的命令其大小要比傳輸?shù)臄?shù)據(jù)還要大 , 其消耗要高于實(shí)際的數(shù)據(jù)傳輸消耗 ;
3. Nagle 算法引入 : 為了避免上述情況的消耗 , 便有了 Nagle 算法 ;
- ① 服務(wù)器端處理 : 其原理是接收端接到數(shù)據(jù)后 , 如果數(shù)據(jù)很小 , 那就多接收幾個(gè)數(shù)據(jù) , 然后將反饋信息一起回送給發(fā)送端 ;
- ② 客戶端處理 : 對(duì)應(yīng)的客戶端處理便是一條數(shù)據(jù)發(fā)送之后 , 會(huì)等待服務(wù)器端反饋 , 然后這段時(shí)間內(nèi)如果又有新的數(shù)據(jù)要發(fā)送 , 那么就會(huì)將這些數(shù)據(jù)緩存起來(lái) , 等待前面的數(shù)據(jù)反饋信息回送之后 , 將發(fā)送端緩存的這些數(shù)據(jù)全部發(fā)送出去 ; 這樣就出現(xiàn)了沾包的情況 ;
4. Nagle 算法好處 : Nagle 算法有效的減少了因發(fā)送少量數(shù)據(jù) , 而產(chǎn)生大量的 ACK 回送包的數(shù)據(jù)量 ; 優(yōu)化網(wǎng)絡(luò)帶寬 ;
在需要低延遲傳輸?shù)那闆r下是需要關(guān)閉該算法的 , 該算法會(huì)導(dǎo)致數(shù)據(jù)沾包情況出現(xiàn) ;
socket.setTcpNoDelay(true);IV 心跳包機(jī)制
設(shè)置了 setKeepAlive(true) 之后的效果 : 如果 TCP 連接在 2 小時(shí)之內(nèi)沒(méi)有數(shù)據(jù)傳輸 , 客戶端就會(huì)發(fā)送心跳包 , 服務(wù)器端會(huì)會(huì)送消息 , 如果客戶端沒(méi)有收到服務(wù)器端反饋信息 , 就認(rèn)為該 TCP 連接已經(jīng)斷開(kāi) , 客戶端會(huì)拋出異常信息 ;
//在長(zhǎng)時(shí)間 ( 2 小時(shí) ) 沒(méi)有數(shù)據(jù)交互 , 是否需要發(fā)送心跳包確認(rèn)連接 socket.setKeepAlive(true);V 連接關(guān)閉處理
1. 連接關(guān)閉處理 : 對(duì)于連接關(guān)閉行為處理方式設(shè)置 , 調(diào)用 setSoLinger 函數(shù)設(shè)置 ;
2. 關(guān)閉情況說(shuō)明 : 當(dāng) Socket 對(duì)象調(diào)用 close 方法關(guān)閉連接時(shí) , 有可能緩沖區(qū)中還有數(shù)據(jù)沒(méi)有發(fā)送完成 , 這個(gè)方法就是用于處理這部分緩沖區(qū)數(shù)據(jù)的 ;
3. setSoLinger 函數(shù)原型 :
/*** Enable/disable {@link SocketOptions#SO_LINGER SO_LINGER} with the* specified linger time in seconds. The maximum timeout value is platform* specific.** The setting only affects socket close.** @param on whether or not to linger on.* @param linger how long to linger for, if on is true.* @exception SocketException if there is an error* in the underlying protocol, such as a TCP error.* @exception IllegalArgumentException if the linger value is negative.* @since 1.1* @see #getSoLinger()*/public void setSoLinger(boolean on, int linger) throws SocketException4. setSoLinger 參數(shù)解析 :
- ① boolean on : TCP 連接關(guān)閉處理功能是否打開(kāi) , 默認(rèn)是關(guān)閉的 ( false ) ;
- ② int linger : Socket 調(diào)用 close 方法后 , 需要阻塞等待緩沖區(qū)數(shù)據(jù)發(fā)送的時(shí)間 , 單位毫秒 ;
5. 默認(rèn)狀態(tài) : 如果 boolean on 設(shè)置成false , 不處理連接的緩存數(shù)據(jù) , 調(diào)用 close 會(huì)立刻關(guān)閉連接 , 系統(tǒng)底層會(huì)操作輸出流發(fā)送剩余緩存數(shù)據(jù) , 將緩沖區(qū)中的數(shù)據(jù)發(fā)送給連接對(duì)方 ; 如果設(shè)置 false 不會(huì)產(chǎn)生阻塞操作 ;
6. 開(kāi)啟連接關(guān)閉處理 : setSoLinger( true , 20 ) 情況 , 如果設(shè)置 boolean on 參數(shù)為 true , int linger 參數(shù)設(shè)置一個(gè)大于等于 0 的參數(shù) , 那么在關(guān)閉的時(shí)候 , 阻塞 linger 毫秒 , 之后緩沖區(qū)如果還有數(shù)據(jù) , 就會(huì)被丟棄 , 直接向連接對(duì)方發(fā)送結(jié)束命令 , 無(wú)需經(jīng)過(guò)超時(shí)等待 ;
超時(shí)等待是數(shù)據(jù)達(dá)到對(duì)方并返回的最長(zhǎng)等待時(shí)間 ( MSL ) ;
7. 開(kāi)啟連接關(guān)閉處理 ( 不阻塞 ) : setSoLinger( true , 0 ) 情況 , 如果設(shè)置成 0 , 那么其后果是不阻塞 , 也不讓系統(tǒng)接管輸出流 , 立刻丟棄緩沖區(qū)數(shù)據(jù) , 向?qū)Ψ桨l(fā)送 RST 命令 ;
VI Socket 緊急數(shù)據(jù)內(nèi)斂設(shè)置
//設(shè)置緊急數(shù)據(jù)是否內(nèi)斂 , 默認(rèn)情況時(shí) false 關(guān)閉的 ; socket.setOOBInline(true);
1. 緊急數(shù)據(jù) : 緊急數(shù)據(jù)是 Socket 對(duì)象通過(guò)調(diào)用 sendUrgentData 發(fā)送出去的數(shù)據(jù) ; 該方法參數(shù)是一個(gè) int 值 , 僅有最低的 8 位是有效的 ;
2. 緊急數(shù)據(jù)透明特性 : 緊急數(shù)據(jù)默認(rèn)情況下與上層的數(shù)據(jù)是隔離的 , 如客戶端給服務(wù)器端發(fā)送了一條緊急數(shù)據(jù) , 服務(wù)器端照常接收處理普通數(shù)據(jù) , 其不影響數(shù)據(jù)的接收與處理 , 也不知道客戶端發(fā)送了緊急數(shù)據(jù) ;
3. 接收緊急數(shù)據(jù) : 如果服務(wù)器端想要接收客戶端發(fā)送的緊急數(shù)據(jù) , 那么需要在獲取 Socket 輸入流之前設(shè)置 socket.setOOBInline(true) , 才能在接收數(shù)據(jù)時(shí) , 讀取到緊急數(shù)據(jù) ;
4. 設(shè)置緊急數(shù)據(jù) : setOOBInline 方法設(shè)置緊急數(shù)據(jù)是否內(nèi)斂 , 默認(rèn)情況時(shí) false 關(guān)閉的 ;
5. 適用場(chǎng)景 : 使用緊急數(shù)據(jù)當(dāng)做心跳包 ;
不建議設(shè)置緊急數(shù)據(jù)內(nèi)斂 , 可能會(huì)影響實(shí)際數(shù)據(jù)的正確性 ;
VII Socket 設(shè)置緩沖區(qū)大小
1. 緩沖區(qū)大小設(shè)置包括兩個(gè)緩沖區(qū)設(shè)置 :
- ① 發(fā)送緩沖區(qū)設(shè)置 :
- ② 接收緩沖區(qū)設(shè)置 ;
2. 緩沖區(qū)作用 : 緩沖區(qū)大小默認(rèn) 32 KB , 緩沖區(qū)大小不是要等到有 32 KB 數(shù)據(jù)才進(jìn)行發(fā)送和接收 , 而是如果發(fā)送和接收的數(shù)據(jù)大于 32 KB , 如 33 KB , 就會(huì)將數(shù)據(jù)拆分成兩包 , 32 KB 和 1KB , 然后進(jìn)行發(fā)送和接收操作 ;
注意設(shè)置一定要在連接之前設(shè)置 , 連接后設(shè)置時(shí)無(wú)效的 ;
VIII Socket 連接性能參數(shù)設(shè)置
1. 調(diào)用 Socket 對(duì)象的 setPerformancePreferences 方法 , 設(shè)置連接的性能參數(shù) ; 連接有以下三個(gè)性能參數(shù) :
- ① 連接時(shí)間 ;
- ② 往返延遲 ;
- ③ 帶寬 ;
2. 設(shè)置的是權(quán)重不是具體性能參數(shù) : 設(shè)置的值不是具體的參數(shù) , 而是連接的性能權(quán)重 , 對(duì)哪個(gè)性能要求比較高 ;
3. 連接時(shí)間 : 如果該 Socket 的連接很頻繁 , 連接后傳一個(gè)數(shù)據(jù) , 馬上斷開(kāi) , 這時(shí)候比較看重連接時(shí)間性能 , 此時(shí)可以將第一個(gè)參數(shù)設(shè)置成 10 , 后兩個(gè)參數(shù)設(shè)置成 1 , 表示注重連接時(shí)間性能 ;
//設(shè)置 連接時(shí)間 性能參數(shù)較重要 socket.setPerformancePreferences(10, 1, 1);4. 往返延遲 : 如果開(kāi)發(fā)的是網(wǎng)游服務(wù)器 , 此時(shí)對(duì)延遲很看重 , 這時(shí)候可以將第二個(gè)參數(shù)設(shè)置成比較高的權(quán)重 ;
//設(shè)置 往返延遲 性能參數(shù)較重要 socket.setPerformancePreferences(1, 10, 1);5. 帶寬 : 如果開(kāi)發(fā)的是音視頻服務(wù)器 , 注重帶寬性能 , 此時(shí)需要將第三個(gè)參數(shù)設(shè)置成較高的權(quán)重 ;
//設(shè)置 帶寬 性能參數(shù)較重要 socket.setPerformancePreferences(1, 10, 1);6. 上面的延遲和帶寬的性能是互斥的 , 延遲低 , 就意味著很小的包就要發(fā)送一次 , 其帶寬就低了 , 延遲高了 , 每次積累很多數(shù)據(jù)才發(fā)送 , 其帶寬就相應(yīng)的提高了 ;
7. 函數(shù)原型 :
/*** Sets performance preferences for this socket.** <p> Sockets use the TCP/IP protocol by default. Some implementations* may offer alternative protocols which have different performance* characteristics than TCP/IP. This method allows the application to* express its own preferences as to how these tradeoffs should be made* when the implementation chooses from the available protocols.** <p> Performance preferences are described by three integers* whose values indicate the relative importance of short connection time,* low latency, and high bandwidth. The absolute values of the integers* are irrelevant; in order to choose a protocol the values are simply* compared, with larger values indicating stronger preferences. Negative* values represent a lower priority than positive values. If the* application prefers short connection time over both low latency and high* bandwidth, for example, then it could invoke this method with the values* {@code (1, 0, 0)}. If the application prefers high bandwidth above low* latency, and low latency above short connection time, then it could* invoke this method with the values {@code (0, 1, 2)}.** <p> Invoking this method after this socket has been connected* will have no effect.** @param connectionTime* An {@code int} expressing the relative importance of a short* connection time** @param latency* An {@code int} expressing the relative importance of low* latency** @param bandwidth* An {@code int} expressing the relative importance of high* bandwidth** @since 1.5*/public void setPerformancePreferences(int connectionTime,int latency,int bandwidth) 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的【Java 网络编程】客户端 Socket 配置 ( 超时时间 | 端口复用 | Nagle 算法 | 心跳包机制 | 连接关闭机制 | 缓冲区大小 | 性能权重设置 | 紧急数据设置 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Java 网络编程】TCP 传输机制
- 下一篇: 【Java 网络编程】客户端 Socke