1. 程式人生 > >從jedis的TCP連線建立來學習Java Socket

從jedis的TCP連線建立來學習Java Socket

在很多教材或者教程上,通常都是很簡單的一個例子來演示如何使用Java進行TCP通訊.在這款廣泛被使用的開源元件中,我們能夠更好的學習到一個企業級的元件在TCP連線的處理上,更應該關注哪些方面.有哪些是我們應該掌握或者瞭解的TCP知識.TCP協議本身相當複雜,我們做應用的可以先從應用層需要用到的相關知識開始瞭解.
jedis中,與redis服務端建立連線的程式碼在Connection這個類中.

  public void connect() {
    if (!isConnected()) {
      try {
        socket = new Socket();
        // ->@wjw_add
socket.setReuseAddress(true); socket.setKeepAlive(true); // Will monitor the TCP connection is // valid socket.setTcpNoDelay(true); // Socket buffer Whetherclosed, to // ensure timely delivery of data socket.setSoLinger(true, 0); // Control calls close () method,
// the underlying socket is closed // immediately // <[email protected]_add socket.connect(new InetSocketAddress(host, port), connectionTimeout); socket.setSoTimeout(soTimeout); if (ssl) { if (null == sslSocketFactory) { sslSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault(); } socket = (SSLSocket) sslSocketFactory.createSocket(socket, host, port, true
); if (null != sslParameters) { ((SSLSocket) socket).setSSLParameters(sslParameters); } if ((null != hostnameVerifier) && (!hostnameVerifier.verify(host, ((SSLSocket) socket).getSession()))) { String message = String.format( "The connection to '%s' failed ssl/tls hostname verification.", host); throw new JedisConnectionException(message); } } outputStream = new RedisOutputStream(socket.getOutputStream()); inputStream = new RedisInputStream(socket.getInputStream()); } catch (IOException ex) { broken = true; throw new JedisConnectionException("Failed connecting to host " + host + ":" + port, ex); } } } public boolean isConnected() { return socket != null && socket.isBound() && !socket.isClosed() && socket.isConnected() && !socket.isInputShutdown() && !socket.isOutputShutdown(); }

通過以上程式碼,可以看到用到了jdk中相關的Socket物件來與redis服務進行tcp連線.重點看幾個方法

setReuseAddress(true)
setKeepAlive(true)
setTcpNoDelay(true)
setSoLinger(true, 0)
setSoTimeout(soTimeout)

Socket

setReuseAddress

要解釋這個方法的作用,首先要了解TCP套接字的一個狀態-time-wait.
眾所周知,TCP的連線建立和斷開要經歷三次握手和四次揮手.
如圖所示,
四次揮手-圖片來自維基百科
而time-wait這個狀態就是連線發起方,通常就是client,在收到伺服器端的FIN包後進入的狀態.那為什麼這個狀態需要存在呢?客戶端收到服務端傳送的FIN包後,會向服務端傳送一個ACK包,服務端接收到ACK包後進入CLOSED狀態.但是由於網路或者其他問題,導致服務端有可能沒有收到ACK包,導致伺服器端重發FIN包.
time-wait這個需要保持多久呢?大概是2MSL(最大分段生存期).

MSL(最大分段生存期)指明TCP報文在Internet上最長生存時間,每個具體的TCP實現都必須選擇一個確定的MSL值。RFC 1122建議是2分鐘,但BSD傳統實現採用了30秒。

瞭解了這些之後,我們可以看看這個方法的內部實現

public void setReuseAddress(boolean on) throws SocketException {
        if (isClosed())
            throw new SocketException("Socket is closed");
        getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
    }

我們看到,它是對SO_REUSEADDR這個套接字選項進行了設定.

這個套接字選項通知核心,如果埠忙,但TCP狀態位於 TIME_WAIT ,可以重用埠。如果埠忙,而TCP狀態位於其他狀態,重用埠時依舊得到一個錯誤資訊,指明”地址已經使用中”。如果你的服務程式停止後想立即重啟,而新套接字依舊使用同一埠,此時 SO_REUSEADDR 選項非常有用。

對應linux作業系統響應的配置為

net.ipv4.tcp_tw_reuse = 1    表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連線,預設為0,表示關閉
net.ipv4.tcp_tw_recycle = 1  表示開啟TCP連線中TIME-WAIT sockets的快速回收,預設為0,表示關閉

setKeepAlive

心跳檢測是我們用來判斷後端程式是否依舊正常服務的一個常用手段.TCP協議提供keepalive機制來監測TCP連線是否已經斷開.

net.ipv4.tcp_keepalive_intvl = 20 重發keepalive包間隔 
net.ipv4.tcp_keepalive_probes = 3 重發次數
net.ipv4.tcp_keepalive_time = 60 超過一段時間沒有進行資料傳輸則進行心跳監測

setTcpNoDelay

