以下是對我之前學習的linux網路程式設計的一些筆記。
int socket(int domain, int type, int protocol);
type這個引數,可以加上乙個 sock_nonblock,把套接字設定為非阻塞,保證這一設定的原子性。
int listen(int sockfd, int backlog);
把sockfd設定成listen狀態,之後就可以完成三次握手了,其實三次握手是在核心態完成的,accpet僅僅只是移除已經做好三次握手的鍊錶中的套接字。
而backlog有最大值限制,一般為128。這就是做好三次握手,卻沒有被accept移除的資料鏈表大小。
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
繫結sockfd和埠,以及ip,注意:sockaddr的另乙個異構的結構體:sockaddr_in中的sin_port和sin_address必須是網路位元組序。
為什麼sin_family不用?
因為它不用傳送到網路上去,而port和address分別放在傳輸層和網路層。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
用於從已經完成三次握手的鍊錶中將移除隊頭,並且返回控制代碼(fd)。並且利用sockaddr資料結構返回連線的socket的port,family,ip等資料。
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
connect的一些錯誤返回分析:
(1)原因:連線沒有開啟的port
使用者態:errno=111(connection refused)
(核心態)傳輸層:tcp收到了對端機器傳送的rst包。
(2)原因:連線乙個不存在的ip(ping不到的ip)
使用者態:errno=110(connection time out)
(核心態)傳輸層:tcp不斷進行超時重傳,總共127s,
時間間隔:1s,2s,4s,8s,16s,32s,64s,指數退避。
重傳的tcp報文中一般只有時間戳選項會有變化,時間戳選項一般用於計算rtt,防止迴繞(時間要大於2mst),syn cookie是把一些第一次syn協商的值(如:wscale,sack)編進32bit時間戳中。
syn cookie:收到tcp syn包,並返回syn|ack不分配資料區,而是用對方syn包,演算法出cookie值,在發syn|ack時,把cookie作為序列號!在syn_recvd狀態下收到對方的ack號,比對,如果合法,則分配核心資料區(分配資料區的其他選項,協商的其他選項,會放在32bit時間戳中)。
(3)如果設定sock_nonblock,connect一般會立即返回-1,errno = einprogress,當然也可能直接返回0表示成功,這個情況很特殊,就不做討論。
如果返回-1,errno=einprogress,在後面的怎麼使用?
一般會利用epoll來進行阻塞判斷。
具體是先向epoll_create建立的epfd(控制代碼)註冊connect獲得的connfd,然後利epollerr中利用getsockopt對套接字的錯誤errno進行提取。
注意:利用epoll多路復用,一般使用以上這個方法獲取套接字的errno。而且取完以後,errno會被重置為0,就是說,任何錯誤,只有一次得知的機會;但是除此之外,一般函式如果成功返回都不會對errno進行修改。
lt:當出現以上1、2的錯誤時,按以上方式註冊的套接字,會觸發無數次epollin/epollout和一次epollerr。
et:
均只觸發一次。
epoll_create(int size);
這個size是沒有什麼意義的,但是不能小於等於0,不然會出錯。
epoll的et和lt的比較:
lt:在epollout方面,只要緩衝區有空閒位置,就會觸發。而epollin事件,則只要資料沒讀完就會不斷觸發epollin。
在lt被發滿的緩衝區以後(此時win=0),out就停止了,但是通過tcpdump可以發現有時還有0位元組的資料報傳送到對端,這是為了避免糊塗視窗。
et:在out方面,第一次新增套接字 和 傳送緩衝區從滿變成非滿會觸發一次,但是只觸發一次。而in事件則有資料來觸發一次,而且會贈送一次epollout事件。
listen的套接字是不會觸發epollout事件,如果向它寫入,會發生sigpipe訊號。
利用getsockopt(conn_sock, sol_socket, so_sndbuf, &snd_size, &optlen);可以獲得sock的緩衝區大小,但是這個大小和傳輸層的win的大小不一致,win是不可控制的,有核心完成大小控制。而win卻剛好和 setsockopt(conn_sock, sol_socket, so_rcvbuf, &rcv_size, optlen);的rcv_size一樣大。
預設的sendbuffer在/proc/sys/net/ipv4/tcp_wmem
預設的recvbuffer在/proc/sys/net/ipv4/tcp_rmem
預設的sendbuffer在/proc/sys/net/core/wmem_max
預設的recvbuffer在/proc/sys/net/core/rmem_max
而最小值通過測試發現和網上說的不太一樣,所以沒有得出結論!!!mark一下,以後解決。
最小的sendbuffer=4608,recvbuffer=2304.
注意:不同的機器可能不同。我的機器版本:ubuntu14.04
write和read的阻塞和非阻塞行為:
read:
非阻塞:read讀到資料,那麼返回值為資料大小。讀不到,則返回eagain,表示資料還未就緒。
阻塞:read不管讀不讀夠buffersize指定的資料,只要讀到資料,都可能返回,沒有資料則阻塞。
如果read套接字返回值為0,那麼說明read到檔案未,要close套接字。
write:
非阻塞:只要寫入了資料就會返回寫入資料的大小,當緩衝區滿時,返回eagain,表示還不能寫入。
阻塞:這個和read不太一樣,必須要寫入buffersize的資料才能返回,否則阻塞。
write和sigpipe
阻塞和非阻塞的情況相同:
1.socket write中,對方socket斷開(進入close_wait),收到rst包,第一次寫,返回errno=104,不會產生sigpipe訊號。但第二次寫,就會產生sigpipe訊號,errno=32(這個要對sigpipe做處理才能看到,因為不做處理,程式直接崩潰,根本看不到)。
可以使用shutdown進入半關閉狀態。
2.如果read乙個已經close的套接字,會產生errno=9(無效套接字)的錯誤。
《Linux網路程式設計》讀書筆記
去年買了 linux網路程式設計 這本,沒想到一放就是半年的時間了,慚愧啊!當年的雄心壯志都去哪了 好,廢話不多說,從今天開始,每天積累一點,厚積才能薄發,磨刀不誤砍柴工。工資趕快漲 漲 1991年,linux開始誕生了,到2011年,linux的版本從2.6直接蹦到了3.0,據說這個沒什麼大意義,...
Linux網路程式設計學習筆記(五)
通過捕捉sigchld訊號捕捉殭屍程序,可解決多個子程序同時連線的情況 伺服器端 include include include include include include include include include void error handling char message void...
Linux網路程式設計學習筆記 索引
一 linux基本知識 學習筆記 linux平台的檔案i o操作 學習筆記 linux平台的檔案,目錄及操作 linux學習筆記 標準輸入輸出 linux學習筆記 程序概念及控制 linux學習筆記 訊號處理 二 程序間通訊 三 傳輸層協議tcp和udp 四 tcp套接字 五 udp資料報 六 套接...