Unix網絡API

索引:

1.字節序函數
2.字節操作函數
3.地址轉換函數
4.readn、writen和readline
5.測試描述符類型
6.socket函數
7.connect函數
8.bind函數
9.listen函數
10.accept函數
11.close函數
12.getsockname和getpeername
13.select函數
14.shutdown函數
15.pselect函數
16.poll函數
17.getsockopt和setsockopt
18.套接口選項列表
19.處理套接口的fcntl函數
20.gethostbyname函數
21.gethostbyname2函數
22.ethostbyaddr函數
23.uname函數
24.gethostname函數
25.getservbyname函數
26.getservbyport函數
27.recv和send
28.readv和writev
29.readmsg和writemsg
30.socketpair函數
31.套接口ioctl函數

 


1.字節序函數

#include <netinet.h>
uint16_t htons(uint16_t host16bitvalue);
uint32_t htonl(uint32_t host32bitvalue);
返回:網絡字節序值

uint16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);
返回:主機字節序值

一個測試本機字節序的程序,可參見見unpv12e:intro/byteorder.c。


2.字節操作函數

#include <strings.h>
void bzero(void *dest, size_t nbytes);
void bcopy(const void *src, void *dest, size_t nbytes);
int bcmp(const void *ptr1, const void *ptr2, size_t nbytes);
返回:0—相等,非0—不相等

#include <string.h>
void *memset(void *dest, int c, size_t len);
void *memcpy(void *dest, void *src, size_t nbytes);
int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);
返回:0—相同,>0或<0—不相同;進行比較操作時,假定兩個不相等的字節均爲無符號字符(unsigned char)。


3.地址轉換函數

#include <arpa/inet.h>
int inet_aton(const char *strptr, struct in_addr *addrptr);
返回:1—串有效,0—串有錯。

in_addr_t inet_addr(const char *strptr);
返回:若成功,返回32爲二進制的網絡字節序地址;若有錯,則返回INADDR_NONE。

char *inet_ntoa(struct in_addr inaddr);
返回:指向點分十進制數串的指針。

int inet_pton(int family, const char *strptr, void *addrptr);
返回:1—成功;0—輸入不是有效的表達格式,-1—出錯。

const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
返回:指向結果的指針—成功,NULL—失敗。

說明:

  • inet_aton函數的指針若爲空,則函數仍然執行輸入串的有效性檢查,但不存儲任何結果。
  • inet_addr的缺陷:出錯返回值INADDR_NONE等於255.255.255.255(IPv4的有限廣播地址),所以該函數不能處理此地址。
    儘量使用inet_aton,不使用inet_addr。
  • inet_ntoa函數的執行結果放在靜態內存中,是不可重入的。
  • 參數family可以是AF_INET,也可以是AF_INET6,若參數family不被支持,則出錯,errno置爲EAFNOSUPPORT。
  • 指針addrptr是結構指針。
  • len指定目標的大小,避免緩衝區溢出。如果len太小,則返回一個空指針,errno置爲ENOSPC。爲有助於規定該大小,有如下定義:
    #include <netinet.h>
    #define INET_ADDRSTRLEN 16 /*fro IPv4 dotted-decimal */
    #define INET6_ADDRSTRLEN 46 /*for IPv6 hex string */
  • inet_ntop函數的參數strptr不能爲空指針,成功時,此指針即是函數的返回值。


實現IPv4版本的inet_pton和inet_ntop的程序,參見:unpv12e:libfree/inet_pton_ipv4.c和libfree/inet_ntop_ipv4.c。


4.readn、writen和readline

函數原型如下:
ssize_t readn(int filedes, void *buff, size_t nbytes);
ssize-t writen(int filedes, void *buff, size_t nbytes);
ssize_t readline(int filedes, void *buff, size_t maxlen);
返回:讀寫字節數,-1—出錯。

實現程序見:unpv12e:lib/readn.c、lib/writen.c、lib/readline1.c和lib/readline.c。


5.測試描述符類型

#include <sys/stat.h>
int isfdtype( int fd, int fdtype);
返回:1—是指定類型,0—不是指定類型,-1—出錯。

要測試是否爲套接口描述子,fdtype應設爲S_IFSOCK。

該函數的一個實現程序,參見unpv12e:lib/isfdtype.c


6.socket函數

#include <sys/socket.h>
int socket(int family, int type, int protocol);
返回:非負描述字—成功,-1—出錯。

family指定協議族,有如下取值:

  • AF_INET     IPv4協議
  • AF_INET6    IPv6協議
  • AF_LOCAL    Unix域協議
  • AF_ROUTE    路由套接口
  • AF_KEY      密鑰套接口

type指定套接口類型:

  • SOCK_STREAM    字節流套接口
  • SOCK_DGRAM     數據報套接口
  • SOCK_RAW       原始套接口

protocol一般設爲0,除非用在原始套接口上。

並非所有family和type的組合都是有效的。

AF_LOCAL等於早期的AF_UNIX。


7.connect函數

#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
返回:0—成功,-1—出錯。

sockfd是socket函數返回的套接口描述字,servaddr和addrlen是指向服務器的套接口地址結構指針和結構大小。

在調用connect之前不必非得調用bind函數。

如果是TCP,則connect激發TCP的三路握手過程,在阻塞情況下,只有在連接建立成功或出錯時該函數才返回,
出錯情況:

  • 沒有收到SYN分節的響應,在規定時間內經過重發仍無效,則返回ETIMEDOUT;
  • 如果對SYN分節的響應是RST,表示服務器在指定端口上沒有相應的服務,返回ECONNREFUSED;
  • 如果發出 SYN在中間路由器上引發一個目的地不可達ICMP錯誤,在規定時間內經過重發仍無效,則返回EHOSTUNREACH或ENETUNREACH錯誤。

注意:如果connect失敗,則套接口將不能再使用,必須關閉,不能對此套接口再調用函數connect。


8.bind函數

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *maddr, socklen_t addrlen);
返回:0—成功,-1—出錯。

進程可以把一個特定的IP地址捆綁到他的套接口上,但此IP地址必須是主機的一個接口。

對於IPv4,通配地址是INADDR_ANY,其值一般爲0;使用方法如下:
struct sockaddr_in servaddr;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

對於IPv6,方法如下:
struct sockaddr_in6 serv;
serv.sin6_addr = in6addr_any; (系統分配變量in6addr_any並將其初始化爲常值IN6ADDR_ANY_INIT。)

如果讓內核選擇臨時端口,注意的是bind並不返回所選的斷口值,要得到一個端口,必須使用getsockname函數。

bind失敗的常見錯誤是EADDRINUSE(地址已使用)。


9.listen函數

