socket函式 整理

2021-06-22 23:31:44 字數 4533 閱讀 9612

#include

int connect(int sockfd, const struct sockaddr* server_addr, socklen_t addrlen)

為了理解connect函式,我們需要對connect函式的功能進行介紹。connect函式的功能可以用一句話來概括,就是完成面向連線的協議的連線過程,它是主要連線的。面向連線的協議,在建立連線的時候總會有一方先傳送資料,那麼誰呼叫了connect誰就是先傳送資料的一方。如此理解connect三個引數是容易了,我必需指定資料傳送的位址,同時也必需指定資料從**傳送,這正好是connect的前兩個引數,而第三個引數是為第二個引數服務的。

引數sockfd

指定資料傳送的套接字,解決從**傳送的問題。核心需要維護大量io通道,所以使用者必需通過這個引數告訴核心從哪個io通道,此處就是從哪個socket介面中傳送資料。sockfd是先前socket返回的值。

引數server_addr

指定資料傳送的目的地,也就是伺服器端的位址。這裡伺服器是針對connect說的,因為connect是主動連線的一方呼叫的,所以相應的要存在乙個被連線的一方,被動連線的一方需要呼叫listen以接受connect的連線請求,如此被動連線的一方就是伺服器了。

引數addrlen

指定server_addr結構體的長度。我們知道系統中存在大量的位址結構,但socket介面只是通過乙個統一的結構來指定引數型別,所以需要指定乙個長度,以使核心在進行引數複製的時候有個有個界限。

在套介面中,乙個套接字只是使用者程式與核心互動資訊的樞紐,它自身沒有太多的資訊,也沒有網路協議位址和埠號等資訊,在進行網路通訊的時候,必須把乙個套接字與乙個位址相關聯,這個過程就是位址繫結的過程。許多時候核心會我們自動繫結乙個位址,然而有時使用者可能需要自己來完成這個繫結的過程,以滿足實際應用的需要,最典型的情況是乙個伺服器程序需要繫結乙個眾所周知的位址或埠以等待客戶來連線。這個事由bind的函式完成。

#include

int bind(int sockfd, struct sockaddr* addr, socklen_t addrlen)

引數sockfd

指定位址與哪個套接字繫結,這是乙個由之前的socket函式呼叫返回的套接字。呼叫bind的函式之後,該套接字與乙個相應的位址關聯,傳送到這個位址的資料可以通過這個套接字來讀取與使用。

引數addr

指定位址。這是乙個位址結構,並且是乙個已經經過填寫的有效的位址結構。呼叫bind之後這個位址與引數sockfd指定的套接字關聯,從而實現上面所說的效果。

引數addrlen

正如大多數socket介面一樣,核心不關心位址結構,當它複製或傳遞位址給驅動的時候,它依據這個值來確定需要複製多少資料。這已經成為socket介面中最常見的引數之一了。

bind函式並不是總是需要呼叫的,只有使用者程序想與乙個具體的位址或埠相關聯的時候才需要呼叫這個函式。如果使用者程序沒有這個需要,那麼程式可以依賴核心的自動的選址機制來完成自動位址選擇,而不需要呼叫bind的函式,同時也避免不必要的複雜度。在一般情況下,對於伺服器程序問題需要呼叫bind函式,對於客戶程序則不需要呼叫bind函式。

:listen函式使用主動連線套介面變為被連線套介面,使得乙個程序可以接受其它程序的請求,從而成為乙個伺服器程序。在tcp伺服器程式設計中listen函式把程序變為乙個伺服器,並指定相應的套接字變為被動連線。

listen函式在一般在呼叫bind之後-呼叫accept之前呼叫,它的函式原型是:

#include

int listen(int sockfd, int backlog)

返回:0──成功, -1──失敗

引數sockfd

被listen函式作用的套接字,sockfd之前由socket函式返回。在被socket函式返回的套接字fd之時,它是乙個主動連線的套接字,也就是此時系統假設使用者會對這個套接字呼叫connect函式,期待它主動與其它程序連線,然後在伺服器程式設計中,使用者希望這個套接字可以接受外來的連線請求,也就是被動等待使用者來連線。由於系統預設時認為乙個套接字是主動連線的,所以需要通過某種方式來告訴系統,使用者程序通過系統呼叫listen來完成這件事。

引數backlog

這個引數涉及到一些網路的細節。在程序正理乙個乙個連線請求的時候,可能還存在其它的連線請求。因為tcp連線是乙個過程,所以可能存在一種半連線的狀態,有時由於同時嘗試連線的使用者過多,使得伺服器程序無法快速地完成連線請求。如果這個情況出現了,伺服器程序希望核心如何處理呢?核心會在自己的程序空間裡維護乙個佇列以跟蹤這些完成的連線但伺服器程序還沒有接手處理或正在進行的連線,這樣的乙個佇列核心不可能讓其任意大,所以必須有乙個大小的上限。這個backlog告訴核心使用這個數值作為上限。

毫無疑問,伺服器程序不能隨便指定乙個數值,核心有乙個許可的範圍。這個範圍是實現相關的。很難有某種統一,一般這個值會小30以內。

當呼叫listen之後,伺服器程序就可以呼叫accept來接受乙個外來的請求。

對於伺服器程式設計中最重要的一步等待並接受客戶的連線,那麼這一步在程式設計中如何完成,accept函式就是完成這一步的。它從核心中取出已經建立的客戶連線,然後把這個已經建立的連線返回給使用者程式,此時使用者程式就可以與自己的客戶進行點到點的通訊了。

