socket編程 ------ BSD socket API

伯克利套接字Berkeley sockets),也稱爲BSD Socket。伯克利套接字的應用編程接口(API)是採用C語言的進程間通信的庫,經常用在計算機網絡間的通信。 BSD Socket的應用編程接口已經是網絡套接字的抽象標準。大多數其他程序語言使用一種相似的編程接口。它最初是由加州伯克利大學爲Unix系統開發出來的。所有現代的操作系統都實現了伯克利套接字接口,因爲它已經是連接互聯網的標準接口了。

 

 API函數

以下函數是最基本的 socket API

  • socket() 創造某種類型的套接字,分配一些系統資源,用返回的整數識別。
  • bind() 一般是用在服務器這邊,和一個套接字地址結構相連,比如說是一個特定的本地端口號和一個IP地址。
  • listen()用在服務器一邊,導致一個綁定的TCP套接字進入監聽狀態。
  • connect() 用在客戶機這邊,給套接字分配一個空閒的端口號。比如說一個TCP套接字,它會試圖建立一個新的TCP連接。
  • accept() 用在服務器這邊。從客戶機那接受請求試圖創造一個新的TCP連接,並把一個套接字和這個連接相聯繫起來。
  • send() and recv(), or write() and read(), or sendto() and recvfrom()用來接收和發送數據。
  • close() 當套接字的引用計數爲0的時候纔會引發TCP的四次揮手,關閉連接,系統釋放資源。------- 不可對某個socket連續調用兩次close,否則第二次調用會出現釋放未分配的內存問題(野指針)(在LWIP下測試得出的結論)。個人想法:應該在close函數裏面把socket置成某個數,這樣每次進入close,如果socket等於某個數,表示已經close過,直接函數返回。
  • shutdown()  不用管套接字的引用計數,調用讀寫函數返回小於0的數,退出阻塞。

 

以下函數用來設置 / 獲取套接字的屬性,有些函數的功能有重疊;fcntl() 和 ioctl() 功能比較強大,在linux c 中不僅僅用來網絡編程

  • gethostbyname() and gethostbyaddr()用來解析主機名和地址。
  • select() ------ 用來獲取指定套接字的狀態(可讀、可寫或者出錯)
  • fcntl() ------ 設置套接字的工作模式(阻塞或非阻塞)
  • ioctl()
  • poll() is used to check on the state of a socket in a set of sockets. The set can be tested to see if any socket can be written to, read from or if an error occurred.
  • getsockopt() ------ 獲得套接字的屬性,有些屬性的開關在 opt.h 和 lwipopts.h
  • setsockopt() ------ 設置套接字的屬性,有些屬性的開關在 opt.h 和 lwipopts.h
  • getsockname()、getpeername() ------ 用於獲取本地、對方IP和端口號

 

以下函數用來數據的轉換

  • ntohs()、ntohl()、htons()、htonl()   ------ 大端編碼和小端編碼的轉換,s表示short(16bit),l表示long(32bit);h 代表 host,就是本地主機的表示形式; n 代表 network,表示網絡上傳輸的字節序
  • inet_ntoa() 、inet_addr()  ----- inet_ntoa()將一個 32bits 無符號整數轉換爲點分十進制IP格式的字符串,inet_addr()正好相反
  • inet_pton()  ---- inet_pton() 的功能和 inet_addr() 功能類似
  • IP4_ADDR --- 把 IP地址中的4個數字整合放到 u32 類型的變量

 

 

 

 

更多的函數說明如下:

recv、send和read、write

這四個函數用在 TCP 通信中

 

recv和send函數提供了和read和write差不多的功能.不過它們提供了第四個參數來控制讀寫操作

int recv(int sockfd,void *buf,int len,int flags)
int send(int sockfd,void *buf,int len,int flags)

對於send(),flags取值有:
0: 與write()無異,阻塞操作
MSG_DONTROUTE:告訴內核,目標主機在本地網絡,不用查路由表
MSG_DONTWAIT:將單個I/O操作設置爲非阻塞模式
MSG_OOB:指明發送的是帶外信息