#include <sys/socket.h>
int listen(int sockfd, int backlog);
返回:0—成功,-1—出錯。

listen把未連接的套接口轉化爲被動套接口,指示內核應接受指向此套接口的連接請求。第二個參數規定了內核爲此套接口排隊的最大連接數。

參數backlog曾經規定爲監聽套接口上的未完成連接隊列和已完成連接隊列總和的最大值,但各個系統的定義方法都不盡相同;歷史上常把backlog置爲5,但對於繁忙的服務器是不夠的;backlog的設置沒有一個通用的方法,依情況而定,但不要設爲0。


10.accept函數

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
返回:非負描述字—OK,-1—出錯。

accept從已完成連接隊列頭返回下一個連接,若已完成連接隊列爲空,則進程睡眠(套接口爲阻塞方式時)。

參數cliaddr和addrlen返回連接對方的協議地址,其中addrlen是值-結果參數,調用前addrlen所指的整數值要置爲cliaddr所指的套接口結構的長度,返回時由內核修改。

accept成功執行後,返回一個連接套接口描述字。

如果對客戶的協議地址沒有興趣,可以把cliaddr和addrlen置爲空指針。


11.close函數

#include <unistd.h>
int close(int sockfd);
返回:0—OK,-1—出錯。

TCP套接口的close缺省功能是將套接口做上“已關閉”標記,並立即返回到進程。這個套接口描述字不能再爲進程使用,但TCP將試着發送已排隊待發的任何數據,然後按正常的TCP連接終止序列進行操作。

close把描述字的訪問計數減1,當訪問計數仍大於0時,close並不會引發TCP的四分組連接終止序列。若確實要發一個FIN,可以用函數shutdown。


12.getsockname和getpeername

#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
返回:0—OK,-1—出錯。

getsockname函數返回與套接口關聯的本地協議地址。

getpeername函數返回與套接口關聯的遠程協議地址。

addrlen是值-結果參數。

使用場合:

  • 在不調用bind的TCP客戶,當connect成功返回後,getsockname返回分配給此連接的本地IP地址和本地端口號;
  • 在以端口號爲0調用bind後,使用getsockname返回內核分配的本地端口號;
  • getsockname可用來獲取某套接口的地址族;
  • 在捆綁了通配IP地址的TCP服務器上,當連接建立後,可以使用getsockname獲得分配給此連接的本地IP地址;
  • 當一個服務器調用exec啓動後,他獲得客戶身份的唯一途徑是調用getpeername函數。

13.select函數

#include <sys/select.h>
#include <sys/time.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);
返回:準備好描述字的正數目,0—超時,-1—出錯。

結構timeval的定義:
struct timeval {
    long tv_sec; /* seconds */
    long tv_usec; /* microseconds */
};

timeout取值的三種情況:

  • 永遠等下去:僅在有一個描述字準備好I/O時才返回,設置timeout爲空指針;
  • 等待固定時間:在有一個描述字準備好I/O時返回,但不超過由timeout參數所指定的秒數和微秒數;
  • 根本不等待:檢查描述字後立即返回,將timeout中的秒數和微秒數都設置爲0。

在等待過程中,若進程捕獲了信號並從信號處理程序返回,等待一般被中斷,爲了可移植性,必須準備好select返回EINTR錯誤。

timeout的值在返回時並不會被select修改(const標誌)。

readset、writeset、exceptset指定我們要讓內核測試讀、寫和異常條件所需的描述字。

當前支持的異常條件有兩個:

  1. 套接口帶外數據的到達;
  2. 控制狀態信息的存在,可從一個已置爲分組方式的僞終端主端讀到。

描述字集的使用:
數據類型:fd_set;
void FD_ZERO(fd_set *fdset);
void FD_SET(int fd, fd_set *fdset);
void FD_CLR(int fd, fd_set *fdset);
void FD_ISSET(int fd, fd_set *fdset);

參數maxfdp1指定被測試的描述字個數,它的值是要被測試的最大描述字加1。描述字0,1,2,…,maxfdp1-1都被測試。

readset、writeset、exceptset是值-結果參數,select修改三者所指的描述字集。所以,每次調用select時,我們都要將所有描述字集中關心的位置爲1。

套接口準備好讀的條件:

  • 套接口接收緩衝區中的數據字節數大於等於套接口接收緩衝區低潮限度的當前值。對這樣的套接口的讀操作將不阻塞並返回一個大於0的值(即準備好讀入的數據量)。可以用套接口選項SO_RCVLOWAT來設置低潮限度,對於TCP和UDP,缺省值爲1;
  • 連接的讀這一半關閉(接收了FIN的TCP連接)。對這樣的套接口讀操作將不阻塞並且返回0(即文件結束符);
  • 套接口是一個監聽套接口且已完成的連接數爲非0;
  • 有一個套接口錯誤待處理。對這樣的套接口讀操作將不阻塞且返回一個錯誤,errno設置成明確的錯誤條件。這些待處理錯誤也可以通過指定套接口選項SO_ERROR調用getsockopt來取得並清除。

套接口準備好寫的條件:

  • 套接口發送緩衝區中的可用字節數大於等於套接口發送緩衝區低潮限度的當前值,且或者(1)套接口已連接,或者(2)套接口不要求連接(如UDP套接口)。可以用套接口選項SO_SNDLOWAT來設置此低潮限度,對於TCP和UDP,缺省值爲2048;
  • 連接的寫這一半關閉。對這樣的套接口寫將產生信號SIGPIPE;
  • 有一個套接口錯誤待處理。對這樣的套接口寫操作將不阻塞且返回一個錯誤,errno設置成明確的錯誤條件。這些待處理錯誤也可以通過指定套接口選項SO_ERROR調用getsockopt來取得並清除。

如果一個套接口存在帶外數據或者仍處於帶外標記,那它有異常條件待處理。

一個套接口出錯時,它被select標記爲既可讀又可寫。


14.shutdown函數

#include <sys/socket.h>
int shutdown(int sockfd, int howto);
返回:0—成功,-1—失敗。

函數的行爲依賴於參數howto的值:

  • SHUT_RD:關閉連接的讀這一半,不再接收套接口中的數據且留在套接口緩衝區中的數據都作廢。進程不能再對套接口任何讀函數。調用此函數後,由TCP套接口接收的任何數據都被確認,但數據本身被扔掉。
  • SHUT_WR:關閉連接的寫這一半,在TCP場合下,這稱爲半關閉。當前留在套接口發送緩衝區中的數據都被髮送,後跟正常的TCP連接終止序列。此半關閉不管套接口描述字的訪問計數是否大於0。進程不能再執行對套接口的任何寫函數。