accept函式等待並接受客戶請求:

#include

int accept(int sockfd, struct sockaddr* addr, socklen_t* len)

返回:非負描述字——成功, -1——失敗

accept缺省會阻塞程序,直到有乙個客戶連線建立後返回,它返回的是乙個新可用的套接字,這個套接字是連線套接字。此時我們需要區分兩種套接字,一種套接字正如accept的引數sockfd,它是監聽套接字,在呼叫listen函式之後,乙個套接字會從主動連線的套接字變身為乙個監聽套接字;而accept返回是乙個連線套接字,它代表著乙個網路已經存在的點點連線。自然要問的是:為什麼要有兩種套接字?原因很簡單,如果使用乙個描述字的話,那麼它的功能太多,使得使用很不直觀,同時在核心確實產生了乙個這樣的新的描述字。

引數sockfd

引數sockfd就是上面解釋中的監聽套接字,這個套接字用來監聽乙個埠,當有乙個客戶與伺服器連線時,它使用這個乙個埠號,而此時這個埠號正與這個套接字關聯。當然客戶不知道套接字這些細節,它只知道乙個位址和乙個埠號。

引數addr

這是乙個結果引數,它用來接受乙個返回值,這返回值指定客戶端的位址,當然這個位址是通過某個位址結構來描述的,使用者應該知道這乙個什麼樣的位址結構。如果對客戶的位址不感興趣,那麼可以把這個值設定為null。

引數len

如同大家所認為的,它也是結果的引數,用來接受上述addr的結構的大小的,它指明addr結構所占有的位元組個數。同樣的,它也可以被設定為null。

如果accept成功返回,則伺服器與客戶已經正確建立連線了,此時伺服器通過accept返回的套接字來完成與客戶的通訊。

對於網路tcp面向連線的程式,它需要在某個時候終止已經存在的連線。使用者可以主動終止乙個連線,這很重要,尤其對於伺服器程序而言,因為乙個程序可以同時開啟的連線是有限的,如果不在某個時候主動終止已有的連線,那麼對於伺服器程序來說,它總會在某個時候因為無法開啟新連線而失敗。

對於unix系統而言,無論是一般的檔案描述符,還是網路中使用的套接字都是描述字的範圍,所以它們都可以用close函式來完成關閉的任務,然後對於網路套接字這乙個特殊的描述字,我們卻可以使用更加豐富的shutdown函式完成有選擇的關閉。下面我們先來看看這個兩個函式:

#include

int close

(int fd

)返回:

0——成功, 

-1——失敗

#include

int shutdown

(int sockfd, 

int howto

)返回:

0——成功, 

-1——失敗

讓我們來回憶一下,乙個檔案描述符關聯著乙個實際的檔案——不管這個檔案是什麼,普通檔案或網路套介面等等,但是多個打字可以同時與乙個檔案關聯,並且核心維護乙個檔案引用計數。正常情況下,close函式不武斷地釋放乙個描述字關聯的檔案,除了這個引用計數為0的時候,並且無論如何,當對乙個描述字呼叫了close函式,使用者無法再次使用這個描述字。這是close相對shutdown的兩點差別,相應地shutdown是針對socket套介面定製的函式,所以它會做的更好。

shutdown函式不是參考引用計數,它會直接關閉相應的socket套介面,無論引用計數是多少。我們還知道,socket套介面是全雙工的,也就是使用者可以讀,也可以寫。存在乙個這樣的情況,此時使用者已經把所有要寫的資料都寫完了,他想告訴對等端這一點;或者使用者把所有要讀的資料都讀完成了,同樣要告訴對等端。此時就是關閉讀這一半或寫這一半,使用shutdown可以完成這乙個。系統定義了3個巨集,這3個巨集分別用作shutdown的後乙個引數:

剛才我寫完了伺服器程式設計之fork並行模式,這個文章中我們使用close函式,試問一下:我們可以使用shutdown函式代替嗎?簡單的思考之後,我們知道不可以使用shutdown函式代替,因為我們在子程序中只是想解除sockfd與那個監聽套介面的關聯,並不想釋放這個套介面,原因是在父程序還要使用它;相應在父程序我也只是想解除cfd與其套介面的關聯,我們在子程序還需要使用cfd。從這個例子中可以看到,close與shutdown有各自的用處,並不能相互代替,就算在socket套接字這一特定情況下也如此。

資料整理 socket之select函式

select在socket程式設計中還是比較重要的,它能夠監視我們需要監視的檔案描述符的變化情況 讀寫或是異常。select的函式格式 unix系統下的伯克利socket程式設計,和windows下的略有區別,體現兩個方面 一是select函式的第乙個引數,在windows下可以忽略,但在linux...

socket程式設計整理

udp和tcp的對比 簡單點說。udp處理的細節比tcp少。udp不能保證訊息被傳送到 它也報告訊息沒有傳送到 目的地。udp也不保證資料報的傳送順序。udp把資料發出去後只能希望它能夠抵達目的地。tcp優缺點 優點 1 tcp提供以認可的方式顯式地建立和終止連線。2 tcp保證可靠的 順序的 資料...

封裝socket整理

不管是socket通訊程式的客戶端還是服務端,準備工作的 較長,影響了主程式的簡潔性,不過可以分離出來,追求簡單實用。用c語言封裝 c語言只能把程式封裝成函式。測試 客戶端 int connectclient const char severip,const int port include inc...