對於recv(),flags取值有:
0:與read()無異,阻塞操作
MSG_DONTWAIT:將單個I/O操作設置爲非阻塞模式
MSG_OOB:指明發送的是帶外信息
MSG_PEEK:表示只是從系統緩衝區中讀取內容,而不清除系統緩衝區的內容.這樣下次讀的時候,仍然是一樣的內容.一般在有多個進程讀寫數據時可以使用這個標誌.
MSG_WAITALL:通知內核直到讀到請求的數據字節數時,或者發送了錯誤才返回。


對於接收數據函數的返回值:
大於0:讀到數據的字節數
等於0:套接字關閉,讀到FIN
小於0:
  EINTR:表示操作被中斷,下次可以繼續讀取,忽視這個返回值
  EWOULDBLOCK(EAGAIN):當非阻塞讀取時,沒有數據可讀,返回此操作碼
  ECONNRESET:對方發送RST
  ......

對於發送數據函數的返回值:
大於0:成功發送數據的字節數
等於0:套接字關閉
小於0:
  EINTR:表示連接正常,操作被中斷,此次數據發送失敗,下次可以繼續發送
  EWOULDBLOCK(EAGAIN):表示連接正常,但發送緩衝區沒有空間,此次數據發送失敗,下次可以繼續發送
  ......

注:不能通過 shutdown 讀寫通道主動退出服務器的阻塞read(),但是可以主動退出退出客戶端的阻塞read(),ESP8266測試得到

recvfrom、sendto

這兩個函數用在UDP通信的接收和發送

int recefrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
int sendto(int sockfd, const void *buf, size_t size, int flags, const struct sockaddr *to, socklen_t tolen)

 

socket()

函數原型:

int socket(int domain, int type, int protocol);

socket() 爲通信創造一個端點並返回一個文件描述符。 socket() 有三個參數:

  • domain,確定地址協議。例如:
    • PF_INET (AF_INET)是IPv4 
    • PF_INET6 是 IPv6.
  • type,是下面中的一個:
    • SOCK_STREAM (Stream Socket)
    • SOCK_DGRAM (Datagram Socket)
    • SOCK_RAW (Raw Socket)。
  • protocol, 規定套接字發送和接送哪類型協議數據。最常見的是 IPPROTO_TCPIPPROTO_UDPIPPROTO_UDPLITE、IPPROTO_ICMP。如果 domain 和 type已經確定唯一的協議,“0(IPPROTO_IP” 可以用來表示選擇一個默認的協議。

例子:

tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_IP); // 由於 PF_INET 和 SOCK_STREAM 已經可以確認是使用 IPPROTO_TCP,所以第三個參數填什麼都不影響

udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); // PF_INET 和 SOCK_DGRAM 表明使用 IPPROTO_UDP 或 IPPROTO_UDPLITE 其中一種協議,第三個參數填的不是 IPPROTO_UDPLITE 都是IPPROTO_UDP

 

 

 

如果出錯返回-1,否則返回一個代表文件描述符的整數(一般有個宏NUM_SOCKETS規定一共可以創建多少個socket,所以socket()創建成功返回的整數範圍爲0~NUM_SOCKETS-1,而且是從小到大返回)

 

bind()

bind() 給套接字分配一個地址。當使用 socket()創造一個套接字時, 只是給定了協議族,並沒有分配地址。在套接字能夠接受來自其他主機的連接前,必須用bind()給它綁定一個地址。 bind() 由三個參數:

  • sockfd, 代表socket的文件描述符。
  • my_addr, 指向 sockaddr 結構體的指針,代表要綁定的地址 。
  • addrlen, 是sockaddr結構體的大小。

Bind()返回0表示成功,錯誤返回-1。

函數原型:

int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);

 

 listen()

一旦一個套接字和一個地址聯繫之後,listen() 監聽到來的連接。但是這隻適用於對面向連接的模式,例如 套接字類型是 (SOCK_STREAMSOCK_SEQPACKET)。listen()需要兩個參數:

  • sockfd:一個有效的套接字描述符。
  • backlog:accept 隊列大小。當服務器接收到第三次握手後將連接放入這個隊列中,直到被 accept 處理才清除,當 accept 隊列滿了之後,即使 client 繼續向 server 發送 ACK 包,也不會被響應,此時 ListenOverflows+1,同時 server 通過 /proc/sys/net/ipv4/tcp_abort_on_overflow(linux kernel 2.2 之後)來決定如何返回,0表示直接丟棄該 ACK,1表示發送 RST 通知 client;相應的,client 則會分別返回 read timeout 或者 connection reset by peer。參考下圖。