SHUT_RDWR:連接的讀這一半和寫這一半都關閉。這等效於調用shutdown兩次:第一次調用時用SHUT_RD,第二次調用時用SHUT_WR。


15.pselect函數

#include <sys/select.h>
#include <signal.h>
#include <time.h>
int pselect(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timespec *timeout, const sigset_t *sigmask);
返回:準備好描述字的個數,0—超時,-1—出錯。

pselect是Posix.1g發明的。相對select的變化:

  1. pselect使用結構timespec:
    struct timespec {
        time_t tv_sec; /* seconds */
        long tv_nsec; /* nanoseconds */
    };
    新結構中的tv_nsec規定納秒數。
  2. pselect增加了第六個參數:指向信號掩碼的指針。允許程序禁止遞交某些信號。

16.poll函數

#include <poll.h>
int poll(struct pollfd *fdarray, unsigned long nfds, int timeout);
返回:準備好描述字的個數,0—超時,-1—出錯。

第一個參數是指向一個結構數組的第一個元素的指針,每個數組元素都是一個pollfd結構:
struct pollfd {
    int fd; /* descriptor to check */
    short events; /* events of interest on fd */
    short revents; /* events that occurred on fd */
};

要測試的條件由成員events規定,函數在相應的revents成員中返回描述字的狀態(一個描述字有兩個變量:一個爲調用值,一個爲結果)。

第二個參數指定數組中元素的個數。

第三個參數timeout指定函數返回前等待多長時間,單位是毫秒。可能值如下:

  • INFTIM,永遠等待;
  • 0,立即返回,不阻塞;
  • >0,等待指定數目的毫秒數。

標誌的範圍:

常量 能作爲events的輸入嗎? 能作爲revents的結果嗎? 解釋
POLLIN yes yes 普通或優先級帶數據可讀
POLLRDNORM yes yes 普通數據可讀
POLLRDBAND yes yes 優先級帶數據可讀
POLLPRI yes yes 高優先級數據可讀
POLLOUT yes yes 普通或優先級帶數據可寫
POLLWRNORM yes yes 普通數據可寫
POLLWRBAND yes yes 優先級帶數據可寫
POLLERR
yes 發生錯誤
POLLHUP
yes 發生掛起
POLLNVAL
yes 描述字不是一個打開的文件

圖可分爲三部分:處理輸入的四個常值;處理輸出的三個常值;處理錯誤的三個常值。

poll識別三個類別的數據:普通(normal)、優先級帶(priority band)、高優先級(high priority)。術語來自流的概念。

返回條件:

  • 所有正規TCP數據和UDP數據都被認爲是普通數據;
  • TCP的帶外數據被認爲是優先級帶數據;
  • 當TCP連接的讀這一半關閉時(如接收了一個FIN),這也認爲是普通數據,且後續的讀操作將返回0;
  • TCP連接存在錯誤既可以認爲是普通數據,也可以認爲是錯誤(POLLERR)。無論哪種情況,後續的讀操作將返回-1,並將errno置爲適當的值,這就處理了諸如接收到RST或超時等條件;
  • 在監聽套接口上新連接的可用性既可認爲是普通數據,也可以認爲是優先級帶數據,大多數實現都將其作爲普通數據考慮。
  • 如果不關心某個特定的描述字,可將其pollfd結構的fd成員置爲一個負值,這樣就可以忽略成員events,且返回時將成員revents的值置爲0。

poll沒有select存在的最大描述字數目問題。但可移植性select要好於poll。


17.getsockopt和setsockopt

#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
返回:0—OK,-1—出錯。

sockfd必須是一個打開的套接口描述字;level(級別)指定系統中解釋選項的代碼:普通套接口代碼或特定於協議的代碼);optval是一個指向變量的指針;此變量的大小由最後一個參數決定。

對於某些套接口選項,什麼時候進行設置或獲取是有差別的。下面的套接口選項是由TCP已連接套接口從監聽套接口繼承來的:

  • SO_DEBUG;
  • SO_DONTROUTE;
  • SO_KEEPALIVE;
  • SO_LINGER;
  • SO_OOBINLINE;
  • SO_RCVBUF;
  • SO_SNDBUF。

如果想在三路握手完成時確保這些套接口選項中的某一個是給已連接套接口設置的,我們必須先給監聽套接口設置此選項。


18.套接口選項列表

level Optname get set 說明 標誌 數據類型







SOL_SOCKET SO_BROADCAST y y 允許發送廣播數據報 y int

SO_DEBUG y y 使能調試跟蹤 y int

SO_DONTROUTE y y 旁路路由表查詢 y int

SO_ERROR y
獲取待處理錯誤並消除
int

SO_KEEPALIVE y y 週期性測試連接是否存活 y int

SO_LINGER y y 若有數據待發送則延遲關閉
linger{}

SO_OOBINLINE y y 讓接收到的帶外數據繼續在線存放 y int

SO_RCVBUF y y 接收緩衝區大小
int

SO_SNDBUF y y 發送緩衝區大小
int

SO_RCVLOWAT y y 接收緩衝區低潮限度
int

SO_SNDLOWAT y y 發送緩衝區低潮限度
int

SO_RCVTIMEO y y 接收超時
timeval{}

SO_SNDTIMEO y y 發送超時
timeval{}

SO_REUSEADDR y y 允許重用本地地址 y int

SO_REUSEPORT y y 允許重用本地地址 y int

SO_TYPE y
取得套接口類型
int

SO_USELOOPBACK y y 路由套接口取得所發送數據的拷貝 y int







IPPROTO_IP IP_HDRINCL y y IP頭部包括數據 y int

IP_OPTIONS y y IP頭部選項
見後面說明

IP_RECVDSTADDR y y 返回目的IP地址 y int

IP_RECVIF y y 返回接收到的接口索引 y int

IP_TOS y y 服務類型和優先權
int

IP_TTL y y 存活時間
int

IP_MULTICAST_IF y y 指定外出接口
in_addr{}

IP_MULTICAST_TTL y y 指定外出TTL
u_char

IP_MULTICAST_LOOP y y 指定是否回饋
u_char

IP_ADD_MEMBERSHIP
y 加入多播組
ip_mreq{}

IP_DROP_MEMBERSHIP
y 離開多播組
ip_mreq{}







IPPROTO_ICMPV6 ICMP6_FILTER y y 指定傳遞的ICMPv6消息類型
icmp6_filter{}







IPPROTO_IPV6 IPV6_ADDRFORM y y 改變套接口的地址結構
int

IPV6_CHECKSUM y y 原始套接口的校驗和字段偏移
int

IPV6_DSTOPTS y y 接收目標選項 y int

