linux系統(tǒng)開發(fā): 學(xué)習(xí)Linux下網(wǎng)絡(luò)編程(linux開發(fā)板)

      網(wǎng)友投稿 1652 2022-05-30

      第一章 TCP網(wǎng)絡(luò)編程

      1.1 socket創(chuàng)建套接字

      #include

      #include

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

      功能

      創(chuàng)建網(wǎng)絡(luò)套接字,用于網(wǎng)絡(luò)通信使用,類似于文件操作的open函數(shù)。該函數(shù)在服務(wù)器和客戶端都會(huì)用到。

      參數(shù)

      int domain :網(wǎng)絡(luò)協(xié)議版本指定。

      AF_INET??????? IPv4 Internet protocols

      AF_INET6?????? IPv6 Internet protocols

      int type:指定通信協(xié)議類型。

      SOCK_STREAM 表明我們用的是TCP協(xié)議 (字節(jié)流)

      SOCK_DGRAM 表明我們用的是UDP協(xié)議 (數(shù)據(jù)報(bào))

      int protocol:指定通信協(xié)議類型。Type參數(shù)已經(jīng)指定了協(xié)議,該參數(shù)直接填0即可!

      返回值

      成功返回網(wǎng)絡(luò)套接字,與open函數(shù)返回值類似。

      Linux系統(tǒng)開發(fā): 學(xué)習(xí)Linux下網(wǎng)絡(luò)編程(linux開發(fā)板)

      示例

      Clientfd = socket(PF_INET,SOCK_STREAM,0);

      1.2 bind綁定IP-端口

      #include ????????? /* See NOTES */

      #include

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

      功能

      創(chuàng)建服務(wù)器。該函數(shù)在服務(wù)器端使用。

      參數(shù)

      int sockfd : 網(wǎng)絡(luò)套接字

      const struct sockaddr *addr? :填充創(chuàng)建服務(wù)器所需的地址信息,詳細(xì)的成員看1.3章節(jié)。

      socklen_t addrlen :地址長(zhǎng)度,就是該結(jié)構(gòu)體的大小。使用sizeof函數(shù)進(jìn)行計(jì)算。

      返回值

      0表示成功,-1表示失敗!

      1.3 struct sockaddr地址結(jié)構(gòu)體

      1.3.1 結(jié)構(gòu)體成員解析

      在實(shí)際填充參數(shù)的過(guò)程中,struct sockaddr結(jié)構(gòu)體被struct sockaddr_in結(jié)構(gòu)體代替。struct sockaddr_in結(jié)構(gòu)體比struct sockaddr可讀性強(qiáng)一些,填充參數(shù)比較好理解。

      struct sockaddr_in和struct sockaddr大小相同。在填充結(jié)構(gòu)體的時(shí)候?yàn)榱朔奖闾畛鋮?shù),使用struct sockaddr_in結(jié)構(gòu)體,給函數(shù)賦值的時(shí)候需要強(qiáng)制轉(zhuǎn)換為struct sockaddr類型的結(jié)構(gòu)體。因?yàn)榈讓雍瘮?shù)最終還是使用struct sockaddr類型的結(jié)構(gòu)體。

      struct sockaddr結(jié)構(gòu)體成員:

      struct sockaddr {undefined

      sa_family_t sa_family;????? //網(wǎng)絡(luò)協(xié)議版本。填寫:AF_INET 或者 AF_INET6。

      char??????? sa_data[14];?? //IP地址和端口

      }

      struct sockaddr_in結(jié)構(gòu)體成員:

      查看IPV4協(xié)議幫助文檔:# man? 7? ip

      struct sockaddr_in {undefined

      sa_family_t??? sin_family;? /* address family: AF_INET?? 協(xié)議類型*/

      in_port_t????? sin_port;?? /* port in network byte order?? 端口號(hào)*/

      struct in_addr sin_addr;??? /* internet address?? 存放IP地址的結(jié)構(gòu)體*/

      };

      /* Internet address. */

      struct in_addr {undefined

      uint32_t?????? s_addr;???? /* address in network byte order IP地址 */

      };

      1.3.2 端口號(hào)賦值

      計(jì)算機(jī)數(shù)據(jù)存儲(chǔ)有兩種字節(jié)優(yōu)先順序: 高位字節(jié)優(yōu)先和低位字節(jié)優(yōu)先。 Internet 上數(shù)據(jù)以高位字節(jié)優(yōu)先順序在網(wǎng)絡(luò)上傳輸, 所以對(duì)于在內(nèi)部是以低位字節(jié)優(yōu)先方式存儲(chǔ)數(shù)據(jù)的機(jī)器, 在 Internet 上傳輸數(shù)據(jù)時(shí)就需要進(jìn)行轉(zhuǎn)換, 否則就會(huì)出現(xiàn)數(shù)據(jù)不一致。

      普通人用的桌面電腦,只要是Intel或AMD的x86/x64架構(gòu)就一定是小端字節(jié)序。

      外很多ARM CPU可以選擇數(shù)據(jù)指令字節(jié)序,不過(guò)通常也都是運(yùn)行小端字節(jié)序(比如我們的智能手機(jī))。

      網(wǎng)絡(luò)設(shè)備,像PowerPC核心的一些路由器,默認(rèn)運(yùn)行大端字節(jié)序。

      下面是幾個(gè)字節(jié)順序轉(zhuǎn)換函數(shù):

      ·htonl(): 把 32 位值從主機(jī)字節(jié)序轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序

      ·htons(): 把 16 位值從主機(jī)字節(jié)序轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序

      ·ntohl(): 把 32 位值從網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換成主機(jī)字節(jié)序

      ·ntohs(): 把 16 位值從網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換成主機(jī)字節(jié)序

      函數(shù)原型

      #include

      uint32_t htonl(uint32_t hostlong);

      uint16_t htons(uint16_t hostshort);

      uint32_t ntohl(uint32_t netlong);

      uint16_t ntohs(uint16_t netshort);

      網(wǎng)際協(xié)議在處理這些多字節(jié)整數(shù)時(shí),使用大端字節(jié)序。

      在主機(jī)本身就使用大端字節(jié)序時(shí),這些函數(shù)通常被定義為空宏。

      給struct sockaddr_in結(jié)構(gòu)體的端口成員賦值的時(shí)候就需要用到以上大端轉(zhuǎn)小端函數(shù)進(jìn)行轉(zhuǎn)換!

      示例:

      /*結(jié)構(gòu)體成員賦值*/

      tcp_server.sin_family=AF_INET; //IPV4協(xié)議類型

      tcp_server.sin_port=htons(tcp_server_port);//端口號(hào)賦值,將本地字節(jié)序轉(zhuǎn)為網(wǎng)絡(luò)字節(jié)序

      tcp_server.sin_addr.s_addr=INADDR_ANY; //將本地IP地址賦值給結(jié)構(gòu)體成員

      //inet_addr("192.168.18.3"); //IP地址賦值

      1.3.3 IP地址賦值

      struct sockaddr_in結(jié)構(gòu)體存放IP地址的成員是struct in_addr 結(jié)構(gòu)體類型,底層存放地址的成員是一個(gè)無(wú)符號(hào)int類型,而我們生活中的IP地址是使用xxx.xxx.xxx.xxx 這種格式表示的。比如:192.168.1.1。 在賦值的時(shí)候就需要進(jìn)行將”192.168.1.1”這種格式轉(zhuǎn)為無(wú)符號(hào)int類型才能進(jìn)行賦值。

      以下是幾個(gè)IP格式轉(zhuǎn)換函數(shù):

      將字符串類型IP轉(zhuǎn)為in_addr_t類型(unsigned int)返回。

      in_addr_t inet_addr(const char *cp);

      示例:

      Serveraddr.sin_addr.s_addr = inet_addr("192.168.18.3");

      使用字符串類型的IP直接給結(jié)構(gòu)體成員賦值

      int inet_aton(const char *cp, struct in_addr *inp);

      示例:

      inet_aton(“192.168.18.3”,&Clientaddr.sin_addr);

      將結(jié)構(gòu)體里的IP地址成員轉(zhuǎn)為字符串類型返回

      char *inet_ntoa(struct in_addr in);

      該函數(shù)與上面兩個(gè)函數(shù)功能剛好相反。是將整型的IP轉(zhuǎn)為字符串類型!

      1.3.4 本地計(jì)算機(jī)大小端判斷

      首先說(shuō)明,電腦大小端指的是一種存儲(chǔ)模式。

      為什么有大小端:

      在計(jì)算機(jī)系統(tǒng)中,我們是以字節(jié)為單位的,每個(gè)地址單元都對(duì)應(yīng)著一個(gè)字節(jié),一個(gè)字節(jié)為 8bit。但是在C語(yǔ)言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器),另外,對(duì)于位數(shù)大于 8位的處理器,例如16位或者32位的處理器,由于寄存器寬度大于一個(gè)字節(jié),那么必然存在著一個(gè)如何將多個(gè)字節(jié)安排的問(wèn)題,因此就導(dǎo)致了大端存儲(chǔ)模式和小端存儲(chǔ)模式。

      大小端定義:

      大端模式(Big-endian),是指數(shù)據(jù)的高字節(jié),保存在內(nèi)存的低地址中,而數(shù)據(jù)的低字節(jié),保存在內(nèi)存的高地址中。

      小端模式(Little-endian),是指數(shù)據(jù)的高字節(jié)保存在內(nèi)存的高地址中,而數(shù)據(jù)的低字節(jié)保存在內(nèi)存的低地址中。

      直接來(lái)看一個(gè)圖,詳細(xì)說(shuō)明大小端:

      例子:int i = 0x12345678 兩種模式存入內(nèi)存:

      4. 判斷大小端的C語(yǔ)言代碼

      #include

      int CheckSystem()

      {

      union check

      {

      int i;

      char ch;

      }c;

      c.i=1;

      return (c.ch==1);

      }

      int main()

      {

      int check=CheckSystem();

      if(check==1)

      printf("當(dāng)前系統(tǒng)為小端\n");

      else

      printf("當(dāng)前系統(tǒng)為大端\n");

      return 0;

      }

      ///

      // 公用的四個(gè)字節(jié)地址 :0x1001 -> 0x1002 -> 0x1003 -> 0x1004

      //?? 小端來(lái)說(shuō) ?賦值 1 : 0x01????? 0x00????? 0x00????? 0x00

      //?? 大端來(lái)說(shuō)? 賦值 1 : 0x00????? 0x00????? 0x00????? 0x01

      //也就是說(shuō)存數(shù)據(jù)都是從低地址存放 一個(gè)char字節(jié),

      //他和int開始的地址是一樣的 讀的話 還是從低字節(jié)向高字節(jié)完整的讀取

      1.4 listen監(jiān)聽端口的數(shù)量

      #include ????????? /* See NOTES */

      #include

      int listen(int sockfd, int backlog);

      功能

      設(shè)置服務(wù)器需要監(jiān)聽的端口數(shù)量。決定了能夠同時(shí)響應(yīng)連接的服務(wù)器數(shù)量。

      返回值

      成功返回0,失敗返回-1。

      服務(wù)器創(chuàng)建,函數(shù)調(diào)用順序:

      示例:listen(Serverfd,10)

      1.5 accept 等待客戶端連接

      #include ????????? /* See NOTES */

      #include

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

      功能

      以阻塞的形式等待客戶端連接。

      參數(shù)

      struct sockaddr *addr? :存放已經(jīng)連接的客戶端信息。傳入一個(gè)結(jié)構(gòu)體地址。

      socklen_t *addrlen??? :表示客戶端的結(jié)構(gòu)體大小。該大小需要我們指定,客戶端連接成功然后再判斷是否與填寫的大小一致。

      返回值

      成功將返回客戶端的網(wǎng)絡(luò)套接字。錯(cuò)誤返回-1。

      示例:

      struct sockaddr_in Clientaddr;

      len = sizeof(struct sockaddr);

      Clientfd = accept(Serverfd,(struct sockaddr *)&Clientaddr,&len);

      1.6 connect連接服務(wù)器

      #include ????????? /* See NOTES */

      #include

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

      功能

      連接到指定服務(wù)器。該函數(shù)在客戶端使用。

      參數(shù)

      int sockfd :socket函數(shù)的網(wǎng)絡(luò)套接字。

      const struct sockaddr *addr :服務(wù)器的IP地址信息。 參考:1.2節(jié)和1.3.節(jié)

      socklen_t addrlen :結(jié)構(gòu)體的大小。

      返回值

      成功返回0,錯(cuò)誤返回-1。

      示例

      connect(Clientfd,(struct sockaddr *)&Clientaddr,sizeof(struct sockaddr));

      1.7 send/ recv網(wǎng)絡(luò)數(shù)據(jù)收發(fā)

      #include

      #include

      ssize_t send(int sockfd, const void *buf, size_t len, int flags);

      ssize_t recv (int sockfd, void *buf, size_t len, int flags);

      功能

      客戶端與服務(wù)器之間的數(shù)據(jù)收發(fā)。

      參數(shù)

      const void *buf 、void *buf :讀寫的緩沖區(qū)。

      int flags :填0。

      以上兩個(gè)函數(shù)可以使用write和read函數(shù)替換。

      1.8 shutdown關(guān)閉連接

      #include

      int shutdown(int sockfd, int how);

      返回

      0—成功,-1—失敗。

      參數(shù)how的值:

      SHUT_RD:關(guān)閉連接的讀這一半,不再接收套接口中的數(shù)據(jù)且留在套接口緩沖區(qū)中的數(shù)據(jù)都作廢。進(jìn)程不能再對(duì)套接口任何讀函數(shù)。調(diào)用此函數(shù)后,由TCP套接口接收的任何數(shù)據(jù)都被確認(rèn),但數(shù)據(jù)本身被扔掉。

      SHUT_WR:關(guān)閉連接的寫這一半,在TCP場(chǎng)合下,這稱為半關(guān)閉。當(dāng)前留在套接口發(fā)送緩沖區(qū)中的數(shù)據(jù)都被發(fā)送,后跟正常的TCP連接終止序列。此半關(guān)閉不管套接口描述字的訪問(wèn)計(jì)數(shù)是否大于0。進(jìn)程不能再執(zhí)行對(duì)套接口的任何寫函數(shù)。

      SHUT_RDWR:連接的讀這一半和寫這一半都關(guān)閉。這等效于調(diào)用shutdown兩次:第一次調(diào)用時(shí)用SHUT_RD,第二次調(diào)用時(shí)用SHUT_WR。

      shutdown(tcp_client_fd,SHUT_WR);? //TCP半關(guān)閉,保證緩沖區(qū)內(nèi)的數(shù)據(jù)全部寫完

      直接強(qiáng)制關(guān)閉連接示例:

      int close(int fd);

      1.9 查看Linux系統(tǒng)當(dāng)前的網(wǎng)絡(luò)連接

      在/proc/net/tcp目錄下面保存了當(dāng)前系統(tǒng)所有TCP鏈接的狀態(tài)信息。

      查看示例:

      [root@wbyq FileSend2]# cat /proc/net/tcp

      sl? local_address rem_address?? st tx_queue rx_queue tr tm->when retrnsmt?? uid? timeout inode

      0: 00000000:006F 00000000:0000 0A 00000000:00000000 00:00000000 00000000???? 0??????? 0 13264 1 c16ac5c0 99 0 0 10 -1

      1: 00000000:DA10 00000000:0000 0A 00000000:00000000 00:00000000 00000000??? 29??????? 0 13592 1 c16ac0c0 99 0 0 10 -1

      2: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000???? 0??????? 0 14400 1 c16acac0 99 0 0 10 -1

      3: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000???? 0??????? 0 13851 1 c142f080 99 0 0 10 -1

      4: 0100007F:0019 00000000:0000 0A 00000000:00000000 00:00000000 00000000???? 0??????? 0 14753 1 c142fa80 99 0 0 10 -1

      5: 813DA8C0:A019 49AAC3CB:0522 01 00000000:00000000 00:00000000 00000000? ???0??????? 0 123641 1 c142f580 20 3 18 10 -1

      說(shuō)明:? 這里的IP地址信息和端口號(hào)都是使用十六進(jìn)制保存的。

      813DA8C0:A019 49AAC3CB:0522

      查看網(wǎng)絡(luò)狀態(tài)連接:

      [root@wbyq FileSend2]# netstat -ntp

      Active Internet connections (w/o servers)

      Proto Recv-Q Send-Q?? Local Address??????? ?Foreign Address?????? State??????????? PID/Program name

      tcp??????? 0? 0???? 192.168.61.129:40985???? 203.195.170.73:1314 ???ESTABLISHED?? 20955/./app_c

      從上面可得到的信息:

      連接類型: TCP協(xié)議

      本地IP地址和端口號(hào): 192.168.61.129:40985

      與其通信的遠(yuǎn)程IP地址和端口號(hào): 203.195.170.73:1314

      狀態(tài): ESTABLISHED(已建立的連接)

      進(jìn)程PID號(hào)與應(yīng)用程序名稱: 20955/./app_c

      socket網(wǎng)絡(luò)連接的狀態(tài)如下

      1、LISTENING狀態(tài)

      FTP服務(wù)啟動(dòng)后首先處于偵聽(LISTENING)狀態(tài)。

      2、ESTABLISHED狀態(tài)

      ESTABLISHED的意思是建立連接。表示兩臺(tái)機(jī)器正在通信。

      3、CLOSE_WAIT

      對(duì)方主動(dòng)關(guān)閉連接或者網(wǎng)絡(luò)異常導(dǎo)致連接中斷,這時(shí)我方的狀態(tài)會(huì)變成CLOSE_WAIT 此時(shí)我方要調(diào)用close()來(lái)使得連接正確關(guān)閉

      4、TIME_WAIT

      我方主動(dòng)調(diào)用close()斷開連接,收到對(duì)方確認(rèn)后狀態(tài)變?yōu)門IME_WAIT。TCP協(xié)議規(guī)定TIME_WAIT狀態(tài)會(huì)一直持續(xù)2MSL(即兩倍的分 段最大生存期),以此來(lái)確保舊的連接狀態(tài)不會(huì)對(duì)新連接產(chǎn)生影響。處于TIME_WAIT狀態(tài)的連接占用的資源不會(huì)被內(nèi)核釋放,所以作為服務(wù)器,在可能的情 況下,盡量不要主動(dòng)斷開連接,以減少TIME_WAIT狀態(tài)造成的資源浪費(fèi)。

      目前有一種避免TIME_WAIT資源浪費(fèi)的方法,就是關(guān)閉socket的LINGER選項(xiàng)。但這種做法是TCP協(xié)議不推薦使用的,在某些情況下這個(gè)操作可能會(huì)帶來(lái)錯(cuò)誤。

      5、SYN_SENT狀態(tài)

      SYN_SENT狀態(tài)表示請(qǐng)求連接,當(dāng)你要訪問(wèn)其它的計(jì)算機(jī)的服務(wù)時(shí)首先要發(fā)個(gè)同步信號(hào)給該端口,此時(shí)狀態(tài)為SYN_SENT,如果連接成功了就變?yōu)?ESTABLISHED,此時(shí)SYN_SENT狀態(tài)非常短暫。但如果發(fā)現(xiàn)SYN_SENT非常多且在向不同的機(jī)器發(fā)出,那你的機(jī)器可能中了沖擊波或震蕩波 之類的病毒了。這類病毒為了感染別的計(jì)算機(jī),它就要掃描別的計(jì)算機(jī),在掃描的過(guò)程中對(duì)每個(gè)要掃描的計(jì)算機(jī)都要發(fā)出了同步請(qǐng)求,這也是出現(xiàn)許多 SYN_SENT的原因。

      根據(jù)TCP協(xié)議定義的3次握手?jǐn)嚅_連接規(guī)定,發(fā)起socket主動(dòng)關(guān)閉的一方 socket將進(jìn)入TIME_WAIT狀態(tài),TIME_WAIT狀態(tài)將持續(xù)2個(gè)MSL(Max Segment Lifetime),在Windows下默認(rèn)為4分鐘,即240秒,TIME_WAIT狀態(tài)下的socket不能被回收使用. 具體現(xiàn)象是對(duì)于一個(gè)處理大量短連接的服務(wù)器,如果是由服務(wù)器主動(dòng)關(guān)閉客戶端的連接,將導(dǎo)致服務(wù)器端存在大量的處于TIME_WAIT狀態(tài)的socket, 甚至比處于Established狀態(tài)下的socket多的多,嚴(yán)重影響服務(wù)器的處理能力,甚至耗盡可用的socket,停止服務(wù). TIME_WAIT是TCP協(xié)議用以保證被重新分配的socket不會(huì)受到之前殘留的延遲重發(fā)報(bào)文影響的機(jī)制,是必要的邏輯保證.

      第二章 UDP網(wǎng)絡(luò)編程

      2.1 UDP協(xié)議創(chuàng)建流程

      2.2 數(shù)據(jù)報(bào)收發(fā)函數(shù)

      2.2.1 recvfrom函數(shù)

      UDP使用recvfrom()函數(shù)接收數(shù)據(jù),他類似于標(biāo)準(zhǔn)的read(),但是在recvfrom()函數(shù)中要指明數(shù)據(jù)的目的地址。

      #include

      #include

      ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr * from, size_t *addrlen);

      返回值

      成功返回接收到數(shù)據(jù)的長(zhǎng)度,負(fù)數(shù)失敗

      前三個(gè)參數(shù)等同于函數(shù)read()的前三個(gè)參數(shù),flags參數(shù)是傳輸控制標(biāo)志。最后兩個(gè)參數(shù)類似于accept的最后兩個(gè)參數(shù)(接收客戶端的IP地址)。

      示例:

      /*阻塞方式接收數(shù)據(jù)*/

      int len=0;

      char buff[1024];

      size_t addrlen=sizeof(struct sockaddr);

      while(1)

      {undefined

      len=recvfrom(socketfd,buff,1024,0,(struct sockaddr *)&ClientSocket,&addrlen);

      buff[len]='\0';

      printf("Rx: %s,len=%d\n",buff,len);

      printf("數(shù)據(jù)發(fā)送方IP地址:%s\n",inet_ntoa(ClientSocket.sin_addr));

      printf("數(shù)據(jù)發(fā)送方端口號(hào):%d\n",ntohs(ClientSocket.sin_port));

      }

      2.2.2 sendto函數(shù)

      UDP使用sendto()函數(shù)發(fā)送數(shù)據(jù),他類似于標(biāo)準(zhǔn)的write(),但是在sendto()函數(shù)中要指明目的地址。

      #include

      #include

      ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr * to, int addrlen);

      返回值

      成功返回發(fā)送數(shù)據(jù)的長(zhǎng)度,失敗返回-1

      前三個(gè)參數(shù)等同于函數(shù)read()的前三個(gè)參數(shù),flags參數(shù)是傳輸控制標(biāo)志。參數(shù)to指明數(shù)據(jù)將發(fā)往的協(xié)議地址,他的大小由addrlen參數(shù)來(lái)指定。

      示例:

      /*向UDP協(xié)議服務(wù)器發(fā)送數(shù)據(jù)*/

      ServerSocket.sin_family=PF_INET; //協(xié)議

      ServerSocket.sin_port=htons(PROT); //端口

      ServerSocket.sin_addr.s_addr=inet_addr(argv[1]);? //表示服務(wù)器的IP地址

      bzero(ServerSocket.sin_zero,8); //初始化空間

      char buff[]="1234567890";

      int len=0;

      while(1)

      {undefined

      len=sendto(socketfd,buff,strlen(buff),0,(const struct sockaddr*)&ServerSocket,sizeof(struct sockaddr));

      printf("Tx: %d\n",len);

      sleep(1);

      }

      第三章 設(shè)置Socket套接字屬性

      3.1 函數(shù)原型介紹

      #include ????????? /* See NOTES */

      #include

      int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);

      int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

      參數(shù)

      sockfd:標(biāo)識(shí)一個(gè)套接口的描述字。

      level:選項(xiàng)定義的層次;目前僅支持SOL_SOCKET和IPPROTO_TCP層次。

      optname:需設(shè)置的選項(xiàng)。

      optval:指針,指向存放選項(xiàng)值的緩沖區(qū)。

      optlen:optval緩沖區(qū)的長(zhǎng)度。

      3.2 屬性功能注釋

      setsockopt()函數(shù)用于任意類型、任意狀態(tài)套接口的設(shè)置選項(xiàng)值。盡管在不同協(xié)議層上存在選項(xiàng),但本函數(shù)僅定義了最高的“套接口”層次上的選項(xiàng)。選項(xiàng)影響套接口的操作,諸如加急數(shù)據(jù)是否在普通數(shù)據(jù)流中接收,廣播數(shù)據(jù)是否可以從套接口發(fā)送等等。

      setsockopt()支持的選項(xiàng)定義位置:/usr/include/asm-generic/socket.h

      #ifndef __ASM_GENERIC_SOCKET_H

      #define __ASM_GENERIC_SOCKET_H

      #include

      /* For setsockopt(2) */

      #define SOL_SOCKET? 1

      #define SO_DEBUG????? 1

      #define SO_REUSEADDR??? 2

      #define SO_TYPE????????? 3

      #define SO_ERROR?????? 4

      #define SO_DONTROUTE??? 5

      #define SO_BROADCAST??? 6

      #define SO_SNDBUF??? 7

      #define SO_RCVBUF??? 8

      #define SO_SNDBUFFORCE?????? 32

      #define SO_RCVBUFFORCE?????? 33

      #define SO_KEEPALIVE????? 9

      #define SO_OOBINLINE?????? 10

      #define SO_NO_CHECK?????? 11

      #define SO_PRIORITY 12

      #define SO_LINGER????? 13

      #define SO_BSDCOMPAT?? 14

      /* To add :#define SO_REUSEPORT 15 */

      #ifndef SO_PASSCRED /* powerpc only differs in these */

      #define SO_PASSCRED??????? 16

      #define SO_PEERCRED??????? 17

      #define SO_RCVLOWAT????? 18

      #define SO_SNDLOWAT????? 19

      #define SO_RCVTIMEO?????? 20

      #define SO_SNDTIMEO?????? 21

      #endif

      /* Security levels - as per NRL IPv6 - don't actually do anything */

      #define SO_SECURITY_AUTHENTICATION?????????? 22

      #define SO_SECURITY_ENCRYPTION_TRANSPORT?? 23

      #define SO_SECURITY_ENCRYPTION_NETWORK?????????????? 24

      #define SO_BINDTODEVICE????? 25

      /* Socket filtering */

      #define SO_ATTACH_FILTER??? 26

      #define SO_DETACH_FILTER??? 27

      #define SO_PEERNAME?????????????? 28

      #define SO_TIMESTAMP???????????? 29

      #define SCM_TIMESTAMP???????? SO_TIMESTAMP

      #define SO_ACCEPTCONN????????? 30

      #define SO_PEERSEC?????????? 31

      #define SO_PASSSEC?? ??????? 34

      #define SO_TIMESTAMPNS??????????????? 35

      #define SCM_TIMESTAMPNS??????????? SO_TIMESTAMPNS

      #define SO_MARK???????????????????????? 36

      #define SO_TIMESTAMPING????????????? 37

      #define SCM_TIMESTAMPING? SO_TIMESTAMPING

      #define SO_PROTOCOL??????????????? 38

      #define SO_DOMAIN??????????? 39

      #define SO_RXQ_OVFL??????????????? 40

      #endif /* __ASM_GENERIC_SOCKET_H */

      setsockopt()支持下列選項(xiàng)。其中“類型”表明optval所指數(shù)據(jù)的類型。

      選項(xiàng)

      類型

      意義

      SO_BROADCAST

      BOOL

      允許套接口傳送廣播信息。

      SO_DEBUG

      BOOL

      記錄調(diào)試信息。

      SO_DONTLINER

      BOOL

      不要因?yàn)閿?shù)據(jù)未發(fā)送就阻塞關(guān)閉操作。設(shè)置本選項(xiàng)相當(dāng)于將SO_LINGER的l_onoff元素置為零。

      SO_DONTROUTE

      BOOL

      禁止選徑;直接傳送。

      SO_KEEPALIVE

      BOOL

      發(fā)送“保持活動(dòng)”包。

      SO_LINGER

      struct linger FAR*

      如關(guān)閉時(shí)有未發(fā)送數(shù)據(jù),則逗留。

      SO_OOBINLINE

      BOOL

      在常規(guī)數(shù)據(jù)流中接收帶外數(shù)據(jù)。

      SO_RCVBUF

      int

      為接收確定緩沖區(qū)大小。

      SO_REUSEADDR

      BOOL

      允許套接口和一個(gè)已在使用中的地址捆綁(參見bind())。

      SO_SNDBUF

      int

      指定發(fā)送緩沖區(qū)大小。

      TCP_NODELAY BOOL

      禁止發(fā)送合并的Nagle算法。

      3.3 設(shè)置socket具有廣播特性

      發(fā)送UDP數(shù)據(jù)報(bào)的時(shí)候,設(shè)置socket具有廣播特性:(默認(rèn)情況下socket不支持廣播特性)

      const int opt = 1;

      //設(shè)置該套接字為廣播類型,

      int nb = 0;

      nb = setsockopt(client_fd, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt));

      if(nb == -1)

      {undefined

      printf("設(shè)置廣播類型錯(cuò)誤.\n");

      }

      3.4 設(shè)置socket發(fā)送和接收的緩沖區(qū)大小。

      系統(tǒng)默認(rèn)的狀態(tài)發(fā)送和接收一次為8688字節(jié)(約為8.5K);在實(shí)際的過(guò)程中發(fā)送數(shù)據(jù)和接收數(shù)據(jù)量比較大,可以設(shè)置socket緩沖區(qū)。

      // 接收緩沖區(qū)

      int nRecvBuf=20*1024;//設(shè)置為20K

      setsockopt(socketfd,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));

      //發(fā)送緩沖區(qū)

      int nSendBuf=20*1024;//設(shè)置為20K

      setsockopt(socketfd,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));

      3.5 設(shè)置收發(fā)時(shí)限

      在發(fā)送和接收過(guò)程中有時(shí)由于網(wǎng)絡(luò)狀況等原因,發(fā)收不能預(yù)期進(jìn)行,而設(shè)置收發(fā)時(shí)限:

      int nNetTimeout=1000;? //1秒

      //發(fā)送時(shí)限

      setsockopt(socketfd,SOL_SOCKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));

      //接收時(shí)限

      setsockopt(socketfd,SOL_SOCKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));

      3.6 允許套接字綁定已使用的端口

      有時(shí)候?qū)⒎?wù)器關(guān)閉之后,端口的釋放需要時(shí)間,可以設(shè)置該數(shù)據(jù)允許套接字綁定正在被占用的端口。

      int on = 1;

      setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

      3.7 忽略SIGPIPE信號(hào)

      往一個(gè)已經(jīng)接收到FIN的套接中寫是允許的,接收到的FIN僅僅代表對(duì)方不再發(fā)送數(shù)據(jù)。并不能代表我不能發(fā)送數(shù)據(jù)給對(duì)方。

      往一個(gè)FIN結(jié)束的進(jìn)程中寫(write),對(duì)方會(huì)發(fā)送一個(gè)RST字段過(guò)來(lái),TCP重置。

      如果再調(diào)用write就會(huì)產(chǎn)生SIGPIPE信號(hào)。

      (也就是當(dāng)服務(wù)器向客戶端發(fā)送數(shù)據(jù)時(shí),客戶端突然斷開連接,會(huì)導(dǎo)致SIGPIPE信號(hào)產(chǎn)生,如果不處理,系統(tǒng)默認(rèn)的處理方式就終止進(jìn)程)

      signal(SIGPIPE,SIG_IGN); ?//忽略SIGPIPE信號(hào)

      3.8 獲取網(wǎng)絡(luò)底層緩沖區(qū)發(fā)送剩余字節(jié)數(shù)

      在網(wǎng)絡(luò)編程時(shí),發(fā)送方調(diào)用write(fd)將報(bào)文發(fā)送的時(shí)候?qū)嶋H上只是寫入了內(nèi)核的write buffer。接收方什么時(shí)候能收到報(bào)文是個(gè)未知數(shù)。

      在某些需要同步狀態(tài)機(jī)的地方,發(fā)送方最好能夠確認(rèn)接收方收到報(bào)文后再進(jìn)行下一步動(dòng)作。

      linux提供了ioctl(fd, SIOCOUTQ, &count)方法來(lái)查詢一個(gè)tcp socket的write buffer是否清空。發(fā)送方一般可以用這個(gè)方法來(lái)判斷對(duì)端是否收到報(bào)文。當(dāng)?shù)讓泳W(wǎng)卡將緩沖區(qū)的數(shù)據(jù)全部發(fā)送成功時(shí),獲取的count=0

      #include?

      #include?

      int?value;

      ioctl(client_fd,SIOCOUTQ,&value);

      3.9 獲取當(dāng)前網(wǎng)絡(luò)協(xié)議底層發(fā)送與接收緩沖區(qū)大小

      int?sockfd;

      /*1.?創(chuàng)建socket套接字*/

      sockfd=socket(AF_INET,SOCK_STREAM,0);

      int?nRecvBuf;

      socklen_t??len=4;

      getsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&nRecvBuf,&len);

      printf("接收緩沖區(qū)大小=%d\n",nRecvBuf);

      //發(fā)送緩沖區(qū)

      int?nSendBuf;

      getsockopt(sockfd,SOL_SOCKET,SO_SNDBUF,&nSendBuf,&len);

      printf("發(fā)送緩沖區(qū)大小=%d\n",nSendBuf);

      Redhat6.3系統(tǒng)上輸出結(jié)果:

      接收緩沖區(qū)大小=87380

      發(fā)送緩沖區(qū)大小=16384

      Linux 數(shù)據(jù)結(jié)構(gòu) 網(wǎng)絡(luò)

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:分布式主動(dòng)感知在智能運(yùn)維中的實(shí)踐|分享實(shí)錄(物聯(lián)網(wǎng)中全面感知特點(diǎn)能夠感知哪些數(shù)據(jù))
      下一篇:數(shù)據(jù)庫(kù)開發(fā)升級(jí)變更技術(shù)探究(數(shù)據(jù)庫(kù)升級(jí)和配置變更前)
      相關(guān)文章
      中文字幕精品亚洲无线码二区| 亚洲国产一区明星换脸| 亚洲人成无码网站久久99热国产| 亚洲精品宾馆在线精品酒店| 亚洲免费黄色网址| 亚洲福利视频网站| 亚洲精品视频在线免费| 亚洲精选在线观看| 亚洲一区中文字幕久久| 亚洲国产成人久久综合碰碰动漫3d | 亚洲AV美女一区二区三区| 亚洲中文字幕无码一区| 国产亚洲色视频在线| 中文字幕亚洲无线码| 亚洲色偷拍另类无码专区| 在线亚洲人成电影网站色www| 中文字幕不卡亚洲 | 红杏亚洲影院一区二区三区| 亚洲片一区二区三区| 国产精品亚洲αv天堂无码| 中文字幕亚洲电影| 亚洲精品无码鲁网中文电影| 亚洲精品乱码久久久久久中文字幕 | 国产成人亚洲综合网站不卡| 亚洲日本在线电影| 国产成人精品日本亚洲语音 | 国产成人亚洲午夜电影| 亚洲国产精品视频| 国产亚洲精品福利在线无卡一| 亚洲精品无码久久一线| 亚洲国产精品婷婷久久| 亚洲性一级理论片在线观看| 国产v亚洲v天堂a无| 亚洲AV成人一区二区三区观看| 偷自拍亚洲视频在线观看99| 亚洲美女高清一区二区三区 | 亚洲婷婷第一狠人综合精品| 亚洲欧洲av综合色无码| avtt亚洲天堂| 亚洲日韩精品无码一区二区三区| 亚洲av丰满熟妇在线播放 |