一旦連接被接受,返回0表示成功,錯誤返回-1。

函數原型:

int listen(int sockfd, int backlog);

 

 

accept()

當應用程序監聽來自其他主機的面對數據流的連接時,通過事件(比如Unix select()系統調用)通知它。必須用accept()函數初始化連接。 Accept() 爲每個連接創立新的套接字並從監聽隊列中移除這個連接。它使用如下參數:

  • sockfd,監聽的套接字描述符
  • cliaddr, 指向sockaddr 結構體的指針,客戶機地址信息。
  • addrlen,指向 socklen_t的指針,確定客戶機地址結構體的大小 。

返回新的套接字描述符,出錯返回-1。和客戶端的通信是通過這個套接字。假如是 sockfd(服務器套接字,accept 第一個參數) 0,accpet 返回的是 1,遞增。可以在沒關閉 accept 返回的套接字之前關閉 accept 的套接字,這樣防止新的客戶端連上。但是有個問題,如果關閉服務器套接字,accept 返回一個套接字是1,用 select 函數的第一個參數填套接字總數,現在的總是是1,而唯一個套接字的值是1(不是0),所以 select 會返回小於0,不能正常使用 select 函數。

Datagram 套接字不要求用accept()處理,因爲接收方可能用監聽套接字立即處理這個請求。

函數原型:

int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

 注:不能通過 close() 或者 shutdown() 主動退出 accept() 阻塞,ESP8266測試得出。

 

connect()

connect()系統調用爲一個套接字設置連接,參數有文件描述符和主機地址。

函數原型:

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

 

close()

close()函數只是將這個套接字引用計數減1,就像rm一樣,刪除一個文件時只是移除一個硬鏈接數,只有這個套接字的所有引用計數減到0,套接字描述符纔會真的被關閉,纔會開始後續的四次揮手。

 關於引用計數:操作系統創建子進程時,子進程將繼承父進程打開的套接字,父子進程擁有對該套接字同樣的訪問權,系統對每個套接字的引用進行計數,每增加一個進程訪問套接字,計數加1,當進程完成對套接字的使用時,對套接字的使用調用 close 進行關閉,close 調用將減少套接字的引用計數,並且在計數值爲0時刪除該套接字

 

SO_LINGER選項對close()的行爲有影響

SO_LINGER 的 I_onoff 爲0(默認情況):

在套接字上不能再發出發送或接收請求,套接字發送緩衝區中的內容被髮送到對端,如果描述符引用計數變爲0,在發送完發送緩衝區的數據後,後跟正常的TCP連接終止序列(即發送FIN),套接字接收緩衝區中的內容被丟棄

SO_LINGER 的 l_onoff = 1,l_linger = 0:

在套接字上不能再發出發送或接收請求,如果描述符引用計數變爲0,RST被髮送到對端,連接的狀態被置爲CLOSED(沒有TIME_WAIT狀態),套接字發送緩衝區和接收緩衝區中的內容被丟棄;

 

shutdown() 

可以指定關閉讀通道、寫通道或者讀寫通道。

ESP8266 LWIP TCP客戶端情況下(不推薦用shutdown退出阻塞,推薦用select()):

  調用了shutdown()的讀通道,不會引發四次揮手,但是執行read()會退出阻塞,返回小於0的數,然後再close()引發四次揮手,釋放資源。

  特別強調:執行 shutdown() 後執行 close(),然後再執行read()會阻塞,永遠的阻塞。。。

 

gethostbyname() 和 gethostbyaddr()

gethostbyname() 和 gethostbyaddr()函數是用來解析主機名和地址的。可能會使用DNS服務或者本地主機上的其他解析機制(例如查詢/etc/hosts)。返回一個指向 struct hostent的指針,這個結構體描述一個IP主機。函數使用如下參數:

  • name 指定主機名。例如 www.wikipedia.org
  • addr 指向 struct in_addr的指針,包含主機的地址。
  • len 給出 addr的長度,以字節爲單位。
  • type 指定地址族類型 (比如 AF_INET)。