IPV6_HOPLIMIT y y 接收單播跳限 y int

IPV6_HOPOPTS y y 接收步跳選項 y int

IPV6_NEXTHOP y y 指定下一跳地址 y sockaddr{}

IPV6_PKTINFO y y 接收分組信息 y int

IPV6_PKTOPTIONS y y 指定分組選項
見後面說明

IPV6_RTHDR y y 接收原路徑 y int

IPV6_UNICAST_HOPS y y 缺省單播跳限
int

IPV6_MULTICAST_IF y y 指定外出接口
in6_addr{}

IPV6_MULTICAST_HOPS y y 指定外出跳限
u_int

IPV6_MULTICAST_LOOP y y 指定是否回饋 y u_int

IPV6_ADD_MEMBERSHIP
y 加入多播組
ipv6_mreq{}

IPV6_DROP_MEMBERSHIP
y 離開多播組
ipv6_mreq{}







IPPROTO_TCP TCP_KEEPALIVE y y 控測對方是否存活前連接閒置秒數
int

TCP_MAXRT y y TCP最大重傳時間
int

TCP_MAXSEG y y TCP最大分節大小
int

TCP_NODELAY y y 禁止Nagle算法 y int

TCP_STDURG y y 緊急指針的解釋 y int

詳細說明:

 

SO_BROADCAST

使能或禁止進程發送廣播消息的能力。只有數據報套接口支持廣播,並且還必須在支持廣播消息的網絡上(如以太網、令牌環網等)。

如果目的地址是廣播地址但此選項未設,則返回EACCES錯誤。

 

 

SO_DEBUG

僅僅TCP支持。當打開此選項時,內核對TCP在此套接口所發送和接收的所有分組跟蹤詳細信息。這些信息保存在內核的環形緩衝區內,可由程序trpt進行檢查。

 

 

SO_DONTROUTE

此選項規定發出的分組將旁路底層協議的正常路由機制。

該選項經常由路由守護進程(routed和gated)用來旁路路由表(路由表不正確的情況下),強制一個分組從某個特定接口發出。

 

 

SO_ERROR

當套接口上發生錯誤時,源自Berkeley的內核中的協議模塊將此套接口的名爲so_error的變量設爲標準的UNIX Exxx值中的一個,它稱爲此套接口的待處理錯誤(pending error)。內核可立即以以下兩種方式通知進程:

  1. 如果進程阻塞於次套接口的select調用,則無論是檢查可讀條件還是可寫條件,select都返回並設置其中一個或所有兩個條件。
  2. 如果進程使用信號驅動I/O模型,則給進程或進程組生成信號SIGIO。

進程然後可以通過獲取SO_ERROR套接口選項來得到so_error的值。由getsockopt返回的整數值就是此套接口的待處理錯誤。so_error隨後由內核復位爲0。

當進程調用read且沒有數據返回時,如果so_error爲非0值,則read返回-1且errno設爲so_error的值,接着so_error的值被複位爲0。如果此套接口上有數據在排隊,則read返回那些數據而不是返回錯誤條件。

如果進程調用write時so_error爲非0值,則write返回-1且errno設爲so_error的值,隨後so_error也被複位。

 

 

SO_KEEPALIVE

打開此選項後,如果2小時內在此套接口上沒有任何數據交換,TCP就會自動給對方發一個保持存活探測分節,結果如下:

  1. 對方以期望的ACK響應,則一切正常,應用程序得不到通知;
  2. 對方以RST響應,套接口的待處理錯誤被置爲ECONNRESET,套接口本身則被關閉;
  3. 對方對探測分節無任何響應,經過重試都沒有任何響應,套接口的待處理錯誤被置爲ETIMEOUT,套接口本身被關閉;若接收到一個ICMP錯誤作爲某個探測分節的響應,則返回相應錯誤。

此選項一般由服務器使用。服務器使用它是爲了檢測出半開連接並終止他們。

 

 

SO_LINGER

此選項指定函數close對面向連接的協議如何操作(如TCP)。缺省close操作是立即返回,如果有數據殘留在套接口緩衝區中則系統將試着將這些數據發送給對方。

SO_LINGER選項用來改變此缺省設置。使用如下結構:
struct linger {
    int l_onoff; /* 0 = off, nozero = on */
    int l_linger; /* linger time */
};

有下列三種情況:

  1. l_onoff爲0,則該選項關閉,l_linger的值被忽略,等於缺省情況,close立即返回;
  2. l_onoff爲非0,l_linger爲0,則套接口關閉時TCP夭折連接,TCP將丟棄保留在套接口發送緩衝區中的任何數據併發送一個RST給對方,而不是通常的四分組終止序列,這避免了TIME_WAIT狀態;
  3. l_onoff 爲非0,l_linger爲非0,當套接口關閉時內核將拖延一段時間(由l_linger決定)。如果套接口緩衝區中仍殘留數據,進程將處於睡眠狀態,直到(a)所有數據發送完且被對方確認,之後進行正常的終止序列(描述字訪問計數爲0)或(b)延遲時間到。此種情況下,應用程序檢查close的返回值是非常重要的,如果在數據發送完並被確認前時間到,close將返回EWOULDBLOCK錯誤且套接口發送緩衝區中的任何數據都丟失。close的成功返回僅告訴我們發送的數據(和FIN)已由對方TCP確認,它並不能告訴我們對方應用進程是否已讀了數據。如果套接口設爲非阻塞的,它將不等待close完成。

l_linger的單位依賴於實現,4.4BSD假設其單位是時鐘滴答(百分之一秒),但Posix.1g規定單位爲秒。

讓客戶知道服務器已經讀其數據的一個方法時:調用shutdown(SHUT_WR)而不是調用close,並等待對方close連接的本地(服務器)端。

 

 

SO_OOBINLINE

此選項打開時,帶外數據將被保留在正常的輸入隊列中(即在線存放)。當發生這種情況時,接收函數的MSG_OOB標誌不能用來讀帶外數據。

 

 

SO_RCVBUF和SO_SNDBUF

每個套接口都有一個發送緩衝區和一個接收緩衝區,使用這兩個套接口選項可以改變缺省緩衝區大小。

當設置TCP套接口接收緩衝區的大小時,函數調用順序是很重要的,因爲TCP的窗口規模選項是在建立連接時用SYN與對方互換得到的。對於客戶,SO_RCVBUF選項必須在connect之前設置;對於服務器,SO_RCVBUF選項必須在listen前設置。

TCP套接口緩衝區的大小至少是連接的MSS的三倍,而必須是連接的MSS的偶數倍。

 

 

SO_RCVLOWAT和SO_SNDLOWAT