要了解這個方法的作用,首先要知道TCP協議中一個註明的演算法-Nagle演算法.Nagle演算法的初衷是避免小包擁塞網路.比如只需要傳送一個位元組的資料,可是由於TCP包本身就佔用了幾十個位元組,這樣是比較浪費網路資源的.Nagle演算法導致了要麼是等待ACK到達或者緩衝區滿,才會傳送新的資料.
再介紹一下TCP-Delayed-ACK ,它是將ACK和響應資料綁在一個包中傳送,降低協議開銷.
如果客戶端採用了Nagle演算法和服務端採用了Delayed-ACK,同時客戶端採用write-write-read模式,就很容易造成客戶端與服務端都在等待對方資料的問題.
Delayed Ack 是有個超時機制的,而預設的超時正好就是40ms.
這裡有一篇文章很好的介紹了write-write-read這種問題
setTcpNoDelay其實就是講Nagle演算法關閉,使得每次無論資料包有多大都會被立即傳送.

setSoLinger

SO_LINGER選項用來控制Socket關閉時的行為,預設情況下,執行Socket的close方法,該方法會立即返回,但底層的Socket實際上並不會立即關閉,他會立即延遲一段時間,知道傳送完剩餘的資料,才會真正的關閉Socket,斷開連線。

setSoLinger(true, 0)

執行該方法,那麼執行Socket的close方法,該方法也會立即返回,但底層的Socket也會立即關閉,所有未傳送完的剩餘資料被丟棄.

setSoTimeOut

官方文件中解釋

啟用/禁用帶有指定超時值的 SO_TIMEOUT,以毫秒為單位。
將此選項設為非零的超時值時,在與此 Socket 關聯的 InputStream 上呼叫 read() 將只阻塞此時間長度。如果超過超時值,將引發java.net.SocketTimeoutException,雖然 Socket
仍舊有效。選項必須在進入阻塞操作前被啟用才能生效。超時值必須是 > 0 的數。超時值為 0 被解釋為無窮大超時值。
引數:
timeout - 指定的以毫秒為單位的超時值。
丟擲:
SocketException -
如果底層協議出現錯誤,例如 TCP 錯誤。

相關推薦

jedis的TCP連線建立學習Java Socket

在很多教材或者教程上,通常都是很簡單的一個例子來演示如何使用Java進行TCP通訊.在這款廣泛被使用的開源元件中,我們能夠更好的學習到一個企業級的元件在TCP連線的處理上,更應該關注哪些方面.有哪些是我們應該掌握或者瞭解的TCP知識.TCP協議本身相當複雜

火箭發場景學習Java多執行緒併發閉鎖物件

從火箭發場景來學習Java多執行緒併發閉鎖物件 倒計時器場景 在我們開發過程中,有時候會使用到倒計時計數器。最簡單的是:int size = 5; 執行後,size—這種方式來實現。但是在多執行緒併發的情況下,這種操作會不安全的。舉個現實中最典型的一個例子:火箭發射的案例。 大家都看過火箭發射的直播吧。火箭在

【轉】歸納一個某課程薅Java架構學習計劃和知識體系-給自己記錄一下(趕緊學)

1.Java基礎-原始碼 1. 常用的設計模式 Proxy代理模式 Factory工廠模式 Singleton單例模式 Delegate委派模式 Strategy策略模式 Prototype原型模式 Template模版模式 Deco

一道面試題認識java類加載時機與過程【轉】

包含 布局 hello 印象 大致 周期 default () itl 說明:本文的內容是看了《深入理解Java虛擬機:JVM高級特性與最佳實踐》後為加印象和理解,便記錄了重要的內容。 1 開門見山 以前曾經看到過一個java的面試題,當時覺得此題很簡單,可是自己

另一個思路學習安卓事件分發機制

從另一個思路來學習安卓事件分發機制 前言 事件分發機制是一個安卓老生常談的話題了,從前幾年的面試必問題到如今的本當成預設都會的基礎知識。關於這方面的部落格網上已經有很多很多了,有從原始碼分析的,有從實際出發開始分析的等等。面對這麼多的教程,小白可能一頭霧水不知道從哪裡看起,而且看完之後感覺啥也沒留下。那麼

21. 一道CTF靶機學習mysql-udf提權

這次測試的靶機為 Raven: 2 這裡是CTF解題視訊地址:https://www.youtube.com/watch?v=KbUUn3SDqaU 此次靶機主要學習 PHPMailer 跟 mymql 的UDF提權。 掃描網站目錄發現,還是wordpress搭建的,嘗試使用wp

一道面試題認識java類載入時機與過程