出錯返回NULL指針,可以通過檢查 h_errno 來確定是臨時錯誤還是未知主機。正確則返回一個有效的 struct hostent *。

這些函數並不是伯克利套接字嚴格的組成部分。這些函數可能是過時了,新函數是 getaddrinfo() and getnameinfo(), 這些新函數是基於addrinfo數據結構。

函數原型:

struct hostent *gethostbyname(const char *name);
struct hostent *gethostbyaddr(const void *addr, int len, int type);

 


 

setsockopt()、getsockopt()

int setsockopt( int socket, int level, int option_name, const void *option_value, size_t option_len);

 sockfd:             套接字
 level:                協議層(SOL_SOCKET、IPPROTO_IP、IPPRO_TCP)
 opt_name:       選項名,每一個協議層都有其一些固定的選項名,
 option_value:   緩衝區,setsockopt() 是指向將要存放的地址,getsockopt() 是指向目前存放信息的地址
 option_len:      緩衝區大小長度 

 

在 socket.h 有 level 和 opt_name 的介紹

SOL_SOCKET層,有如下選項:  

 opt_name  說明  option_value類型
 SO_BROADCAST  允許發送和接收廣播數據  int
 SO_DEBUG  允許調試  int
 SO_DONTROUTE  不查找路由  int
 SO_ERROR  獲得套接字錯誤  int
 SO_KEEPALIVE  保持連接  int
 SO_LINGER  延遲關閉連接  struct linger
 SO_OOBINLINE  帶外數據放入正常數據流  int
 SO_RCVBUF  接收緩衝區大小  int
 SO_SNDBUF  發送緩衝區大小  int
 SO_RCVLOWAT  接收緩衝區下限  int
 SO_SNDLOWAT  發送緩衝區下限  int
 SO_RCVTIMEO  接收超時  struct timeval
 SO_SNDTIMEO  發送超時  struct timeval
 SO_REUSERADDR  允許重用本地地址和端口  int
 SO_TYPE  獲得套接字類型  int
 SO_BSDCOMPAT  與BSD系統兼容  int
   ......

 

IPPROTO_TCP層,有如下選型:

TCP_NODELAY

TCP_KEEPIDLE(設置多久沒接收到數據開始發送keepalive包)

TCP_KEEPINTVL(設置每個keepalive包的間隔時間)

TCP_KEEPCNT(設置發送多少個keepalive包)

......

 

ntohs()、ntohl()、htons()、htonl()

ntohs(n)     //n爲16位數據類型,網絡字節順序到主機字節順序的轉換  

htons(n)     //n爲16位數據類型,主機字節順序到網絡字節順序的轉換  

ntohl(n)      //n爲32位數據類型,網絡字節順序到主機字節順序的轉換  

htonl(n)      //n爲32位數據類型,主機字節順序到網絡字節順序的轉換  

網絡字節順序採用大端模式進行編址,而主機字節順序根據處理器的不同而不同,如PowerPC處理器使用大端模式,而Pentuim處理器使用小端模式。大端模式處理器的字節序到網絡字節序不需要轉換,此時ntohs(n)=n,ntohl(n) = n;而小端模式處理器的字節序到網絡字節必須要進行轉換

 

select()

int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout)

本函數用於確定一個或多個套接口的狀態。對每一個套接口,調用者可查詢它的可讀性、可寫性及錯誤狀態信息。用結構體 fd_set 來表示一組等待檢查的套接口。在調用返回時,這個結構存有滿足一定條件的套接口組的子集,並且select()返回滿足條件的套接口的數目,0表示超時,-1表示出錯。有一組宏可用於對 fd_set 的操作(宏的功能有:把套接口放入 fd_set 結構、清除 fd_set 結構中的某個套接口、檢查否個套接口是否可讀可寫等)

 

maxfdp1:等於創建成功的socket個數,socket()成功返回的整數範圍爲0~NUM_SOCKETS-1,NUM_SOCKETS爲最多能創建的個數,所以maxfdp1一般取值爲socket()返回的最大值+1