每個套接口有一個接收低潮限度和一個發送低潮限度,他們由函數select使用。這兩個選項可以修改他們。

接收低潮限度是讓select返回“可讀”而在套接口接收緩衝區中必須有的數據量,對於一個TCP或UDP套接口,此值缺省爲1。發送低潮限度是讓select返回“可寫”而在套接口發送緩衝區中必須有的可用空間,對於TCP套接口,此值常爲2048。

 

 

SO_RCVTIMEO和SO_SNDTIMEO

使用這兩個選項可以給套接口設置一個接收和發送超時。通過設置參數的值爲0秒和0微秒來禁止超時。缺省時兩個超時都是禁止的。

接收超時影響5個輸入函數:read、readv、recv、recvfrom和recvmsg;發送超時影響5個輸出函數:write、writev、send、sendto和sendmsg。

 

 

SO_REUSEADDR和SO_REUSEPORT

SO_REUSEADDR提供如下四個功能:

  1. SO_REUSEADDR允許啓動一個監聽服務器並捆綁其衆所周知端口,即使以前建立的將此端口用做他們的本地端口的連接仍存在。這通常是重啓監聽服務器時出現,若不設置此選項,則bind時將出錯。
  2. SO_REUSEADDR允許在同一端口上啓動同一服務器的多個實例,只要每個實例捆綁一個不同的本地IP地址即可。對於TCP,我們根本不可能啓動捆綁相同IP地址和相同端口號的多個服務器。
  3. SO_REUSEADDR允許單個進程捆綁同一端口到多個套接口上,只要每個捆綁指定不同的本地IP地址即可。這一般不用於TCP服務器。
  4. SO_REUSEADDR允許完全重複的捆綁:當一個IP地址和端口綁定到某個套接口上時,還允許此IP地址和端口捆綁到另一個套接口上。一般來說,這個特性僅在支持多播的系統上纔有,而且只對UDP套接口而言(TCP不支持多播)。

SO_REUSEPORT選項有如下語義:

  1. 此選項允許完全重複捆綁,但僅在想捆綁相同IP地址和端口的套接口都指定了此套接口選項才性。
  2. 如果被捆綁的IP地址是一個多播地址,則SO_REUSEADDR和SO_REUSEPORT等效。

使用這兩個套接口選項的建議:

  1. 在所有TCP服務器中,在調用bind之前設置SO_REUSEADDR套接口選項;
  2. 當編寫一個同一時刻在同一主機上可運行多次的多播應用程序時,設置SO_REUSEADDR選項,並將本組的多播地址作爲本地IP地址捆綁。

 

 

SO_TYPE

該選項返回套接口的類型,返回的整數值是一個諸如SOCK_STREAM或SOCK_DGRAM這樣的值。

 

 

SO_USELOOPBACK

該選項僅用於路由域(AF_ROUTE)的套接口,它對這些套接口的缺省設置爲打開(這是唯一一個缺省爲打開而不是關閉的SO_xxx套接口選項)。當此套接口打開時,套接口接收在其上發送的任何數據的一個拷貝。

禁止這些回饋拷貝的另一個方法是shutdown,第二個參數應設爲SHUT_RD。

 

 

IP_HDRINCL

如果一個原始套接口設置該選項,則我們必須爲所有發送到此原始套接口上的數據報構造自己的IP頭部。

 

 

IP_OPTIONS

設置此選項允許我們在IPv4頭部中設置IP選項。這要求掌握IP頭部中IP選項的格式信息。

 

 

IP_RECVDSTADDR

該選項導致所接收到的UDP數據報的目的IP地址由函數recvmsg作爲輔助數據返回。

 

 

IP_RECVIF

該選項導致所接收到的UDP數據報的接口索引由函數recvmsg作爲輔助數據返回。

 

 

IP_TOS

該選項使我們可以給TCP或UDP套接口在IP頭部中設置服務類型字段。如果我們給此選項調用getsockopt,則放到外出IP數據報頭部的TOS字段中的當前值將返回(缺省爲0)。還沒有辦法從接收到的IP數據報中取此值。

可以將TOS設置爲如下的值:

  • IPTOS_LOWDELAY:最小化延遲
  • IPTOS_THROUGHPUT:最大化吞吐量
  • IPTOS_RELIABILITY:最大化可靠性
  • IPTOS_LOWCOST:最小化成本

 

 

IP_TTL

用次選項,可以設置和獲取系統用於某個給定套接口的缺省TTL值(存活時間字段)。與TOS一樣,沒有辦法從接收到的數據報中得到此值。

 

 

ICMP6_FILTER

可獲取和設置一個icmp6_filter結構,他指明256個可能的ICMPv6消息類型中哪一個傳遞給在原始套接口上的進程。

 

 

IPV6_ADDRFORM

允許套接口從IPv4轉換到IPv6,反之亦可。

 

 

IPV6_CHECKSUM

指定用戶數據中校驗和所處位置的字節偏移。如果此值爲非負,則內核將(1)給所有外出分組計算並存儲校驗和;(2)輸入時檢查所收到的分組的校驗和,丟棄帶有無效校驗和的分組。此選項影響出ICMPv6原始套接口外的所有IPv6套接口。如果指定的值爲-1(缺省值),內核在此原始套接口上將不給外出的分組計算並存儲校驗和,也不檢查所收到的分組的校驗和。

 

 

IPV6_DSTOPTS

設置此選項指明:任何接收到的IPv6目標選項都將由recvmsg作爲輔助數據返回。此選項缺省爲關閉。

 

 

IPV6_HOPLIMIT

設置此選項指明:接收到的跳限字段將由recvmsg作爲輔助數據返回。

 

 

IPV6_HOPOPTS

設置此選項指明:任何接收到的步跳選項都將由recvmsg作爲輔助數據返回。

 

 

IPV6_NEXTHOP

這不是一個套接口選項,而是一個可指定個sendmsg的輔助數據對象的類型。此對象以一個套接口地址結構指定某個數據報的下一跳地址。

 

 

IPV6_PKTINFO

設置此選項指明:下面關於接收到的IPv6數據報的兩條信息將由recvmsg作爲輔助數據返回:目的IPv6地址和到達接口索引。

 

 

IPV6_PKTOPTIONS

大多數IPv6套接口選項假設UDP套接口使用recvmsg和sendmsg所用的輔助數據在內核與應用進程間傳遞信息。TCP套接口使用IPV6_PKTOPTIONS來獲取和存儲這些值。

 

 

IPV6_RTHDR

設置此選項指明:接收到的IPv6路由頭部將由recvmsg作爲輔助數據返回。

 

 

IPV6_UNICAST_HOPS

