在研究 pcp_child.c 中的代碼的時候,看到 pcp_do_accept 函數中有如下代碼:
複制代碼
if (setsockopt(afd, IPPROTO_TCP, TCP_NODELAY,
(char *) &on,
sizeof(on)) < 0)
{
pool_error("pcp_child: setsockopt() failed: %s", strerror(errno));
close(afd);
return NULL;
}
Google了一下,發現是:為了最小化 封包傳輸的延遲。就是說不會對封包合并,有了資料就進行發送。
但是下一個是比較奇怪的:
if (setsockopt(afd, SOL_SOCKET, SO_KEEPALIVE,
}
Google了一下,人家都是這麼說的:
設定 SO_KEEPALIVE 選項
SO_KEEPALIVE 保持連接配接檢測對方主機是否崩潰,避免(伺服器)永遠阻塞于TCP連接配接的輸入。
設定該選項後,如果2小時内在此套接口的任一方向都沒有資料交換,TCP就自動給對方 發一個保持存活探測分節(keepalive probe)。
這是一個對方必須響應的TCP分節.
它會導緻以下三種情況:
對方接收一切正常:以期望的ACK響應。
2小時後,TCP将發出另一個探測分節。
對方已崩潰且已重新啟動:
以RST響應。套接口的待處理錯誤被置為ECONNRESET,套接 口本身則被關閉。
對方無任何響應:
源自berkeley的TCP發送另外8個探測分節,相隔75秒一個,試圖得到一個響應。
在發出第一個探測分節11分鐘15秒後若仍無響應就放棄。套接口的待處理錯誤被置為ETIMEOUT,套接口本身則被關閉。
如ICMP錯誤是“host unreachable(主機不可達)”,說明對方主機并沒有崩潰,但是不可達,這種情況下待處理錯誤被置為 EHOSTUNREACH。在該書的第158頁有更詳細的描述。
根據上面的介紹我們可以知道對端以一種非優雅的方式斷開連接配接的時候,
我們可以設定SO_KEEPALIVE屬性使得我們在2小時以後發現對方的TCP連接配接是否依然存在。
keepAlive = 1; Setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));
如果我們不能接受如此之長的等待時間,
從TCP-Keepalive-HOWTO上可以知道一共有兩種方式可以設定,
一種是修改核心關于網絡方面的配置參數,
另外一種就是SOL_TCP字段的TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT三個選項。
英文說明在:http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/programming.html
但是我的問題在于:pcp_pool_status等各種用戶端指令,都是立即結束的。根本就不會維持和伺服器端的長連接配接。經過試驗,修改 下列參數:
/proc/sys/net/ipv4/tcp_keepalive_time
/proc/sys/net/ipv4/tcp_keepalive_intvl
/proc/sys/net/ipv4/tcp_keepalive_probes
改為 tcp_keepalive_time=180秒 tcp_keepalive_intvl=10秒 tcp_keepalive_probes=6個
再次運作,無論程式中是否包含
if (setsockopt(afd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) {
pool_error("pcp_child: setsockopt() failed: %s", strerror(errno));
close(afd);
return NULL;
都可以正常多次運作 pcp_pool_status 指令,背景産生響應的 socket描述符的值也都一樣。
懷疑當初的開發者考慮過長連接配接的問題:就是pcp_pool_status 之類不斷運作,長連接配接并不斷開。但最終pcp用戶端并沒有如此實作。
标簽: pgpool-II, setsockopt, SO_KEEPALIVE
本文轉自健哥的資料花園部落格園部落格,原文連結:http://www.cnblogs.com/gaojian/archive/2012/08/15/2639963.html,如需轉載請自行聯系原作者