說明:本文的內容是看了《深入理解Java虛擬機器:JVM高階特性與最佳實踐》後為加印象和理解,便記錄了重要的內容。 1  開門見山 以前曾經看到過一個java的面試題,當時覺得此題很簡單,可是自己把程式碼執行起來,可是結果並不是自己想象的那樣。題目如下: class SingleTon {

java基礎類庫學習 java.sql(7)使用資料庫連線管理資料庫連線物件

前言: 在實際開發中,如果我們不斷地建立資料庫連線物件,一個數據庫連線物件均對應一個物理資料庫連線,每次操作都開啟一個物理連線,使用完後就立即關閉連線,頻繁的開啟關閉連線會造成系統性能下降 因此實際開發中不推薦頻繁的建立資料庫連線物件,頻繁的開啟物理資料庫連線,頻繁的關閉

深度學習R(1):零開始建立完全連線的神經網路

作者:PENG ZHAO 我要感謝Feiwen, Neil和所有其他的技術評論家和讀者,他們為本文提出了寶貴的意見和建議。 背景 深度神經網路(DNN)近年來取得了在影象識別、自然語言處理和自動駕駛領域取得了巨大成就,如圖1所示,從2012至2015

Java零基礎學習Java編程語言哪兒入手?

軟件工程是計算機領域發展最快的學科分支之一,國家非常重視軟件行業的發展。對軟件工程師人才的培養給予了非常優惠的政策。在所有軟件開發類人才的需求中對Java工程師的需求達到全部需求量的60~70%。應該說Java軟件工程師就業前景是非常好的,再加上Java軟件工程師不僅IT專業企業需要,廣大的非IT企業也

五本書籍助你零基礎學習java編程到精通之路

html 書籍 區域 快速 學會 即使 沒有 j2e j2se 前天的文章給大家介紹了Java初學者應該學習哪些基礎,亦是美網絡小編從Java的三個大方向:J2SE、J2EE、J2ME對大家做了前景分析,這兩天也收到了大家的很多反饋,很多小夥伴看了後對自己的Java編程方向

java基礎學習總結(十七):Java Socket

一、 什麼是Socket          Socket的概念很簡單,它是網路上執行的兩個程式間雙向通訊的一端,既可以接收請求,也可以傳送請求,利用它可以較為方便地編寫網路上資料的傳遞。 所以簡而言之,Socket就是程序通訊的端點

一種JSON資料建立Java類的高效辦法

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Java基礎(二)Java 基礎語法,小白趕緊學習吧!

Java 基礎語法 一個Java程式可以認為是一系列物件的集合,而這些物件通過呼叫彼此的方法來協同工作。下面簡要介紹下類、物件、方法和例項變數的概念。 物件:物件是類的一個例項,有狀態和行為。例如,一條狗是一個物件,它的狀態有:顏色、名字、品種;行為有:搖尾巴、叫、吃等。 類:類

Java——socket實現tcp連線

Server: import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server { /** * Socket服務端 */

區塊鏈學習零開始建立自己的區塊鏈應用

閱讀物件 本文閱讀物件,主要是希望和即將從事區塊鏈開發的專案架構師,開發工程師,專案設計或產品設計師。要求閱讀者具備一定的“區塊鏈”基礎知識、概念和以及相關的技術知識。 如果你只需要對區塊鏈應用做一個更深更直觀的瞭解,通過本文的例子更清晰瞭解區塊鏈是怎麼回事,大概是怎麼開發出來的,怎麼使用,那麼

學習Java 這些書開始吧

Java的優勢是簡單、面向物件、分散式、解釋執行、魯棒、安全、體系結構中立、可移植、高效能、多執行緒以及動態性。 Java語言的設計從現在的角度看非常中庸,啥都不是特別出色,但都“湊合”。 學習Java就業時就意味著有不少選擇餘地的。 其實Java並沒有想象中的那麼難,前提是做好一

大資料學習:帶你多個維度分析大資料發展趨勢

如今“大資料”已不再是單純描述資料特徵的詞彙,而是一個多學科交融的熱點研究領域,其背後有著複雜和深刻的新理念。 今天我們帶大家從“技術、工程、科學和應用”這四個維度分析大資料的研究現狀與挑戰,探討未來研究的側重點和發展趨勢。 推薦下小編的大資料學習群;前面是251中間是956後面是502,不管

虛擬機器的角度看java物件的建立

前言 建立物件有多種方式,最直觀的方式就是通過new關鍵字建立物件。通過new建立的物件儲存在java的堆中。 物件的建立過程 java建立過程要經過下圖的6個步驟,我們所能看到的是new 類名和呼叫物件的初始化方法,中間的四個是虛擬機器內部所執行的,對於開發者來講它遮

零基礎學習java,先基礎書籍入手

       Java行業的火爆,吸引了成批的初學者的加入,這些大都是零基礎沒有經驗的,想通過java的學習另闢人生路。對於java學習,小編整理了一些關於Java基礎入門的書籍,可以供大家學習。 1、《深入理解計算機系統》         著名的CSAPP,從c語言到組