這個是的嵌入式liux 開的第二篇,網路基礎。
方法/步驟
1.1 網路基本概念
1.1.1 IP網路資料傳輸方式
組播技術是IP網路資料傳輸三種方式之一,在介紹IP組播技術之前,先對IP網路資料傳輸的單播、組播和廣播方式做一個簡單的介紹:單播(Unicast)傳輸:在傳送者和每一接收者之間實現點對點網路連線。如果一臺傳送者同時給多個的接收者傳輸相同的資料,也必須相應的複製多份的相同資料包。
組播(Multicast)傳輸:在傳送者和每一接收者之間實現點對多點網路連線。如果一臺傳送者同時給多個的接收者傳輸相同的資料,也只需複製一份的相同資料包。它提高了資料傳送效率。減少了骨幹網路出現擁塞的可能性。
廣播(Broadcast)傳輸:是指在IP子網內廣播資料包,所有在子網內部的主機都將收到這些資料包。廣播意味著網路向子網每一個主機都投遞一份資料包,不論這些主機是否樂於接收該資料包。所以廣播的使用範圍非常小,只在本地子網內有效,通過路由器和網路裝置控制廣播傳輸。
1.1.2 網路基本結構體
1.地址結構相關處理
(1)資料結構介紹
下面首先介紹兩個重要的資料型別:sockaddr 和sockaddr_in,這兩個結構型別都是用來儲存socket資訊的,如下所示:
struct sockaddr {
unsigned short sa_family; /*地址族*/
char sa_data[14]; /*14位元組的協議地址,包含該socket的IP地址和埠號*/
};
struct sockaddr_in {
short int sa_family; /*地址族*/
unsigned short int sin_port; /*埠號*/
struct in_addr sin_addr; /*IP地址*/
unsigned char sin_zero[8]; /*填充0 以保持與structsockaddr同樣大小*/
};
這兩個資料型別是等效的,可以相互轉化,通常sockaddr_in資料型別使用更為方便。在建立socketadd或sockaddr_in後,就可以對該socket 進行適當的操作了。
函式
摘要:對於伺服器程式設計中最重要的一步等待並接受客戶的連線,那麼這一步在程式設計中如何完成,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返回的套接字來完成與客戶的通訊。
send函式
int send( SOCKET s, const char FAR *buf, int len,int flags );
不論是客戶還是伺服器應用程式都用send函式來向TCP連線的另一端傳送資料。
客戶程式一般用send函式向伺服器傳送請求,而伺服器則通常用send函式來向客戶程式傳送應答。
該函式的第一個引數指定傳送端套接字描述符;
第二個引數指明一個存放應用程式要傳送資料的緩衝區;
第三個引數指明實際要傳送的資料的位元組數;
第四個引數一般置0。
這裡只描述同步Socket的send函式的執行流程。linux的緩衝區預設大小為8K參考部落格修改http://blog.csdn.net/maopig/article/details/6982457。當呼叫該函式時,send先比較待發送資料的長度len和套接字s的傳送緩衝的長度,如果len大於s的傳送緩衝區的長度,該函式返回SOCKET_ERROR;如果len小於或者等於s的傳送緩衝區的長度,那麼send先檢查協議是否正在傳送s的傳送緩衝中的資料,如果是就等待協議把資料傳送完,如果協議還沒有開始傳送s的傳送緩衝中的資料或者s的傳送緩衝中沒有資料,那麼send就比較s的傳送緩衝區的剩餘空間和len,如果len大於剩餘空間大小send就一直等待協議把s的傳送緩衝中的資料傳送完,如果len小於剩餘空間大小send就僅僅把buf中的資料copy到剩餘空間裡(注意並不是send把s的傳送緩衝中的資料傳到連線的另一端的,而是協議傳的,send僅僅是把buf中的資料copy到s的傳送緩衝區的剩餘空間裡)。如果send函式copy資料成功,就返回實際copy的位元組數,如果send在copy資料時出現錯誤,那麼send就返回SOCKET_ERROR;如果send在等待協議傳送資料時網路斷開的話,那麼send函式也返回SOCKET_ERROR。要注意send函式把buf中的資料成功copy到s的傳送緩衝的剩餘空間裡後它就返回了,但是此時這些資料並不一定馬上被傳到連線的另一端。如果協議在後續的傳送過程中出現網路錯誤的話,那麼下一個Socket函式就會返回SOCKET_ERROR。(每一個除send外的Socket函式在執行的最開始總要先等待套接字的傳送緩衝中的資料被協議傳送完畢才能繼續,如果在等待時出現網路錯誤,那麼該Socket函式就返回SOCKET_ERROR)注意:在Unix系統下,如果send在等待協議傳送資料時網路斷開的話,呼叫send的程序會接收到一個SIGPIPE訊號,程序對該訊號的預設處理是程序終止。
recv函式int recv( SOCKET s, char FAR *buf, int len, int flags );
不論是客戶還是伺服器應用程式都用recv函式從TCP連線的另一端接收資料。
該函式的第一個引數指定接收端套接字描述符;
第二個引數指明一個緩衝區,該緩衝區用來存放recv函式接收到的資料;
第三個引數指明buf的長度;
第四個引數一般置0。
這裡只描述同步Socket的recv函式的執行流程。當應用程式呼叫recv函式時,recv先等待s的傳送緩衝中的資料被協議傳送完畢,如果協議在傳送s的傳送緩衝中的資料時出現網路錯誤,那麼recv函式返回SOCKET_ERROR,如果s的傳送緩衝中沒有資料或者資料被協議成功傳送完畢後,recv先檢查套接字s的接收緩衝區,如果s接收緩衝區中沒有資料或者協議正在接收資料,那麼recv就一直等待,只到協議把資料接收完畢。當協議把資料接收完畢,recv函式就把s的接收緩衝中的資料copy到buf中(注意協議接收到的資料可能大於buf的長度,所以在這種情況下要呼叫幾次recv函式才能把s的接收緩衝中的資料copy完。recv函式僅僅是copy資料,真正的接收資料是協議來完成的),recv函式返回其實際copy的位元組數。如果recv在copy時出錯,那麼它返回SOCKET_ERROR;如果recv函式在等待協議接收資料時網路中斷了,那麼它返回0。
注意:在Unix系統下,如果recv函式在等待協議接收資料時網路斷開了,那麼呼叫recv的程序會接收到一個SIGPIPE訊號,程序對該訊號的預設處理是程序終止。網路中的細節問題參考Linux 套接字程式設計中的 5 個隱患,URL: