青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

TCP/IP網絡編程中socket的行為

剛才看到一篇文章,感覺不錯,轉載過來和大家分享: 

一. read/write的語義:為什么會阻塞?

先從write說起:

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

首先,write成功返回,只是buf中的數據被復制到了kernel中的TCP發送緩沖區。至于數據什么時候被發往網絡,什么時候被對方主機接收,什么時候被對方進程讀取,系統調用層面不會給予任何保證和通知。

write在什么情況下會阻塞?當kernel的該socket的發送緩沖區已滿時。對于每個socket,擁有自己的send buffer和receive buffer。從Linux 2.6開始,兩個緩沖區大小都由系統來自動調節(autotuning),但一般在default和max之間浮動。

# 獲取socket的發送/接受緩沖區的大小:(后面的值是在我在Linux 2.6.38 x86_64上測試的結果)
sysctl net.core.wmem_default       #126976
sysctl net.core.wmem_max     #131071
sysctl net.core.wmem_default #126976
sysctl net.core.wmem_max #131071

已經發送到網絡的數據依然需要暫存在send buffer中,只有收到對方的ack后,kernel才從buffer中清除這一部分數據,為后續發送數據騰出空間。接收端將收到的數據暫存在receive buffer中,自動進行確認。但如果socket所在的進程不及時將數據從receive buffer中取出,最終導致receive buffer填滿,由于TCP的滑動窗口和擁塞控制,接收端會阻止發送端向其發送數據。這些控制皆發生在TCP/IP棧中,對應用程序是透明的,應用程序繼續發送數據,最終導致send buffer填滿,write調用阻塞。

一般來說,由于接收端進程從socket讀數據的速度跟不上發送端進程向socket寫數據的速度,最終導致發送端write調用阻塞。

而read調用的行為相對容易理解,從socket的receive buffer中拷貝數據到應用程序的buffer中。read調用阻塞,通常是發送端的數據沒有到達。

 

二. blocking(默認)和nonblock模式下read/write行為的區別:

將socket fd設置為nonblock(非阻塞)是在服務器編程中常見的做法,采用blocking IO并為每一個client創建一個線程的模式開銷巨大且可擴展性不佳(帶來大量的切換開銷),更為通用的做法是采用線程池+Nonblock I/O+Multiplexing(select/poll,以及Linux上特有的epoll)。

1
2
3
4
5
6
7
8
// 設置一個文件描述符為nonblock
int set_nonblocking(int fd)
{
    int flags;
    if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
        flags = 0;
    return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

幾個重要的結論:

1. read總是在接收緩沖區有數據時立即返回,而不是等到給定的read buffer填滿時返回。

只有當receive buffer為空時,blocking模式才會等待,而nonblock模式下會立即返回-1(errno = EAGAIN或EWOULDBLOCK)

2. blocking的write只有在緩沖區足以放下整個buffer時才返回(與blocking read并不相同)

nonblock write則是返回能夠放下的字節數,之后調用則返回-1(errno = EAGAIN或EWOULDBLOCK)

 對于blocking的write有個特例:當write正阻塞等待時對面關閉了socket,則write則會立即將剩余緩沖區填滿并返回所寫的字節數,再次調用則write失敗(connection reset by peer),這正是下個小節要提到的:

 

三. read/write對連接異常的反饋行為:

對應用程序來說,與另一進程的TCP通信其實是完全異步的過程:

1. 我并不知道對面什么時候、能否收到我的數據

2. 我不知道什么時候能夠收到對面的數據

3. 我不知道什么時候通信結束(主動退出或是異常退出、機器故障、網絡故障等等)

對于1和2,采用write() -> read() -> write() -> read() ->...的序列,通過blocking read或者nonblock read+輪詢的方式,應用程序基于可以保證正確的處理流程。

對于3,kernel將這些事件的“通知”通過read/write的結果返回給應用層。


假設A機器上的一個進程a正在和B機器上的進程b通信:某一時刻a正阻塞在socket的read調用上(或者在nonblock下輪詢socket)

當b進程終止時,無論應用程序是否顯式關閉了socket(OS會負責在進程結束時關閉所有的文件描述符,對于socket,則會發送一個FIN包到對面)。

”同步通知“:進程a對已經收到FIN的socket調用read,如果已經讀完了receive buffer的剩余字節,則會返回EOF:0

”異步通知“:如果進程a正阻塞在read調用上(前面已經提到,此時receive buffer一定為空,因為read在receive buffer有內容時就會返回),則read調用立即返回EOF,進程a被喚醒。

socket在收到FIN后,雖然調用read會返回EOF,但進程a依然可以其調用write,因為根據TCP協議,收到對方的FIN包只意味著對方不會再發送任何消息。 在一個雙方正常關閉的流程中,收到FIN包的一端將剩余數據發送給對面(通過一次或多次write),然后關閉socket。

但是事情遠遠沒有想象中簡單。優雅地(gracefully)關閉一個TCP連接,不僅僅需要雙方的應用程序遵守約定,中間還不能出任何差錯。

假如b進程是異常終止的,發送FIN包是OS代勞的,b進程已經不復存在,當機器再次收到該socket的消息時,會回應RST(因為擁有該socket的進程已經終止)。a進程對收到RST的socket調用write時,操作系統會給a進程發送SIGPIPE,默認處理動作是終止進程,知道你的進程為什么毫無征兆地死亡了吧:)

