Socket 網路程式設計實踐經驗

2021-08-10 05:49:16 字數 2916 閱讀 5766

會話過期問題

同步還是非同步問題

資料快取問題

完全斷開連線問題

首先通過對比法來了解兩者不同的特性:

下面列出在生產專案中應用 socket 所需要注意的幾點:

網路斷開重連問題

連線會話和身份認證問題

同步和非同步問題

資料快取問題

完全斷開連線問題

的確,socket 連線在理想的網路環境下是持久的長連線,但實際網路環境是複雜的,網路抖動、路由宕機等各種網路問題都會導致 socket 連線被動斷開。而且 socket 沒有提供「自動重連」的機制,所以解決網路斷開重連問題,是 socket 程式穩定性的重要保證。

思路:在 傳送 和 接收 前檢查 socket 連線是否依然生效,若不生效,則重新建立 socket 連線。

那麼首先需要解決的是:如何判斷 socket 連線狀態是否 active?

note:一般的來說,「判斷 socket 連線狀態是否 active」都是服務端的功能需求,因為服務端需要以此來作為是否**連線資源的依據。而客戶端則無需特別在意,因為即便斷開了連線也只需捕獲異常、重新連線、重新傳送即可。

別名定義

一般的 socket 應用程式邏輯中,ser-socket 應該能夠感知到 cli-socket 的斷開,並且執行相應的斷開邏輯處理,釋放相應的 socket 連線資源。但實際是,ser-socket 無法有效的區分 cli-socket 是處於長時間空閒還是處於 offline 的狀態,所以也無法確定 cli-socket 的連線是否已經斷開。為解決這個問題,程式設計師所提出的思路就是,遮蔽「長時間空閒」的場景,讓 cli-socket 看起來始終是忙碌的(不斷傳送「無用包」),直到其靜默即表示連線斷開。

這就是較為通用的用於保證連線質量的心跳機制,而 cli-socket 傳送的無用包也稱之為心跳包。所謂心跳包就是 cli-socket 定時傳送簡單的協議資訊給 ser-socket,以此讓 ser-socket 知道 cli-socket 依舊 online。相對的, ser-socket 就會認為 cli-socket 已經斷開。注意,發包方可以是 cli-socket 也可以是 ser-socket,但出於效率的考慮(減輕伺服器壓力),一般由 cli-socket 承擔。如果是流式 socket(for tcp),則使用 send 發出;如果是資料報式 socket(for udp),則使用 sendto 發出。還有一點需要說明,心跳包實際是乙個自定義協議包,由開發者制定,並在 cli-socket 和 ser-socket 中遵守。

**note:**如果僅為了確定 ser-socket 是否 online,可以用 tcp 協議自帶的心跳包,應用 socket.socket.setsockopt 的 so_keepalive 屬性,來設定發包時間間隔。so_keepalive 是作業系統的底層機制,用於維護每乙個 tcp 連線。但so_keepalive 並不能用於替代心跳機制,因為其僅能確保 ser-socket 一方的連線狀態。

以非同步(非阻塞)模式建立連線 s.setblocking(0),如果 select 函式返回的值為 1 (表示 socket 可讀),但使用 recv 函式讀取到的資料長度為 0,並且 errno != eintr and errno != eagain,則說明該 socket 已經斷開

note:需要注意的是,在非阻塞模式下,即便 recv 函式的返回值小於等於 0,依舊不足以證明問題。此時還需要繼續判斷 errno ?= eintr,如果 yes,則說明此次 recv 是由於程式接收到 eintr 中斷訊號後返回的,socket 連線仍然正常。除此之外,如果 write 寫的太快,很有可能會把 buffer 寫滿,這時的 errno == eagain。根據實際需要,如果 errno == eagain 的話,建議重試幾次。當然,read 也有類似的情況。

如果服務端程式應用了 session 機制,那麼在實現客戶端程式時除了需要考慮 socket 連線的問題之外,還需要考慮 session 是否過期的問題。

在 傳送 和 接收 前首先檢查連線是否有效,然後檢查會話是否過期:

選擇同步還是非同步模式是非常重要的,使用了錯誤的連線模式將無法達到預期效果。例如高併發需求沒能達到,例如程式的穩定性沒能提高等等,如何進行選擇需要結合實際的應用場景:

note:對於後者,應該盡可以能僅保證 send 和 recv 原子操作是同步的,以此來優化效率。

socket 的 recv 具有快取功能,如果其中一方傳送的資料量超過了另一方 recv 所允許一次接受的最大資料量,資料會被截短,並將剩餘的資料緩衝在接收端。再次呼叫 recv 時,剩餘的資料會從緩衝區取出並刪除。這一特性與 http 連線方式有很大區別,表示 socket 連線無法像 http 連線那般,一次 request 對應的一次 response 就能完成一次操作單元,而是很可能需要任意次的 send 以及任意次的 recv 才能完成。換句話說就是,需要開發者來保證 send 和 recv 的完整性,你需要手動的整理、組合出完整的傳送和響應結果資料。經常的,為了得到乙個完整的響應結果可能需要進行多次 recv。

呼叫 socket 的 close 函式並不會馬上斷開 socket 連線,一般的我們會在 close 之前呼叫 shutdown 函式來確保連線會被正常關閉。而且 shutdown 提供了多種不同的關閉方式:

note:在客戶端程式中,一般我們會選擇使用 shut_wr 方式,立即停止寫操作,但可以繼續將響應資料讀完。而在服務端程式中一般會選擇 shut_rd 模式,立即停止對客戶端請求的讀取,但會繼續完成響應。當然了,在某些對精度要求不要的場景中,shut_rdwr 是不錯的選擇。

git gerrit 實踐經驗

用git一段時間,體驗還是比較好。尤其沒次改一批檔案,檔案列表非常清晰。和gerrit結合,diff,review 都非常方便,尤其你不需要自己手動提交到伺服器 有些缺點 如果多人改同乙個目錄,不是很方便。有些體驗如下 1 工作前都用 repo start dev 開始乙個branch 再工作 2 ...

專案管理各環節實踐經驗

開始做專案是一件令人激動的事情,專案組的每個成員都面臨著新的機會和挑戰。但同時也多少有些令人不安,大家都會考慮這樣乙個問題 我們如何按時完成乙個高質量的專案?因為在專案開始之前往往存在許多不確定的因素,它們也許會一直持續到整個專案結束。所以在專案準備階段,也有許多任務作要做。前提條件與主要任務 開始...

專案實踐經驗總結 (1)

media screen and min width 768px media screen and min width 992px media screen and min width 1200 注意下順序,如果你把 media min width 768px 寫在了下面那麼很悲劇,media sc...