1. 程式人生 > >原始套接字程式設計介面

原始套接字程式設計介面

1.建立套接字

原始套接字可以用socket函式來建立,但第二個引數為SOCK_RAW,第三個引數protocol有使用者設定,可以使用WinSock2.h中定義的字首為IPPROTO_XXX的長值。另外,使用者也可以選擇一個頭檔案中沒有定義的數值,直接在socket函式中傳入數值即可。

2.設定選項

大部分選項設定與TCP/UDP套介面是一樣的,有一個選項IP_HDRINCL,只試用於原始套介面,用於控制是否使用者自己構造ip首部,如果設定非0值,使用者自己構造ip首部及後面的資料;設定0值時,這是預設的情況,使用者只需要構造ip首部之後的資料部分,ip首部有系統自動填寫

3繫結套介面

在原始套介面上呼叫bind()函式,只是設定本地地址,系統並不關心埠值,因為原始套介面沒有埠的概念。通常原始套介面不呼叫bind,而是在傳送資料是有系統自己選擇外出介面。當bind()中地址不屬於本機任何網路介面時,函式會失敗。

4連線套介面

函式connect設定原始套介面的目的地址,也不關心埠值,並把套介面標識為已連線,這裡的已連線至表示設定了目的地址。本地地址不受connect的影響,沒有呼叫bind()時,仍然是未設定的。

5傳送資料

傳送資料通常都用sendto(),在引數to中指定要傳送的目的地址,如果嗲用了connect,也可以呼叫send傳送。

6接受資料

接受資料通常使用recvfrom,如果不關心對方的地址,也可以使用recv,呼叫recvfrom之前必須呼叫過bind,connect或者sendto中的函式,將本地或目的的地址資訊告訴系統,如果直接呼叫recvfrom,WinSock返回失敗。

7關閉

關閉原始套介面與關閉其他型別的套介面是一樣的,呼叫closesocket函式即可。

輸出處理:

原始套介面傳送資料通常用sendto(),第五個引數to中指定要傳送的目的地址。如果呼叫過connect,目的地址已經設定,傳送資料時,可以直接跳用send,當然也可以呼叫sendto(),並且第五個引數to設定為NULL,當to不為null,系統會把資料傳送到to所指定的目的地址,但呼叫connect時儲存在陶介面中的目的地址不會改變。這樣產生的問題

是如果to中與connect的地址不同,由於這個套介面的目的地址是connect指定的,故從to中地址輸入的資料報就不會再這個套介面上受到資料。

傳送的目的地址可以是任何有效ip地址,包括廣播或多播地址。為了向廣播地址傳送資料,程式必須使用選項SO_BROADCAST呼叫setsocketopt設定套接口才能夠廣播,否則send或sendto將失敗,錯誤程式碼為WSAEACCESS。使用原始套介面的應用程式不需要加入一個多播組,就可以向該組播地址傳送資料。

原始套介面傳送的資料長度,包括ip首部在內不能大於ip協議允許的最大值(65535)

如果設定了IP_HDRINCL選項,使用者需要自己構造ip首部及其後面的資料,提供給系統的資料長度也包括了ip首部在內。如果ip首部後面的資料需要校驗和,則必須自己計算。

對ip首部校驗和有系統計算,識別符號可以設定為0,系統會設定識別符號欄位。Windows中填寫ip首部時,各欄位的值都需要使用網路位元組序,這與FreeBSD的實現不同,FreeBSD的ip資料報長度ip_len,片偏移ip_off要使用主機位元組序。

未設定IP_HDRINCL選項時,這也是預設值,傳送資料是傳給系統緩衝區是ip首部之後的資料,系統會在使用者資料前增加一個ip首部,並填寫ip首部中的各個欄位。其中協議欄位設定為呼叫socket函式的第三個引數,原地址是bind的本地地址,沒有呼叫bind是,系統根據外出藉口自動設定。目的地址是connect或sendto中指定的地址。

輸出資料的長度超過外出網路介面的最大傳送但願MTU時,ip協議對資料分片。

輸入處理:

原始套介面接受資料通常使用recvform,第五個引數from可以返回地方的地址,如果應用程式不關心對方的地址,也可以使用recv接受資料

對於ipv4應用程式接受的是整個ip資料報,包含ip首部,即總是指向ip首部的第一個位元組,不管是否設定IP_HDRINCL選項,IP首部中的所有位元組都是網路位元組序。

如果資料報時分片的,ip協議在收到所有分片後進行重組,並把完整的資料報交給套介面。

在TCP/IP協議棧接受到一個完整的資料報後,他檢查所有的套介面,找到與資料報中資訊匹配的套介面,並把該資料報復制一份,複製到匹配的套介面中,對原始套介面,如下圖的條件進行檢查。