from 《Unix Network programming, vol1》 3rd Edition:

"It is okay to write to a socket that has received a FIN, but it is an error to write to a socket that has received an RST."

通過以上的敘述,內核通過socket的read/write將雙方的連接異常通知到應用層,雖然很不直觀,似乎也夠用。

這里說一句題外話:

不知道有沒有同學會和我有一樣的感慨:在寫TCP/IP通信時,似乎沒怎么考慮連接的終止或錯誤,只是在read/write錯誤返回時關閉socket,程序似乎也能正常運行,但某些情況下總是會出奇怪的問題。想完美處理各種錯誤,卻發現怎么也做不對。

原因之一是:socket(或者說TCP/IP棧本身)對錯誤的反饋能力是有限的。

 

考慮這樣的錯誤情況:

不同于b進程退出(此時OS會負責為所有打開的socket發送FIN包),當B機器的OS崩潰(注意不同于人為關機,因為關機時所有進程的退出動作依然能夠得到保證)/主機斷電/網絡不可達時,a進程根本不會收到FIN包作為連接終止的提示。

如果a進程阻塞在read上,那么結果只能是永遠的等待。

如果a進程先write然后阻塞在read,由于收不到B機器TCP/IP棧的ack,TCP會持續重傳12次(時間跨度大約為9分鐘),然后在阻塞的read調用上返回錯誤:ETIMEDOUT/EHOSTUNREACH/ENETUNREACH

假如B機器恰好在某個時候恢復和A機器的通路,并收到a某個重傳的pack,因為不能識別所以會返回一個RST,此時a進程上阻塞的read調用會返回錯誤ECONNREST

恩,socket對這些錯誤還是有一定的反饋能力的,前提是在對面不可達時你依然做了一次write調用,而不是輪詢或是阻塞在read上,那么總是會在重傳的周期內檢測出錯誤。如果沒有那次write調用,應用層永遠不會收到連接錯誤的通知。

write的錯誤最終通過read來通知應用層,有點陰差陽錯?

 

四. 還需要做什么?

至此,我們知道了僅僅通過read/write來檢測異常情況是不靠譜的,還需要一些額外的工作:

1. 使用TCP的KEEPALIVE功能?

復制代碼
cat /proc/sys/net/ipv4/tcp_keepalive_time
7200

cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75

cat /proc/sys/net/ipv4/tcp_keepalive_probes
9
復制代碼

以上參數的大致意思是:keepalive routine每2小時(7200秒)啟動一次,發送第一個probe(探測包),如果在75秒內沒有收到對方應答則重發probe,當連續9個probe沒有被應答時,認為連接已斷。(此時read調用應該能夠返回錯誤,待測試)

但在我印象中keepalive不太好用,默認的時間間隔太長,又是整個TCP/IP棧的全局參數:修改會影響其他進程,Linux的下似乎可以修改per socket的keepalive參數?(希望有使用經驗的人能夠指點一下),但是這些方法不是portable的。

