1.創建socket
sk = socket(int family, int type, int protocol);
family:協議簇,PF_INET、PF_INET6、PF_PACKET等等。
type:類型,SOCK_DGRAM、SOCK_STREAM、SOCK_RAW等等。
protocol:協議,協議簇上面的協議,這個字段不可以使用組合方式,只能使用一個(例如不能使用IPPROTO_UDP|IPPROTO_ICMP)。
協議棧收到數據包是從family開始匹配的,之后匹配type,protocol,如果family是PF_PACKET,則繼續匹配protocol(此時沒有類型區分)。
2.socket參數組合
[1]創建INET TCP/UDP socket:
socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); //創建UDP socket,第三個參數可以填0,填0默認是用UDP類型
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); //創建TCPsocket,第三個參數可以填0,填0默認是用TCP類型
收到的為應用層數據,發送時填充應用層數據。
[2]創建INET RAW socket:
socket(PF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP);
收到的是從IP頭開始的數據,發送時從IP協議之后填充,例如UDP協議時填充UDP頭+應用數據,TCP則填充TCP頭+應用數據。
如果設置了IP_HDRINCL選項:setsockopt(sk, IPPROTO_IP, IP_HDRINCL, &option, sizeof(option)),則UDP協議時發送時填充IP頭+UDP頭+應用數據。
socket(PF_INET, SOCK_RAW, IPPROTO_RAW); //收發都是從ip頭開始,等於自動設置IP_HDRINCL選項
[3]創建鏈路層socket:
socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))
收到的是從二層頭開始的完整數據包,當第三個參數是ETH_P_ALL時,可以接收到從本機發出去的數據包。
socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))
收到的是從二層頭上面開始的數據包。
3.總結
[1]SOCK_RAW類型通常稱為"原始套接字",這里的"原始"是相對來說的,例如協議簇是PF_INET時,則原始就是IP層的起始。協議簇是PF_PACKET時,則原始就是二層的起始。