<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Socket 中文翻譯叫通訊端,可能很多工作四五年的同學都沒有用過這個 API,但只要用到這個 API 時,必然是在重要的工程的核心程式碼處。
大家平時基本都在用開源的各種 rpc 框架,比如說 Dubbo、gRPC、Spring Cloud 等等,很少需要手寫網路呼叫,以下三小節可以幫助大家補充這塊的內容,當你真正需要的時候,可以作為手冊範例。
本文和《ServerSocket 原始碼及面試題》一文主要說 Socket 和 ServerSocket 的原始碼,《工作實戰:Socket 結合執行緒池的使用》這章主要說兩個 API 在實際工作中如何落地。
Socket 的結構非常簡單,Socket 就像一個殼一樣,將通訊端初始化、建立連線等各種操作包裝了一下,其底層實現都是 SocketImpl 實現的,Socket 本身的業務邏輯非常簡單。
Socket 的屬性不多,有通訊端的狀態,SocketImpl,讀寫的狀態等等,原始碼如下圖:
通訊端的狀態變更都是有對應操作方法的,比如通訊端新建(createImpl 方法)後,狀態就會更改成 created = true,連線(connect)之後,狀態更改成 connected = true 等等。
Socket 的構造器比較多,可以分成兩大類:
指定代理型別(Proxy)建立套節點,一共有三種型別為:DIRECT(直連)、HTTP(HTTP、FTP 高階協定的代理)、SOCKS(SOCKS 代理),三種不同的程式碼方式對應的 SocketImpl 不同,分別是:PlainSocketImpl、HttpConnectSocketImpl、SocksSocketImpl,除了型別之外 Proxy 還指定了地址和埠;
預設 SocksSocketImpl 建立,並且需要在構造器中傳入地址和埠,原始碼如下:
// address 代表IP地址,port 表示通訊端的埠 // address 我們一般使用 InetSocketAddress,InetSocketAddress 有 ip+port、域名+port、InetAddress 等初始化方式 public Socket(InetAddress address, int port) throws IOException { this(address != null ? new InetSocketAddress(address, port) : null, (SocketAddress) null, true); }
這裡的 address 可以是 ip 地址或者域名,比如說 127.0.0.1 或者 www.wenhe.com。
我們一起看一下這個構造器呼叫的 this 底層構造器的原始碼:
// stream 為 true 時,表示為stream socket 流通訊端,使用 TCP 協定,比較穩定可靠,但佔用資源多 // stream 為 false 時,表示為datagram socket 資料包通訊端,使用 UDP 協定,不穩定,但佔用資源少 private Socket(SocketAddress address, SocketAddress localAddr, boolean stream) throws IOException { setImpl(); // backward compatibility if (address == null) throw new NullPointerException(); try { // 建立 socket createImpl(stream); // 如果 ip 地址不為空,繫結地址 if (localAddr != null) // create、bind、connect 也是 native 方法 bind(localAddr); connect(address); } catch (IOException | IllegalArgumentException | SecurityException e) { try { close(); } catch (IOException ce) { e.addSuppressed(ce); } throw e; } }
從原始碼中可以看出:
connect 方法主要用於 Socket 使用者端連線上伺服器端,如果底層是 TCP 層協定的話,就是通過三次握手和伺服器端建立連線,為使用者端和伺服器端之間的通訊做好準備,底層原始碼如下:
public void connect(SocketAddress endpoint, int timeout) throws IOException { }
connect 方法要求有兩個入參,第一個入參是 SocketAddress,表示伺服器端的地址,我們可以使用 InetSocketAddress 進行初始化,比如:new InetSocketAddress(“www.wenhe.com”, 2000)。
第二入參是超時時間的意思(單位毫秒),表示使用者端連線伺服器端的最大等待時間,如果超過當前等待時間,仍然沒有成功建立連線,拋 SocketTimeoutException 異常,如果是 0 的話,表示無限等待。
Socket 的常用設定引數在 SocketOptions 類中都可以找到,接下來我們來一一分析下,以下理解大多來自類註釋和網路。
此方法是用來設定 TCP_NODELAY 屬性的,屬性的註釋是這樣的:此設定僅僅對 TCP 生效,主要為了禁止使用 Nagle 演演算法,true 表示禁止使用,false 表示使用,預設是 false。
對於 Nagle 演演算法,我們參照維基百科上的解釋:
納格演演算法是以減少封包傳送量來增進 [TCP/IP] 網路的效能,它由約翰·納格任職於Ford Aerospace時命名。
納格的檔案[注 1]描述了他所謂的“小封包問題”-某個應用程式不斷地提交小單位的資料,且某些常只佔1位元組大小。因為TCP封包具有40位元組的檔頭資訊(TCP與IPv4各佔20位元組),這導致了41位元組大小的封包只有1位元組的可用資訊,造成龐大的浪費。這種狀況常常發生於Telnet工作階段-大部分的鍵盤操作會產生1位元組的資料並馬上提交。更糟的是,在慢速的網路連線下,這類的封包會大量地在同一時點傳輸,造成壅塞碰撞。
納格演演算法的工作方式是合併(coalescing)一定數量的輸出資料後一次提交。特別的是,只要有已提交的封包尚未確認,傳送者會持續緩衝封包,直到累積一定數量的資料才提交。
總結演演算法開啟關閉的場景:
如果 Nagle 演演算法關閉,對於小封包,比如一次滑鼠移動,點選,使用者端都會立馬和伺服器端互動,實時響應度非常高,但頻繁的通訊卻很佔用不少網路資源;如果 Nagle 演演算法開啟,演演算法會自動合併小封包,等到達到一定大小(MSS)後,才會和伺服器端互動,優點是減少了通訊次數,缺點是實時響應度會低一些。
Socket 建立時,預設是開啟 Nagle 演演算法的,可以根據實時性要求來選擇是否關閉 Nagle 演演算法。
setSoLinger 方法主要用來設定 SO_LINGER 屬性值的。
註釋上大概是這個意思:在我們呼叫 close 方法時,預設是直接返回的,但如果給 SO_LINGER 賦值,就會阻塞 close 方法,在 SO_LINGER 時間內,等待通訊雙方傳送資料,如果時間過了,還未結束,將傳送 TCP RST 強制關閉 TCP 。
我們看一下 setSoLinger 原始碼:
// on 為 false,表示不啟用延時關閉,true 的話表示啟用延時關閉 // linger 為延時的時間,單位秒 public void setSoLinger(boolean on, int linger) throws SocketException { // 檢查是否已經關閉 if (isClosed()) throw new SocketException("Socket is closed"); // 不啟用延時關閉 if (!on) { getImpl().setOption(SocketOptions.SO_LINGER, new Boolean(on)); // 啟用延時關閉,如果 linger 為 0,那麼會立即關閉 // linger 最大為 65535 秒,約 18 小時 } else { if (linger < 0) { throw new IllegalArgumentException("invalid value for SO_LINGER"); } if (linger > 65535) linger = 65535; getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger)); } }
setOOBInline 方法主要使用設定 SO_OOBINLINE 屬性。
註釋上說:如果希望接受 TCP urgent data(TCP 緊急資料)的話,可以開啟該選項,預設該選項是關閉的,我們可以通過 Socket#sendUrgentData 方法來傳送緊急資料。
查詢了很多資料,都建議儘可能的去避免設定該值,禁止使用 TCP 緊急資料。
setSoTimeout 方法主要是用來設定 SO_TIMEOUT 屬性的。
註釋上說:用來設定阻塞操作的超時時間,阻塞操作主要有:
我們必須在必須在阻塞操作之前設定該選項, 如果時間到了,操作仍然在阻塞,會丟擲 InterruptedIOException 異常(Socket 會丟擲 SocketTimeoutException 異常,不同的通訊端丟擲的異常可能不同)。
對於 Socket 來說,超時時間如果設定成 0,表示沒有超時時間,阻塞時會無限等待。
setSendBufferSize 方法主要用於設定 SO_SNDBUF 屬性的,入參是 int 型別,表示設定傳送端(輸出端)的緩衝區的大小,單位是位元組。
入參 size 必須大於 0,否則會丟擲 IllegalArgumentException 異常。
一般我們都是採取預設的,如果值設定太小,很有可能導致網路互動過於頻繁,如果值設定太大,那麼互動變少,實時性就會變低。
setReceiveBufferSize 方法主要用來設定 SO_RCVBUF 屬性的,入參是 int 型別,表示設定接收端的緩衝區的大小,單位是位元組。
入參 size 必須大於 0,否則會丟擲 IllegalArgumentException 異常。
一般來說,在通訊端建立連線之後,我們可以隨意修改視窗大小,但是當視窗大小大於 64k 時,需要注意:
必須在 Socket 連線使用者端之前設定緩衝值;必須在 ServerSocket 繫結本地地址之前設定緩衝值。
setKeepAlive 方法主要用來設定 SO_KEEPALIVE 屬性,主要是用來探測伺服器端的通訊端是否還是存活狀態,預設設定是 false,不會觸發這個功能。
如果 SO_KEEPALIVE 開啟的話,TCP 自動觸發功能:如果兩小時內,使用者端和伺服器端的通訊端之間沒有任何通訊,TCP 會自動傳送 keepalive 探測給對方,對方必須響應這個探測(假設是使用者端傳送給伺服器端),預測有三種情況:
伺服器端使用預期的 ACK 回覆,說明一切正常;伺服器端回覆 RST,表示伺服器端處於宕機或者重啟狀態,終止連線;沒有得到伺服器端的響應(會嘗試多次),表示通訊端已經關閉了。
setReuseAddress 方法主要用來設定 SO_REUSEADDR 屬性,入參是布林值,預設是 false。
通訊端在關閉之後,會等待一段時間之後才會真正的關閉,如果此時有新的通訊端前來繫結同樣的地址和埠時,如果 setReuseAddress 為 true 的話,就可以繫結成功,否則繫結失敗。
如果平時一直在做業務程式碼,Socket 可能用到的很少,但面試問到網路協定時,或者以後有機會做做中介軟體的時候,就會有大概率會接觸到 Socket,所以多學學,作為知識儲備也蠻好的。
以上就是Java程式設計Socket結構常用引數設定原始碼及面試題的詳細內容,更多關於Java程式設計Socket結構常用引數面試的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45