/*peakflys 增加
int keepalive = 1; // 開啟keepalive屬性
int keepidle = 60; // 如該連接在60秒內沒有任何數據往來,則進行探測
int keepinterval = 5; // 探測時發包的時間間隔為5 秒
int keepcount = 3; // 探測嘗試的次數.如果第1次探測包就收到響應了,則后2次的不再發.
setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive , sizeof(keepalive ));
setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepidle , sizeof(keepidle ));
setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval ));
setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount )); sizeof(keepidle ));
setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval ));
setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount )); *///peakflys 增加(PS:好像這種方法也并不是所有情況都奏效)

 

2. 進行應用層的心跳

嚴格的網絡程序中,應用層的心跳協議是必不可少的。雖然比TCP自帶的keep alive要麻煩不少(怎樣正確地實現應用層的心跳,我或許會用一篇專門的文章來談一談),但有其最大的優點:可控。

當然,也可以簡單一點,針對連接做timeout,關閉一段時間沒有通信的”空閑“連接。

原文鏈接:http://www.cnblogs.com/promise6522/archive/2012/03/03/2377935.html

posted on 2012-08-02 12:34 peakflys 閱讀(3439) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


<2012年8月>
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678

導航

統計

公告

人不淡定的時候,就愛表現出來,敲代碼如此,偶爾的靈感亦如此……

常用鏈接

留言簿(4)

隨筆分類

隨筆檔案