類似於IPv4的IP_TTL,它的設置指定發送到套接口上的外出數據報的缺省跳限,而它的獲取則返回內核將用於套接口的跳限值。爲了從接收到的IPv6數據報中得到真實的跳限字段,要求使用IPV6_HOPLIMIT套接口選項。

 

 

TCP_KEEPALIVE

它指定TCP開始發送保持存活探測分節前以秒爲單位的連接空閒時間。缺省值至少爲7200秒,即2小時。該選項僅在SO_KEEPALIVE套接口選項打開時纔有效。

 

 

TCP_MAXRT

它指定一旦TCP開始重傳數據,在連接斷開之前需經歷的以秒爲單位的時間總量。值0意味着使用系統缺省值,值-1意味着永遠重傳數據。

 

 

TCP_MAXSEG

允許獲取或設置TCP連接的最大分節大小(MSS)。返回值是我們的TCP發送給另一端的最大數據量,他常常就是由另一端用SYN分節通告的MSS,除非我們的TCP選擇使用一個比對方通告的MSS小的值。如果此選項在套接口連接之前取得,則返回值爲未從另一端收到的MSS選項的情況下所用的缺省值。

 

 

TCP_NODELAY

如果設置,此選項禁止TCP的Nagle算法。缺省時,該算法是使能的。

Nagle算法的目的是減少WAN上小分組的數目。

Nagle算法常常與另一個TCP算法聯合使用:延遲ACK(delayed ACK)算法。

解決多次寫導致Nagle算法和延遲ACK算法負面影響的方法:

  1. 使用writev而不是多次write;
  2. 合併緩衝區,對此緩衝區使用一次write;
  3. 設置TCP_NODELAY選項,繼續調用write多次,這是最不可取的解決方法。

 

 

TCP_STDURG

它影響對TCP緊急指針的解釋。


19.處理套接口的fcntl函數

#include <fcntl.h>
int fcntl(int fd, int cmd, … /* arg */);
返回:依賴於參數cmd—成功,-1—失敗。

函數fcntl提供瞭如下關於網絡編程的特性:

  1. 非阻塞I/O:通過用F_SETFL命令設置O_NONBLOCK文件狀態標誌來設置套接口爲非阻塞型。
  2. 信號驅動I/O:用F_SETFL命令來設置O_ASYNC文件狀態標誌,這導致在套接口狀態發生變化時內核生成信號SIGIO。
  3. F_SETOWN命令設置套接口屬主(進程ID或進程組ID),由它來接收信號SIGIO和SIGURG。SIGIO在設置套接口爲信號驅動I/O型時生成,SIGURG在新的帶外數據到達套接口時生成。
  4. F_GETOWN命令返回套接口的當前屬主。

注意事項:

  • 設置某個文件狀態標誌時,先取得當前標誌,與新標誌路邏輯或後再設置標誌。
  • 信號SIGIO和SIGURG與其他信號不同之處在於,這兩個信號只有在已使用命令F_SETOWN給套接口指派了屬主後纔會生成。F_SETOWN命令的整參數arg既可以是一個正整數,指明接收信號的進程ID,也可以是一個負整數,它的絕對值是接收信號的進程組ID。
  • 當一個新的套接口由函數socket創建時,他沒有屬主,但是當一個新的套接口從一個監聽套接口創建時,套接口屬主便由已連接套接口從監聽套接口繼承而來。

20.gethostbyname函數

#include <netdb.h>
struct hostent *gethostbyname(const char *hostname);
返回:非空指針—成功,空指針—出錯,同時設置h_errno。

函數返回的非空指針指向的結構如下:
struct hostent {
    char *h_name; /*規範主機名 */
    char **h_aliases; /* 別名列表 */
    int h_addrtype; /* AF_INET or AF_INET6 */
    int h_length; /* 地址長度 */
    char **h_addr_list; /* IPv4或IPv6地址結構列表 */
};
#define h_addr h_addr_list[0];

按照DNS的說法,gethostbyname執行一個對A記錄的查詢或對AAAA記錄的查詢,返回IPv4或IPv6地址。

h_addr的定義是爲了兼容,在新代碼中不應使用。

返回的h_name稱爲主機的規範(canonical)名字。當返回IPv6地址時,h_addrtype被設置爲AF_INET6,成員h_length被設置爲16。

gethostbyname的特殊之處在於:當發生錯誤時,他不設置errno,而是將全局整數h_errno設置爲定義在頭文件<netdb.h>中的下列常值中的一個:

  • HOST_NOT_FOUND;
  • TRY_AGAIN;
  • NO_RECOVERY;
  • NO_DATA(等同於NO_ADDRESS)。

有函數hstrerror(),它將h_errno的值作爲唯一的參數,返回一個指向相應錯誤說明的const char *型指針。

 

DNS小常識:

DNS中的條目稱爲資源記錄RR(resource record),僅有少數幾類RR會影響我們的名字與地址轉換:

  • A:A記錄將主機名映射爲32位的IPv4地址;
  • AAAA:“四A”記錄將主機名映射爲128位的IPv6地址;
  • PTR:PTR記錄(稱爲“指針記錄”)將IP地址映射爲主機名;
  • MX:MX記錄指定一主機作爲某主機的“郵件交換器”。
  • CNAME:CNAME代表“canonical name(規範名字)”,其常見的用法是爲常用服務如ftp和www指派一個CNAME記錄。

21.gethostbyname2函數

#include <netdb.h>
struct hostent *gethostbyname2(const char *hostname, int family);
返回:非空指針—成功,空指針—出錯,同時設置h_errno。

該函數允許指定地址族,其他與gethostbyname相似。


22.gethostbyaddr函數

#include <netdb.h>
struct hostent *gethostbyaddr(const char *addr, size_t len, int family);
返回:非空指針—成功,空指針—出錯,同時設置h_error。

函數根據一個二進制的IP地址並試圖找出相應於此地址的主機名,我們關心的是規範主機名h_name。

參數addr不是char *類型,而是一個真正指向含有IPv4或IPv6地址的結構in_addr或in6_addr的指針;len是該結構的大小,對於IPv4是4,對於IPv6是16;family或爲AF_INET或爲AF_INET6。

按照DNS的說法,該函數查詢PTR記錄。


23.uname函數

#include <sys/utsname.h>
int uname(struct utsname *name);
返回:非負值—成功,-1—失敗。

返回當前主機的名字,存放在如下的結構裏:
#define UTS_NAMESIZE 16
#define UTS_NODESIZE 256
struct utsname {
    char sysname[UTS_NAMESIZE];
    char nodename[UTS_NODESIZE];
    char release[UTS_NAMESIZE];
    char version[UTS_NAMESIZE];
    char machine[UTS_NAMESIZE];
};

