Effective TCP/IP Programming讀書筆記

來源:互聯網
上載者:User

標籤:socket   tcp-ip   

TCP/IP深入思考

這是我讀Effective TCP/IP Programming的 讀書筆記和思考,以及做的一些實驗。強烈建議後端工程師有空讀一讀這本書,有些細節的確是我們平時沒有注意的,讀了最好自己動手做一些實驗加深理解。

fin的含義

對端發送fin會導致read()返回,但send()照樣可以發送,也就是單純的fin其實相當於shutdown(SHUT_WR)。

當對端應用程式崩潰後(未close),本段一直調用send(),對端會返回RST,此時read()會返回Connection reset by peer。

當對端應用程式崩潰後或close串連,本段調用read()返回0,
調用send()會導致EPIPE(Broken pipe),第二次send()才會出錯。

對端主機崩潰

由於主機崩潰,或不結束應用程式關機,或直接關閉modern,導致對方接受不到fin,rst等,recv()會永久阻塞。解決辦法:

1.開啟keepalive機制,預設情況下(2+9*75/60)小時後逾時
2.recv()逾時機制
3.心跳,其實就是發送send(),一段時間會檢測到串連斷了

SO_LINGER深入理解

如果應用程式執行主動關閉,最後會在TIME_WAIT狀態保持2MSL時間,而SO_LINGER選項能迫使串連立刻關閉,不走正常4步關閉流程。
server

from socket import *s = socket(AF_INET,SOCK_STREAM)s.bind(("localhost",9123))s.listen(10)cc = s.accept()print cc #查看零時連接埠為47128

client

from socket import *c = socket(AF_INET,SOCK_STREAM)c.connect(("localhost",9123))c.close()

由於client主動關閉,這時client應該處於FIN_WAIT2,server對應處於CLOSE_WAIT

[[email protected]10-9-22-239 ~]# netstat -an | grep 47128tcp        1      0 127.0.0.1:9123          127.0.0.1:47128         CLOSE_WAIT tcp        0      0 127.0.0.1:47128         127.0.0.1:9123          FIN_WAIT2  

注意netstat要加n參數,不然會根據/etc/services解析成服務名。
當server端再調用cc[0].close()時,此時clinet將處於TIME_WAIT狀態。我們將client的socket加個SO_LINGER選項。

from struct import *c.setsockopt(SOL_SOCKET,SO_LINGER,pack("ii",1,0))

此時我們查看發現沒有對應狀態,也就是未新戶型FIN_WAIT2的狀態,直接關閉,不走正常四步關閉串連流程。

當然強壯的應用伺服器不應該幹擾TIME_WAIT狀態,這是TCP可靠機制的重要組成部分。
SO_LINGER選項還有其它作用,通常當close()一條串連時,即使發送緩衝區仍然有資料要發送,close()也會立即返回。當然TCP還是會嘗試發送未發送出去的資料,但應用程式並不知道是否發送成功,SO_LINGER就是為解決這個問題的。

struct linger{    int l_onoff; // on/off選項    int l_linger; //逗留時間};

1.l_onoff為0,linger不啟用,行為和預設close()相同
2.l_onoff非0,如果l_linger非0,close()在等待資料發送完畢或逗留時間逾時,如果逗留時間到,仍然有未發送資料,close()返回EWOULDBLOCK;如果linger為0,就將丟棄串連,也就是上面我們展示的那樣。

Nagle演算法和延遲ACK

Nagle演算法有助於預防網路中的小報文泛洪,但與延遲ACK互動可能會導致200ms延遲。BSD實現ACK延遲200ms,RFC規定不能大於500ms,我在Linux上做的實驗發現都是40ms延遲ACK。

關閉Nagle演算法

const int on = 1;setsocket(s, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
//from tornadotry:    self.socket.setsockopt(socket.IPPROTO_TCP,socket.TCP_NODELAY, 1)except socket.error as e:    # Sometimes setsockopt will fail if the socket is closed    # at the wrong time.  This can happen with HTTPServer    # resetting the value to false between requests.    if e.errno not in (errno.EINVAL, errno.ECONNRESET):        raise

應對方法:

1.將寫操作合并,可使用writev()
2.多用buff,如go中bufio.Reader,bufio.Writer

非阻塞connect

非阻塞connect()會立即返回EINPROGRESS,如果串連成功通訊端會立刻可寫,那如何檢查是否串連成功呢?

status = connect( sock, ......); // 返回0,成功串連if ( status != 0 && errno != EINPROGRESS) {    close(sock);}

可以使用getsockopt檢查是否出錯,當然之前必須等待該socket狀態變化

int error;socklen_t len = sizeof(error);  int code = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);  if (code < 0 || error) {  //傳回值小於0或error不等於0說明串連錯誤    close(s);    return SOCKET_ERROR;}

用python類比如下:

import socketimport selectimport errnos=socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.setblocking(False)try:  s.connect(("www.google.com",80))except socket.error as e:  if e.errno == errno.EINPROGRESS:    print("INprocess")  else:    raiser,w,x = select.select([s],[s],[s])err = s.getsockopt(socket.SOL_SOCKET,socket.SO_ERROR)if err != 0:  print("error",errno.errorcode[err])  s.close()else:  print("connect ok")

很明顯,不翻牆www.google.com暫時串連不了,出錯資訊

INprocess(‘error‘, ‘ETIMEDOUT‘)
理解udp connect

使用udp connect好處:

1.使用connect()對效能有較大提高,BSD實現中sendto()是connect的特列,核心暫時讓通訊端與目的地址串連,發送資料包,然後解除串連。
2.可以接受非同步錯誤,由於udp無狀態,資料發送出去,系統就會忘記,所以即使返回icmp報文,也不知道是哪個應用程式發送的資料包,使用connect會記錄對應資訊。

s=socket(AF_INET,SOCK_DGRAM)s.connect(("localhost",9999))s.send("1111")s.recv() //error: [Errno 111] Connection refused

send()之後,icmp報文報告不可達,再次recv或recvfrom會報錯。

緩衝區大小

發送緩衝區設定為MSS的3倍大,可有效減少Nagle演算法與延遲ACK導致的互動問題。
Linux預設發送緩衝區為4K,乙太網路mss是1460,還是很合理的。

發送緩衝區大小大於等於對方的接受緩衝區,因為發送方只能收到ACK才會釋放已發送資料,所以發送緩衝區容易滿,不發送新的資料,就會產生40ms延遲ACK。

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

Effective TCP/IP Programming讀書筆記

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.