文章檔案

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲久色影视| 欧美一级网站| 久久精品国产第一区二区三区最新章节| 亚洲国产精品尤物yw在线观看 | 伊人成人在线视频| 国产日韩亚洲欧美| 黄色成人免费观看| 亚洲精品视频在线看| 日韩视频免费| 亚洲自拍偷拍福利| 久久三级福利| 亚洲第一区色| 美女免费视频一区| 亚洲成在人线av| 在线视频亚洲| 久久久久久久999精品视频| 欧美成人亚洲成人| 欧美午夜一区二区三区免费大片 | 麻豆成人在线播放| 欧美日韩亚洲激情| 韩国三级电影久久久久久| 午夜精品成人在线| 久久综合成人精品亚洲另类欧美| 欧美国产一区二区在线观看| 亚洲美女精品久久| 性欧美大战久久久久久久免费观看| 久久久久国色av免费看影院| 欧美激情综合色综合啪啪| 国产精品一级久久久| 亚洲欧洲精品一区二区三区 | 欧美在线你懂的| 欧美理论电影在线播放| 国产偷国产偷精品高清尤物| 亚洲精品视频在线观看免费| 久久久欧美一区二区| 日韩亚洲视频在线| 另类天堂视频在线观看| 国产伦一区二区三区色一情| 日韩视频第一页| 女同性一区二区三区人了人一| 亚洲综合导航| 国产精品v欧美精品v日本精品动漫| 亚洲国产精品一区二区久 | 久久狠狠亚洲综合| 在线亚洲国产精品网站| 欧美激情2020午夜免费观看| 国产伦一区二区三区色一情| 99精品国产一区二区青青牛奶| 久热国产精品视频| 亚洲欧美在线网| 国产精品伦一区| 亚洲午夜激情免费视频| 亚洲欧洲一区二区三区| 欧美α欧美αv大片| 亚洲成人影音| 蜜臀av在线播放一区二区三区| 亚洲欧美在线aaa| 国产伦精品一区二区三区四区免费 | 一本色道久久综合亚洲精品按摩| 麻豆亚洲精品| 欧美在线黄色| 在线观看国产精品网站| 久久午夜精品一区二区| 亚洲欧美视频在线| 国产欧美日韩精品丝袜高跟鞋| 亚洲综合色噜噜狠狠| 在线亚洲观看| 国产亚洲一区二区三区在线观看 | 亚洲午夜精品17c| 久久琪琪电影院| 国产亚洲高清视频| 久久成人综合视频| 欧美呦呦网站| 极品日韩av| 欧美成人dvd在线视频| 久久婷婷综合激情| 亚洲人成77777在线观看网| 亚洲激情不卡| 欧美日本一道本在线视频| 一区二区毛片| 亚洲综合另类| 在线看片一区| 亚洲黄网站黄| 国产精品成人一区二区| 欧美一区综合| 久久在线免费观看| 一区二区三区**美女毛片| 亚洲一区综合| 亚洲高清久久网| 一本色道久久综合亚洲二区三区 | 亚洲午夜一区二区三区| 国产偷自视频区视频一区二区| 麻豆成人av| 欧美久久久久久蜜桃| 亚洲欧美日韩成人| 久久青青草原一区二区| 午夜精品福利视频| 蜜臀av性久久久久蜜臀aⅴ四虎 | 永久免费毛片在线播放不卡| 亚洲美女中文字幕| 国产亚洲va综合人人澡精品| 欧美激情女人20p| 国产欧美一区二区三区视频| 欧美国产一区视频在线观看| 国产精品国产三级国产aⅴ9色| 久久久爽爽爽美女图片| 欧美四级在线观看| 亚洲电影成人| 国产日韩精品一区观看 | 亚洲精品欧美日韩| 狠狠色综合网| 亚洲综合色婷婷| 亚洲精品国产精品国自产观看 | 欧美一区二区三区免费观看视频| 亚洲人成网在线播放| 欧美夜福利tv在线| 欧美精品v日韩精品v国产精品| 午夜视频在线观看一区| 欧美激情网友自拍| 免费观看久久久4p| 国产欧美日韩综合精品二区| 亚洲人成网站精品片在线观看| 影院欧美亚洲| 久久漫画官网| 久久乐国产精品| 国产伦精品一区二区三区照片91| 亚洲精品一区二区三区不| 1769国内精品视频在线播放| 欧美一级免费视频| 欧美在线日韩| 国产酒店精品激情| 亚洲一区不卡| 亚洲在线播放电影| 欧美日韩精品二区| 日韩视频在线一区二区| 99国产精品| 欧美日韩高清在线观看| 亚洲国产精品传媒在线观看| 亚洲精品国产系列| 欧美精品麻豆| 99re这里只有精品6| 99re在线精品| 欧美午夜精品理论片a级大开眼界 欧美午夜精品理论片a级按摩 | 国产日韩欧美黄色| 亚洲天堂av在线免费| 亚洲欧美日韩国产成人| 国产精品日韩欧美一区二区| 亚洲一区二区三区欧美| 亚洲午夜久久久久久久久电影院| 久久久另类综合| 亚洲日韩欧美视频| 亚洲人成网站777色婷婷| 午夜一区不卡| 亚洲国产精品成人综合色在线婷婷| 国产女主播一区二区| 午夜精品999| 久久精品一区二区国产| 国内精品美女av在线播放| 久久成人国产| 欧美成人综合网站| 日韩午夜激情| 国产精品伊人日日| 欧美自拍偷拍| 亚洲黑丝在线| 亚洲午夜激情网页| 国产亚洲欧美aaaa| 免费不卡在线视频| 一本色道久久综合狠狠躁篇怎么玩| 亚洲激情视频网站| 亚洲伦理中文字幕| 亚洲欧美成人一区二区在线电影| 国产精品天美传媒入口| 久久精品久久综合| 日韩视频一区二区三区在线播放免费观看 | 欧美国产第二页| a91a精品视频在线观看| 亚洲毛片在线| 久久久精品tv| 国产精品99久久久久久久久| 国产精品亚洲综合久久| 久久麻豆一区二区| 中文一区字幕| 欧美国产精品劲爆| 午夜精品视频在线观看| 精品999日本| 欧美日韩成人精品| 久久伊人一区二区| 国产啪精品视频| 久久综合色影院| 午夜性色一区二区三区免费视频| 欧美亚洲综合另类| 亚洲级视频在线观看免费1级| 国产精品www| 免费中文日韩| 欧美在线亚洲一区| 亚洲视频在线观看视频| 欧美激情一区在线| 久久久久一本一区二区青青蜜月| 亚洲网站在线| 亚洲美女黄色片|