readset:(可選)指針,指向一組等待可讀性檢查的套接口。如果該套接口正處於監聽listen()狀態,則若有連接請求到達,該套接口便被標識爲可讀,這樣一個accept()調用保證可以無阻塞完成。對其他套接口而言,可讀性意味着有數據供讀取,於是recv()或recvfrom()操作均能無阻塞完成

writeset:(可選)指針,指向一組等待可寫性檢查的套接口。如果一個套接口正在connect()連接(非阻塞),可寫性意味着連接順利建立。如果套接口並未處於connect()調用中,可寫性意味着send()和sendto()調用將無阻塞完成

exceptset:(可選)指針,指向一組等待錯誤檢查的套接口。

timeout:select()最多等待時間,對阻塞操作則爲NULL

不需要查看的形參可以設爲NULL

返回值:負值:select錯誤,正值:可讀可寫套接口數目,0:等待超時,沒有可讀寫或錯誤的文件 

 

判讀:通過宏 FD_ISSET、&readset(宏參數) 和 具體某個描述符(宏參數) 判斷該描述符是否可讀;通過宏 FD_ISSET、&writeset(宏參數) 和 具體某個描述符(宏參數) 判斷該描述符是否可寫;

 

fcntl()

int fcntl(int s, int cmd, int val);

s 爲要設置的socket,cmd 是要進行什麼操作,val 是操作所需要的參數

返回值:成功取決於cmd,失敗返回-1

函數有下面5種功能:

  • 複製一個現有的描述符(cmd=F_DUPFD);
  • 獲得/設置文件描述符標記(cmd=F_GETFD或F_SETFD);
  • 獲得/設置文件狀態標記(cmd=F_GETFL或F_SETFL);
  • 獲得/設置異步I/O所有權(cmd=F_GETOWN或F_SETOWN);
  • 獲得/設置記錄鎖(cmd=F_GETLK , F_SETLK或F_SETLKW);

 

在socket編程中使用 fcntl() 設置 sockfd 爲非阻塞模式,則之後的connect、accept、recv、recvfrom等函數便失去了阻塞功能,變成了非阻塞函數。

用以下方法將socket設置爲非阻塞方式:

int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, flags | O_NONBLOCK); 

將非阻塞的設置回阻塞可以用以下方式:

int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, flags & ~O_NONBLOCK);

 

 ioctl()

int ioctl(int s, long request, void *argp);

ioctl 是 input output control 的簡寫,控制I/O設備, 提供了一種獲得設備信息和向設備發送控制參數的手段

返回值:成功返回0,出錯返回-1

第一個參數:指示某個文件描述符(當然也包括 套接口描述符)

第二個參數:request 指示要ioctl執行的操作

第三個參數:總是某種指針,具體的指向類型依賴於 request 參數

 

我們可以把和網絡相關的請求(request)劃分爲6 類:

      套接口操作

      文件操作

      接口操作

      ARP 高速緩存操作

      路由表操作

      流系統

下表列出了網絡相關ioctl 請求的request 參數以及arg 地址必須指向的數據類型:

類別

Request

說明

數據類型

 
 

SIOCATMARK 
SIOCSPGRP 
SIOCGPGRP

是否位於帶外標記 
設置套接口的進程ID 或進程組ID 
獲取套接口的進程ID 或進程組ID

int 
int 
int

 

FIONBIN 
FIOASYNC 
FIONREAD 
FIOSETOWN 
FIOGETOWN

設置/ 清除非阻塞I/O 標誌 
設置/ 清除信號驅動異步I/O 標誌 
獲取接收緩存區中的字節數 
設置文件的進程ID 或進程組ID 
獲取文件的進程ID 或進程組ID

int 
int 
int 
int 
int

 

SIOCGIFCONF 
SIOCSIFADDR 
SIOCGIFADDR 
SIOCSIFFLAGS 
SIOCGIFFLAGS 
SIOCSIFDSTADDR 
SIOCGIFDSTADDR 
SIOCGIFBRDADDR 
SIOCSIFBRDADDR 
SIOCGIFNETMASK 
SIOCSIFNETMASK 
SIOCGIFMETRIC 
SIOCSIFMETRIC 
SIOCGIFMTU 
SIOCxxx

