selelct函式的需要原因

2021-06-21 21:53:52 字數 1679 閱讀 3348

先看一段**,實現的是echo回射功能,我們從這個程式中,來模擬伺服器程序先於客戶程序終止後,它會發生哪些問題。。
#include "unp.h"

int main(int argc,char**argv)

close(connfd); }}

void str_echo(int connfd)

//int main(int argc,char**argv)

void str_cli(file*fp,int sockfd)

}

現在啟動我們的客戶/伺服器對,一切正常,回射功能實現完好。

接下來,我們先殺死伺服器子程序。這是在模擬伺服器程序崩潰的情形,我們可檢視客戶將發生什麼,(要區分伺服器崩潰和伺服器程序崩潰的情形)

1,執行kill命令,作為程序終止處理的部分工作,子程序中的所有開啟的程序描述符都被關閉,這就導致向客戶傳送乙個fin,而客戶tcp則響應乙個ack(這是tcp的自動實現機制,並不需要使用者做什麼)

(這裡要注意用詞, 區別客戶程序,客戶tcp ,伺服器程序,伺服器tcp),這就是tcp連線終止的前半部分。

2,sigchild訊號被傳送個伺服器父程序,並得到正確處理。

3,這時候的狀態是,fin已經到了客戶的tcp,即到了接受緩衝區了,但是還沒有到使用者緩衝區,客戶程式沒有讀取,而伺服器端tcp已經接受了ack,進入了fin_wait2

狀態了。 且,因為客戶tcp接受到了fin分節,故它進入了close_wait狀態。 可以用netstat檢視。

4, 然而,問題在於,這個fin分節並沒有被客戶程序讀取,它還存在與接受緩衝區,這時客戶程序阻塞在fgets上面,等待使用者從終端輸入。

當我們鍵入 「另外一行」 ,這時候客戶程序呼叫write,緊接著,客戶tcp把資料傳送出去。(tcp允許這麼做,因為客戶tcp受到fin,只是表示伺服器程序已經關閉了連線的

伺服器端,從而不再向其中傳送資料而已,但還可有接受資料,fin的接受並沒有告知客戶tcp,伺服器程序,(注意用詞,tcp和程序)已經終止了,不過它在本例中確實終止了,因為我們已經kill了。)

5,當伺服器tcp接受到客戶的資料時候,既然先前開啟的那個套接字的程序已經終止了,於是,伺服器tcp會響應乙個rst。告知對端,埠已經關閉。(這時候伺服器子程序已經終止,是核心中的tcp協議來做的這件事)。

5,然而,客戶程序確看不見這個rst,原因在於:因為它呼叫write後,立即會呼叫read從接受緩衝區中接受資料,我們還記得,在接受緩衝區中存在乙個分節,即

還沒有別客戶程序讀取的伺服器tcp傳送的fin分節,那麼這時候呼叫read,它就會讀到這個fin,然後,read理解返回0,於是列印「server terminated prematruely」,

6,自此,客戶終止程序了(呼叫err_quit),所有開啟的描述符都關閉了 。這個 客戶程序永遠也讀不到這個rst分節。

本例子的問題在於:當fin達到套接字緩衝區時候,客戶正阻塞在fgets呼叫。客戶實際上在應對兩個描述符----套接字和使用者輸入。事實上,這正視select和poll兩個函式的目的之一。不然程序阻塞在某個特定的輸入上。    一旦伺服器殺死子程序,客戶就會立刻從緩衝區讀出fin。

從這個例子也很好地反映了             tcp程序和tcp 的一些關聯與區別。                以及 描述符與流的關係  緩衝區 的關係。

需要友元的原因及使用

有時候,普通函式需要直接訪問乙個類的保護或私有資料成員。如果沒有友元機制,則只能將類的資料成員宣告為公共的,從而,任何函式都可以無約束的訪問它。普通函式需要直接訪問類的保護或私有資料成員的原因主要是為提高效率。在類裡宣告乙個普通函式,標上關鍵字friend,就成了該類的友元,可以訪問該類的一切成員。...

python不需要過載的原因

函式過載主要是為了解決兩個問題。1 可變引數型別。2 可變引數個數。另外,乙個基本的設計原則是,僅僅當兩個函式除了引數型別和引數個數不同以外,其功能是完全相同的,此時才使用函式過載,如果兩個函式的功能其實不同,那麼不應當使用過載,而應當使用乙個名字不同的函式。好吧,那麼對於情況 1 函式功能相同,但...

關於物件新增的屬性需要 set原因

其實在 vue3.x 還沒有發布 bate 的時候,很火的乙個話題就是vue3.x 將使用 proxy 取代 vue2.x 版本的 object.defineproperty。沒有無緣無故的愛,也沒有無緣無故的恨。為何要將object.defineproperty換掉呢,咋們可以簡單聊一下。我剛上手...