該函數經常與gethostbyname一起用來確定本機的IP地址:先調用uname獲得主機名字,然後調用gethostbyname得到所有的IP地址。

獲得本機IP地址的另一個方法是ioctl的命令SIOCGIFCONF。


24.gethostname函數

#include <unistd.h>
int gethostname(char *name, size_t namelen);
返回:0—成功,-1—失敗。

返回當前主機的名字。name是指向主機名存儲位置的指針,namelen是此數組的大小,如果有空間,主機名以空字符結束。

主機名的最大大小通常是頭文件<sys/param.h>定義的常值MAXHOSTNAMELEN。


25.getservbyname函數

#include <netdb.h>
struct servent *getservbyname(const char *servname, const char *protoname);
返回:非空指針—成功,空指針—失敗。

函數返回如下結構的指針:
struct servent {
    char *s_name;
    char **s_aliases;
    int s_port;
    char *s_proto;
};

服務名servname必須指定,如果還指定了協議(protoname爲非空指針),則結果表項必須有匹配的記錄。如果沒有指定協議名而服務支持多個協議,則返回哪個端口是依賴於實現的。

結構中的端口號是以網絡字節序返回的,所以在將它存儲在套接口地址結構時,絕對不能調用htons。


26.getservbyport函數

#include <netdb.h>
struct servent *getservbyport(int port, const char *protname);
返回:非空指針—成功,空指針—出錯。

port必須爲網絡字節序。例如:
sptr = getservbyport(htons(53), “udp”);


27.recv和send

#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
ssize_t send(int sockfd, void *buf, size_t nbytes, int flags);
返回:成功返回讀入或寫出的字節數,出錯返回-1。

前三個參數與read和write相同,參數flags的值或爲0,或由以下的一個或多個常值邏輯或構成:

flags 描述 recv send




MSG_DONTROUTE 不查路由表
y
MSG_DONTWAIT 本操作不阻塞 y y
MSG_OOB 發送或接收帶外數據 y y
MSG_PEEK 查看外來的消息 y
MSG_WAITALL 等待所有數據 y

下面說明每個標誌的作用:

  • MSG_DONTROUTE:這個標誌告訴內核目的主機在直接連接的本地網絡上,不要查路由表。這是對提供這種特性的SO_DONTROUTE套接口選項的補充。該標誌可以對單個輸出操作提供這種特性,而套接口選項則針對某個套接口上的所有輸出操作。
  • MSG_DONTWAIT:這個標誌將單個I/O操作設爲非阻塞方式,而不需要在套接口上打開非阻塞標誌,執行I/O操作,然後關閉阻塞標誌。
  • MSG_OOB:用send時,這個標誌指明發送的是帶外數據,用recv時,該標誌指明要讀的是帶外數據而不是一般數據。
  • MSG_PEEK:這個標誌可以讓我們查看可讀的數據,在recv或recvfrom後系統不會將這些數據丟棄。
  • MSG_WAITALL:由4.3BSD Reno引入,他告訴內核在沒有讀到請求的字節數之前不使讀操作返回。如果系統支持這個標誌,則可以去掉readn函數。即使設定了該標誌,如果發生如下情況:(1)捕獲了一個信號;(2)連接被終止;(3)在套接口上發生錯誤,這個函數返回的字節數仍會比請求的少。

28.readv和writev

#include <sys/uio.h>
ssize_t readv(int filedes, const struct iovec *iov, int iovcnt);
ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);
返回:讀到或寫出的字節數,出錯返回-1。

readv和writev可以讓我們在一個函數調用中讀或寫多個緩衝區,這些操作被稱爲分散讀和集中寫。

iovec結構定義如下:
struct iovec {
    void *iov_base; /* starting address of buffer */
    size_t iov_len; /* size of buffer */
};

在具體的實現中對iovec結構數組的元素個數有限制,4.3BSD最多允許1024個,而Solaris2.5上限是16。Posix.1g要求定義一個常值IOV_MAX,而且它的值不小於16。

readv和writev可用於任何描述字。writev是一個原子操作,可以避免多次寫引發的Nagle算法。


29.readmsg和writemsg

#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags);
返回:成功時爲讀入或寫出的字節數,出錯時爲-1。

這兩個函數是最通用的套接口I/O函數,可以用recvmsg代替read、readv、recv和recvfrom,同樣,各種輸出函數都可以用sendmsg代替。

參數msghdr結構的定義如下:
struct msghdr {
    void *msg_name; /* protocol address */
    socklen_t msg_namelen; /* size of protocol address */
    struct iovec *msg_iov; /* scatter/gather array */
    size_t msg_iovlen; /* elements in msg_iov */
    void *msg_control; /* ancillary data; must be aligned for a cmsghdr structure */
    socklen_t msg_controllen; /* length of ancillary data */
    int msg_flags; /* flags returned by recvmsg() */
};

該結構源自4.3BSD Reno,也是Posix.1g中所說明的,有些系統仍使用一種老的msghdr結構,此種結構中沒有msg_flags成員,而且 msg_control和msg_controllen成員分別被叫做msg_accrights和msg_accrightslen。老系統中支持的唯一一種輔助數據形式是文件描述字(稱爲訪問權限)的傳遞。

msg_name和msg_namelen成員用於未經連接的套接口,他們與 recvfrom和sendto的第五和第六個參數類似:msg_name指向一個套接口地址結構,如果不需要指明協議地址,msg_name應被設置爲空指針,msg_namelen對sendmsg是一個值,而對recvmsg是一個值-結果參數。

msg_iov和msg_iovlen成員指明輸入或輸出的緩衝區數組。

msg_control和msg_controllen指明可選的輔助數據的位置和大小,msg_controllen對recvmsg是一個值-結果參數。

msg_flags只用於revmsg,調用recvmsg時,flags參數被拷貝到msg_flags成員,而且內核用這個值進行接收處理,接着它的值會根據recvmsg的結果而更新,sendmsg會忽略msg_flags成員,因爲它在進行輸出處理時使用flags參數。

內核檢查的flags和返回的msg_flags如下表所示:

標誌 在send flags、
sendto flags、
sendmsg flags中檢查
在recv flags、
recvfrom flags、
recvmsg flags中檢查
在recvmsg msg_flags
中返回




MSG_DONTROUTE y

MSG_DONTWAIT y y
MSG_PEEK
y
MSG_WAITALL
y
MSG_EOR y
y
MSG_OOB y y y
MSG_BCAST

y
MSG_MCAST

y
MSG_TRUNC

y
MSG_CTRUNC

y