獲取所有接口的清單 
設置接口地址 
獲取接口地址 
設置接口標誌 
獲取接口標誌 
設置點到點地址 
獲取點到點地址 
獲取廣播地址 
設置廣播地址 
獲取子網掩碼 
設置子網掩碼 
獲取接口的測度 
設置接口的測度 
獲取接口MTU 
(還有很多取決於系統的實現)

struct ifconf 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq

ARP

SIOCSARP 
SIOCGARP 
SIOCDARP

創建/ 修改ARP 表項 
獲取ARP 表項 
刪除ARP 表項

struct arpreq 
struct arpreq 
struct arpreq

 

SIOCADDRT 
SIOCDELRT

增加路徑 
刪除路徑

struct rtentry 
struct rtentry

I_xxx

 

 

inet_ntoa()、inet_addr()

inet_ntoa()將一個 32bits 無符號整數轉換爲點分十進制IP格式的字符串。inet_addr()正好相反,inet_addr可以判斷形參是否IP格式的字符串,不是返回0xFFFFFFFF

char* inet_ntoa (struct in_addr addr);

結構體in_addr唯一一個成員就是32bits 無符號整數

 inet_pton()

int inet_pton(int af, const char *src, void *dst);

af 是地址簇,比如 af=AF_INET,AF_INET(又稱 PF_INET)是 IPv4 網絡協議的套接字類型

指針 src 指向十進制IP格式的字符串

指針 dst 指向 32bits 無符號整數,即要得到的數據

 

 IP4_ADDR()

IP4_ADDR(ipaddr, a,b,c,d)

 

ipaddr是一個結構體(struct ip_addr),含有成員變量addr

 

宏定義

PF_INET(AF_INET):IPv4(網際層)

PF_INET6(AF_INET6):IPv6(網際層)

 

SOCK_STREAM:設置套接字類型爲流套接字,流套接字協議只有一個,即 IPPROTO_TCP(傳輸層)

SOCK_DGRAM:設置套接字類型爲數據報套接字,數據報套接字協議有兩個個,即 IPPROTO_UDP 和 IPPROTO_UDPLITE(傳輸層)

SOCK_RAW:設置套接字類型爲原始套接字

  原始套接字(SOCKET_RAW)允許對較低層次的協議直接訪問,比如IP、 ICMP協議,它常用於檢驗新的協議實現,或者訪問現有服務中配置的新設備,因爲RAW SOCKET能夠對網絡底層的傳輸機制進行控制,所以可以應用原始套接字來操縱網絡層和傳輸層應用。比如,我們可以通過RAW SOCKET來接收發向本機的ICMP、IGMP協議包,或者接收TCP/IP棧不能夠處理的IP包,也可以用來發送一些自定包頭或自定協議的IP包。網絡監聽技術很大程度上依賴於SOCKET_RAW

 

 

 

套接字API是Unix網絡的通用接口,允許使用各種網絡協議和地址。

下面列出了一些例子,在現在的 Linux 和BSD中一般都已經實現了。

PF_LOCAL, PF_UNIX, PF_FILE
                Local to host (pipes and file-domain)
PF_INET         IP protocol family
PF_AX25         Amateur Radio AX.25
PF_IPX          Novell Internet Protocol
PF_APPLETALK    Appletalk DDP
PF_NETROM       Amateur radio NetROM
PF_BRIDGE       Multiprotocol bridge
PF_ATMPVC       ATM PVCs
PF_X25          Reserved for X.25 project
PF_INET6        IP version 6
PF_ROSE         Amateur Radio X.25 PLP
PF_DECnet       Reserved for DECnet project
PF_NETBEUI      Reserved for 802.2LLC project
PF_SECURITY     Security callback pseudo AF
PF_KEY          PF_KEY key management API
PF_NETLINK, PF_ROUTE
                routing API
PF_PACKET       Packet family
PF_ASH          Ash
PF_ECONET       Acorn Econet
PF_ATMSVC       ATM SVCs
PF_SNA          Linux SNA Project
PF_IRDA         IRDA sockets
PF_PPPOX        PPPoX sockets
PF_WANPIPE      Wanpipe API sockets
PF_BLUETOOTH    Bluetooth sockets

標籤: 網絡通信知識

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章