前四個標誌只檢查不返回,下兩個標誌既檢查又返回,最後四個只返回。返回的六個標誌含義如下:

  • MSG_BCAST:當收到的數據報是一個鏈路層的廣播或其目的IP地址爲廣播地址時,將返回此標誌。
  • MSG_MCAST:當收到的數據報是鏈路層的多播時,將返回該標誌。
  • MSG_TRUNC:這個標誌在數據報被截斷時返回。
  • MSG_CTRUNC:這個標誌在輔助數據被截斷時返回。
  • MSG_EOR:如果返回的數據不是一個邏輯記錄的結尾,該標誌被清位,反之則置位。TCP不使用這個標誌,因爲它是一種字節流協議。
  • MSG_OOB:這個標誌不是爲TCP的帶外數據返回的,它用於其他協議族(譬如OSI協議等)。

具體的實現可能會在msg_flags中返回一些輸入的flags的標誌,所以我們應該只檢查那些感興趣的標誌的值。


30.socketpair函數

#include <sys/socket.h>
int socketpair(int family, int type, int protocol, int sockfd[2]);
返回:成功返回0,出錯返回-1。

family必須爲AF_LOCAL,protocol必須爲0,type可以是SOCK_STREAM或SOCK_DGRAM。新創建的兩個套接口描述字作爲sockfd[0]和sockfd[1]返回。

這兩個描述字相互連接,沒有名字,即沒有涉及隱式bind。

以SOCK_STREAM作爲type調用所得到的結果稱爲流管道(stream pipe)。這與一般的UNIX管道類似,但流管道是全雙工的,兩個描述字都是可讀寫的。


31.套接口ioctl函數

#include <unistd.h>
int ioctl(int fd, int request, … /* void *arg */ );
返回:成功返回0,出錯返回-1。

第三個參數總是一個指針,但指針的類型依賴於request。

ioctl和網絡有關的請求可分爲如下6類:

類別 request 描述 數據類型




套接口 SIOCATMARK 在帶外標誌上嗎 int

SIOCSPGRP 設置套接口的進程ID或進程組ID int

SIOCGPGRP 獲取套接口的進程ID或進程組ID int




文件 FIONBIO 設置/清除非阻塞標誌 int

FIOASYNC 設置/清除異步I/O標誌 int

FIONREAD 獲取接收緩衝區中的字節數 int

FIOSETOWN 設置文件的進程ID或進程組ID int

FIOGETOWN 獲取文件的進程ID或進程組ID int




接口 SIOCGIFCONF 獲取所有接口的列表 struct ifconf

SIOCSIFADDR 設置接口地址 struct ifreq

SIOCGIFADDR 獲取接口地址 struct ifreq

SIOCSIFFLAGS 設置接口標誌 struct ifreq

SIOCGIFFLAGS 獲取接口標誌 struct ifreq

SIOCSIFDSTADDR 設置點到點地址 struct ifreq

SIOCGIFDSTADDR 獲取點到點地址 struct ifreq

SIOCGIFBRDADDR   獲取廣播地址 struct ifreq

SIOCSIFBRDADDR 設置廣播地址 struct ifreq

SIOCGIFNETMASK 獲取子網掩碼 struct ifreq

SIOCSIFNETMASK 設置子網掩碼 struct ifreq

SIOCGIFMETRIC 獲取接口的測度(metric) struct ifreq

SIOCSIFMETRIC 設置接口的測度(metric) struct ifreq

SIOCxxx (有很多,依賴於實現)




ARP SIOCSARP 創建/修改ARP項 struct arpreq

SIOCGARP 獲取ARP項 struct arpreq

SIOCDARP 刪除ARP項 struct arpreq




路由 SIOCADDRT 增加路徑 struct rtentry

SIOCDELRT 刪除路徑 struct rtentry




I_xxx

 

(1)套接口操作

  • SIOCATMARK:如果套接口的讀指針當前在帶外標誌上,則通過第三個參數指向的整數返回一個非零值,否則返回零。Posix.1g用sockatmark代替了這種請求。
  • SIOCGPGRP:通過第三個參數指向的整數返回爲接收來自這個套接口的SIGIO或SIGURG信號而設置的進程ID或進程組ID。這和fcntl的F_GETOWN相同。
  • SIOCSPGRP:用第三個參數指向的整數設置進程ID或進程組ID以接收這個套接口的SIGIO或SIGURG信號。這和fcntl的F_SETOWN相同。

(2)文件操作

  • FIONBIO:套接口的非阻塞標誌會根據第三個參數指向的值是否爲零而清除或設置。等價於fcntl的F_SETFL設置/清除O_NONBLOCK標誌。
  • FIOASYNC:根據第三個參數指向的值是否爲零決定清除或接收套接口上的異步I/O信號。等價於fcntl的F_SETFL設置和清除O_AYNC標誌。
  • FIONREAD:在第三個參數指向的整數中返回套接口接收緩衝區中當前的字節數。
  • FIOSETOWN:在套接口上等價於SIOCSPGRP。
  • FIOGETOWN:在套接口上等價於SIOCGPGRP。

(3)接口配置

SIOCGIFCONF:從內核中獲取系統中配置的所有接口。它使用了結構ifconf,ifconf又使用了ifreq結構。

結構定義如下:
struct ifconf {
    int ifc_len; /* size of buffer, value-result */
    union {
        caddr_t ifcu_buf; /* input from user->kernel */
        struct ifreq *ifcu_req; /* return from kernel->user */
    }ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf
#define ifc_req ifc_ifcu.ifcu_req
#define IFNAMSIZ 16

struct ifreq {
    char ifr_name[IFNAMSIZ];
    union {
        struct sockaddr ifru_addr;
        struct sockaddr ifru_dstaddr;
        struct sockaddr ifru_broadaddr;
        short ifru_flags;
        int ifru_metric;
        caddr_t ifru_data;
    }ifr_ifru;
};
#define ifr_addr ifr_ifru.ifru_addr
#define ifr_dstaddr ifr_ifru.ifru_dstaddr
#define ifr_broadaddr ifr_ifru.broadaddr
#define ifr_flags ifr_ifru.ifru_flags
#define ifr_metric ifr_ifru.ifru_metric
#define ifr_data ifr_ifru.ifru_data

在調用ioctl之前分配一個緩衝區和一個ifconf結構,然後初始化後者,iotctl的第三個參數指向ifconf結構。

一個實現獲取所有接口的程序,可參見unpv12e:lib/get_ifi_info.c

 

 

(4)接口操作

  • SIOCGIFCONF:從內核中獲取系統中配置的所有接口。

(5)ARP高速緩存操作

(6)路由表操作

http://www.cnblogs.com/riky/archive/2006/11/24/570713.aspx

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