<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Linux網絡編程(四 )

      前言:前面三篇文章的面試總結

      掌握:

      第一部分

      1、靜態庫和動態的區別和各自的使用命令,加載失敗問題和解決。

      2、GDB如何多線程調試,調試命令。

      3、虛擬地址空間的定義和含有的內容,文件描述符。

      4、API函數,需要會結合man命令學習各個函數,其中重要的有dup,dup2函數,fcntl函數用于修改文件描述符的指令。

      第二部分

      1、進程的狀態的轉換,轉換的條件等

      2、fork函數,父子進程虛擬地址空間,exec函數族去執行一個命令,把當前用戶區的內容替換成新的內容。

      3、進程退出、孤兒進程、僵尸進程定義,孤兒進程和僵尸進程的弊端,如何解決僵尸進程,采用回收子進程的資源(wait/waitpid函數),waitpid可以設置成非阻塞的。

      4、進程間通信的方式和實現代碼,方式有匿名管道、有名管道、內存映射、消息隊列、信號、共享內存。每種方式的原理或者流程需要掌握。

      5、信號方面,掌握定時器、信號捕捉 去捕捉信號做信號處理、SIGCHLD信號 子進程在結束或者狀態發生改變的時候會給父進程發送一個SIGCHLD信號。

      6、守護進程的定義,守護進程是后臺一直運行的后臺進程,周期性的去執行某些事情,守護進程的流程步驟。

      7、補充:進程的調度(策略和算法)

      第三部分

      1、掌握API ,創建、終止、連接已終止、分離、取消線程。

      2、線程和進程的區別,線程是共享一個虛擬地址空間,進程是fork出來一個新的虛擬地址空間,寫時復制,讀時共享的特點

      3、線程同步的定義,幾種方式,互斥鎖和讀寫鎖和悲觀鎖等鎖。

      4、生產者消費者模型,其中,在保證容器滿了,生產者停下來,消費者消費,是通過條件變量或者信號量可以實現。

      第四部分

      1、了解BS和CS架構模式,IP和端口,網絡模型,協議(看計算機網絡的書籍)。

      2、掌握ISO七層網絡模型和TCP/IP四層網絡模型(TCP/IP協議的書籍)

      3、字節序,IP操作函數,sockaddr數據結構,掌握系統的API的使用,會問到字節序定義(UNIX網絡編程的書籍)

      4、TCP實現服務器和客戶端通信  三次握手,滑動窗口,四次揮手,通信并發,狀態轉換,半關閉,端口復用,說概念,不涉及具體代碼

      5、IO多路轉接-select、poll、epoll(服務器開發和后臺開發80%會問這個問題)

      6、面試不常問,簡單了解 UDP通信,廣播,組播,本地套接字

       

      Linux網絡編程(四)

      (最重要的章節)

      網絡結構模式

      c/s和b/s模式,掌握各自的定義和優缺點

       

       

       

       

       

      MAC地址、IP地址、端口

      AMC地址

       

       MAC地址是網卡上的唯一標識。

      IP地址(重要)

       

       IP地址

       

       IP地址是32位的二進制數。

      IP地址編址方式

       

       

       

       

       

       

       

       

       子網掩碼

       

       

       

       端口

       

       端口相當于讀寫緩沖區,端口號相當于進程的編號,通過端口號找到進程。

      一個應用程序可以有多個端口,比如QQ可以有通話的端口、視頻的端口、聊天打字的端口等。

       

      網絡模型

      OSI模型(七層模型)

       

       

       

       CP/IP四層模型

       

       

       

       

       

       協議

       

       UDP協議

       

       TCP協議

       

       

       

       IP協議

       

       

       

       以太網幀協議

       

       ARP協議

       

       封裝

       

       分用

       

       

       

       

       

       網絡通信的過程

       

       

      問:網絡通信剛開始封裝的時候是如何知道目地主機的MAC地址和IP地址的啊?

      答:ip地址查詢dns服務器獲得,然后通過ip找到子網,子網進行一個廣播找到指定目的主機,目的主機返回mac地址,后面就知道mac地址了。

      目的端MAC地址是通過ARP協議獲得。

       

      ARP請求封裝

       ARP報文長度28字節

       

      socket介紹

       

       

       

       

       

       

       字節序

       

       

       

       

       

       字節序轉換函數

       

       

       

       socket地址

       

       通用socket地址

       

       

       

       專用socket地址

       

       

       

       

       

       

       

       

      IP地址轉換(字符串ip-整數 ,主機、網絡字節序的轉換)

       

       

       

       

      TCP通信流程

       

       

       

       

       

       

       

       套接字函數

       1 #include <sys/types.h>
       2 #include <sys/socket.h>
       3 #include <arpa/inet.h> // 包含了這個頭文件,上面兩個就可以省略
       4 int socket(int domain, int type, int protocol);
       5 - 功能:創建一個套接字
       6 - 參數:
       7 - domain: 協議族
       8 AF_INET : ipv4
       9 AF_INET6 : ipv6
      10 AF_UNIX, AF_LOCAL : 本地套接字通信(進程間通信)
      11 - type: 通信過程中使用的協議類型
      12 SOCK_STREAM : 流式協議
      13 SOCK_DGRAM : 報式協議
      14 - protocol : 具體的一個協議。一般寫0
      15 - SOCK_STREAM : 流式協議默認使用 TCP
      16 - SOCK_DGRAM : 報式協議默認使用 UDP
      17 - 返回值:
      18 - 成功:返回文件描述符,操作的就是內核緩沖區。
      19 - 失敗:-1
      20 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); // socket命
      21 22 - 功能:綁定,將fd 和本地的IP + 端口進行綁定
      23 - 參數:
      24 - sockfd : 通過socket函數得到的文件描述符
      25 - addr : 需要綁定的socket地址,這個地址封裝了ip和端口號的信息
      26 - addrlen : 第二個參數結構體占的內存大小
      27 int listen(int sockfd, int backlog); // /proc/sys/net/core/somaxconn
      28 - 功能:監聽這個socket上的連接
      29 - 參數:
      30 - sockfd : 通過socket()函數得到的文件描述符
      31 - backlog : 未連接的和已經連接的和的最大值, 5
      32 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
      33 - 功能:接收客戶端連接,默認是一個阻塞的函數,阻塞等待客戶端連接
      34 - 參數:
      35 - sockfd : 用于監聽的文件描述符
      36 - addr : 傳出參數,記錄了連接成功后客戶端的地址信息(ip,port)
      37 - addrlen : 指定第二個參數的對應的內存大小
      38 - 返回值:
      39 - 成功 :用于通信的文件描述符
      40 - -1 : 失敗
      41 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
      42 - 功能: 客戶端連接服務器
      43 - 參數:
      44 - sockfd : 用于通信的文件描述符
      45 - addr : 客戶端要連接的服務器的地址信息
      46 - addrlen : 第二個參數的內存大小
      47 - 返回值:成功 0, 失敗 -1
      48 ssize_t write(int fd, const void *buf, size_t count); // 寫數據
      49 ssize_t read(int fd, void *buf, size_t count); // 讀數據

       

      TCP通信實現(服務器端)

       1 // TCP 通信的服務器端
       2 
       3 #include <stdio.h>
       4 #include <arpa/inet.h>
       5 #include <unistd.h>
       6 #include <string.h>
       7 #include <stdlib.h>
       8 
       9 int main() {
      10 
      11     // 1.創建socket(用于監聽的套接字)
      12     int lfd = socket(AF_INET, SOCK_STREAM, 0);
      13 
      14     if(lfd == -1) {
      15         perror("socket");
      16         exit(-1);
      17     }
      18 
      19     // 2.綁定
      20     struct sockaddr_in saddr;
      21     saddr.sin_family = AF_INET;
      22     // inet_pton(AF_INET, "192.168.193.128", saddr.sin_addr.s_addr);
      23     saddr.sin_addr.s_addr = INADDR_ANY;  // 0.0.0.0
      24     saddr.sin_port = htons(9999);
      25     int ret = bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));
      26 
      27     if(ret == -1) {
      28         perror("bind");
      29         exit(-1);
      30     }
      31 
      32     // 3.監聽
      33     ret = listen(lfd, 8);
      34     if(ret == -1) {
      35         perror("listen");
      36         exit(-1);
      37     }
      38 
      39     // 4.接收客戶端連接
      40     struct sockaddr_in clientaddr;
      41     int len = sizeof(clientaddr);
      42     int cfd = accept(lfd, (struct sockaddr *)&clientaddr, &len);
      43     
      44     if(cfd == -1) {
      45         perror("accept");
      46         exit(-1);
      47     }
      48 
      49     // 輸出客戶端的信息
      50     char clientIP[16];
      51     inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, clientIP, sizeof(clientIP));
      52     unsigned short clientPort = ntohs(clientaddr.sin_port);
      53     printf("client ip is %s, port is %d\n", clientIP, clientPort);
      54 
      55     // 5.通信
      56     char recvBuf[1024] = {0};
      57     while(1) {
      58         
      59         // 獲取客戶端的數據
      60         int num = read(cfd, recvBuf, sizeof(recvBuf));
      61         if(num == -1) {
      62             perror("read");
      63             exit(-1);
      64         } else if(num > 0) {
      65             printf("recv client data : %s\n", recvBuf);
      66         } else if(num == 0) {
      67             // 表示客戶端斷開連接
      68             printf("clinet closed...");
      69             break;
      70         }
      71 
      72         char * data = "hello,i am server";
      73         // 給客戶端發送數據
      74         write(cfd, data, strlen(data));
      75     }
      76    
      77     // 關閉文件描述符
      78     close(cfd);
      79     close(lfd);
      80 
      81     return 0;
      82 }

       

      TCP通信實現(客戶端)

      代碼

       1 // TCP通信的客戶端
       2 
       3 #include <stdio.h>
       4 #include <arpa/inet.h>
       5 #include <unistd.h>
       6 #include <string.h>
       7 #include <stdlib.h>
       8 
       9 int main() {
      10 
      11     // 1.創建套接字
      12     int fd = socket(AF_INET, SOCK_STREAM, 0);
      13     if(fd == -1) {
      14         perror("socket");
      15         exit(-1);
      16     }
      17 
      18     // 2.連接服務器端
      19     struct sockaddr_in serveraddr;
      20     serveraddr.sin_family = AF_INET;
      21     inet_pton(AF_INET, "192.168.193.128", &serveraddr.sin_addr.s_addr);
      22     serveraddr.sin_port = htons(9999);
      23     int ret = connect(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
      24 
      25     if(ret == -1) {
      26         perror("connect");
      27         exit(-1);
      28     }
      29 
      30     
      31     // 3. 通信
      32     char recvBuf[1024] = {0};
      33     while(1) {
      34 
      35         char * data = "hello,i am client";
      36         // 給客戶端發送數據
      37         write(fd, data , strlen(data));
      38 
      39         sleep(1);
      40         
      41         int len = read(fd, recvBuf, sizeof(recvBuf));
      42         if(len == -1) {
      43             perror("read");
      44             exit(-1);
      45         } else if(len > 0) {
      46             printf("recv server data : %s\n", recvBuf);
      47         } else if(len == 0) {
      48             // 表示服務器端斷開連接
      49             printf("server closed...");
      50             break;
      51         }
      52 
      53     }
      54 
      55     // 關閉連接
      56     close(fd);
      57 
      58     return 0;
      59 }

       

      課后練習:回射服務器

       

      TCP三次握手

       

       

      ack:確認

      syn:連接

      fin:斷開連接

       

       

       

       

       

       

       

       

       

      TCP滑動窗口

       

       

      注意:窗口理解為緩沖區的大小,當然,窗口不是緩沖區。

       

       

       

       

       

       

       

      TCP四次揮手

       

       

       

      TCP 通信并發

      TCP 狀態轉換

       

       

       

       

       

       

      從程序的角度,可以使用API來控制實現半連接狀態:

       

       

       

       

       代碼

      client.c

       1 // TCP通信的客戶端
       2 #include <stdio.h>
       3 #include <arpa/inet.h>
       4 #include <unistd.h>
       5 #include <string.h>
       6 #include <stdlib.h>
       7 
       8 int main() {
       9 
      10     // 1.創建套接字
      11     int fd = socket(AF_INET, SOCK_STREAM, 0);
      12     if(fd == -1) {
      13         perror("socket");
      14         exit(-1);
      15     }
      16 
      17     // 2.連接服務器端
      18     struct sockaddr_in serveraddr;
      19     serveraddr.sin_family = AF_INET;
      20     inet_pton(AF_INET, "192.168.193.128", &serveraddr.sin_addr.s_addr);
      21     serveraddr.sin_port = htons(9999);
      22     int ret = connect(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
      23 
      24     if(ret == -1) {
      25         perror("connect");
      26         exit(-1);
      27     }
      28     
      29     // 3. 通信
      30     char recvBuf[1024];
      31     int i = 0;
      32     while(1) {
      33         
      34         sprintf(recvBuf, "data : %d\n", i++);
      35         
      36         // 給服務器端發送數據
      37         write(fd, recvBuf, strlen(recvBuf)+1);
      38 
      39         int len = read(fd, recvBuf, sizeof(recvBuf));
      40         if(len == -1) {
      41             perror("read");
      42             exit(-1);
      43         } else if(len > 0) {
      44             printf("recv server : %s\n", recvBuf);
      45         } else if(len == 0) {
      46             // 表示服務器端斷開連接
      47             printf("server closed...");
      48             break;
      49         }
      50 
      51         sleep(1);
      52     }
      53 
      54     // 關閉連接
      55     close(fd);
      56 
      57     return 0;
      58 }

      server.c

        1 #include <stdio.h>
        2 #include <arpa/inet.h>
        3 #include <unistd.h>
        4 #include <stdlib.h>
        5 #include <string.h>
        6 #include <signal.h>
        7 #include <wait.h>
        8 #include <errno.h>
        9 
       10 void recyleChild(int arg) {
       11     while(1) {
       12         int ret = waitpid(-1, NULL, WNOHANG);
       13         if(ret == -1) {
       14             // 所有的子進程都回收了
       15             break;
       16         }else if(ret == 0) {
       17             // 還有子進程活著
       18             break;
       19         } else if(ret > 0){
       20             // 被回收了
       21             printf("子進程 %d 被回收了\n", ret);
       22         }
       23     }
       24 }
       25 
       26 int main() {
       27 
       28     struct sigaction act;
       29     act.sa_flags = 0;
       30     sigemptyset(&act.sa_mask);
       31     act.sa_handler = recyleChild;
       32     // 注冊信號捕捉
       33     sigaction(SIGCHLD, &act, NULL);
       34     
       35 
       36     // 創建socket
       37     int lfd = socket(PF_INET, SOCK_STREAM, 0);
       38     if(lfd == -1){
       39         perror("socket");
       40         exit(-1);
       41     }
       42 
       43     struct sockaddr_in saddr;
       44     saddr.sin_family = AF_INET;
       45     saddr.sin_port = htons(9999);
       46     saddr.sin_addr.s_addr = INADDR_ANY;
       47 
       48     // 綁定
       49     int ret = bind(lfd,(struct sockaddr *)&saddr, sizeof(saddr));
       50     if(ret == -1) {
       51         perror("bind");
       52         exit(-1);
       53     }
       54 
       55     // 監聽
       56     ret = listen(lfd, 128);
       57     if(ret == -1) {
       58         perror("listen");
       59         exit(-1);
       60     }
       61 
       62     // 不斷循環等待客戶端連接
       63     while(1) {
       64 
       65         struct sockaddr_in cliaddr;
       66         int len = sizeof(cliaddr);
       67         // 接受連接
       68         int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &len);
       69         if(cfd == -1) {
       70             if(errno == EINTR) {
       71                 continue;
       72             }
       73             perror("accept");
       74             exit(-1);
       75         }
       76 
       77         // 每一個連接進來,創建一個子進程跟客戶端通信
       78         pid_t pid = fork();
       79         if(pid == 0) {
       80             // 子進程
       81             // 獲取客戶端的信息
       82             char cliIp[16];
       83             inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, cliIp, sizeof(cliIp));
       84             unsigned short cliPort = ntohs(cliaddr.sin_port);
       85             printf("client ip is : %s, prot is %d\n", cliIp, cliPort);
       86 
       87             // 接收客戶端發來的數據
       88             char recvBuf[1024];
       89             while(1) {
       90                 int len = read(cfd, &recvBuf, sizeof(recvBuf));
       91 
       92                 if(len == -1) {
       93                     perror("read");
       94                     exit(-1);
       95                 }else if(len > 0) {
       96                     printf("recv client : %s\n", recvBuf);
       97                 } else if(len == 0) {
       98                     printf("client closed....\n");
       99                     break;
      100                 }
      101                 write(cfd, recvBuf, strlen(recvBuf) + 1);
      102             }
      103             close(cfd);
      104             exit(0);    // 退出當前子進程
      105         }
      106 
      107     }
      108     close(lfd);
      109     return 0;
      110 }

       

      多線程實現并發服務器

        1 #include <stdio.h>
        2 #include <arpa/inet.h>
        3 #include <unistd.h>
        4 #include <stdlib.h>
        5 #include <string.h>
        6 #include <pthread.h>
        7 
        8 struct sockInfo {
        9     int fd; // 通信的文件描述符
       10     struct sockaddr_in addr;
       11     pthread_t tid;  // 線程號
       12 };
       13 
       14 struct sockInfo sockinfos[128];
       15 
       16 void * working(void * arg) {
       17     // 子線程和客戶端通信   cfd 客戶端的信息 線程號
       18     // 獲取客戶端的信息
       19     struct sockInfo * pinfo = (struct sockInfo *)arg;
       20 
       21     char cliIp[16];
       22     inet_ntop(AF_INET, &pinfo->addr.sin_addr.s_addr, cliIp, sizeof(cliIp));
       23     unsigned short cliPort = ntohs(pinfo->addr.sin_port);
       24     printf("client ip is : %s, prot is %d\n", cliIp, cliPort);
       25 
       26     // 接收客戶端發來的數據
       27     char recvBuf[1024];
       28     while(1) {
       29         int len = read(pinfo->fd, &recvBuf, sizeof(recvBuf));
       30 
       31         if(len == -1) {
       32             perror("read");
       33             exit(-1);
       34         }else if(len > 0) {
       35             printf("recv client : %s\n", recvBuf);
       36         } else if(len == 0) {
       37             printf("client closed....\n");
       38             break;
       39         }
       40         write(pinfo->fd, recvBuf, strlen(recvBuf) + 1);
       41     }
       42     close(pinfo->fd);
       43     return NULL;
       44 }
       45 
       46 int main() {
       47 
       48     // 創建socket
       49     int lfd = socket(PF_INET, SOCK_STREAM, 0);
       50     if(lfd == -1){
       51         perror("socket");
       52         exit(-1);
       53     }
       54 
       55     struct sockaddr_in saddr;
       56     saddr.sin_family = AF_INET;
       57     saddr.sin_port = htons(9999);
       58     saddr.sin_addr.s_addr = INADDR_ANY;
       59 
       60     // 綁定
       61     int ret = bind(lfd,(struct sockaddr *)&saddr, sizeof(saddr));
       62     if(ret == -1) {
       63         perror("bind");
       64         exit(-1);
       65     }
       66 
       67     // 監聽
       68     ret = listen(lfd, 128);
       69     if(ret == -1) {
       70         perror("listen");
       71         exit(-1);
       72     }
       73 
       74     // 初始化數據
       75     int max = sizeof(sockinfos) / sizeof(sockinfos[0]);
       76     for(int i = 0; i < max; i++) {
       77         bzero(&sockinfos[i], sizeof(sockinfos[i]));
       78         sockinfos[i].fd = -1;
       79         sockinfos[i].tid = -1;
       80     }
       81 
       82     // 循環等待客戶端連接,一旦一個客戶端連接進來,就創建一個子線程進行通信
       83     while(1) {
       84 
       85         struct sockaddr_in cliaddr;
       86         int len = sizeof(cliaddr);
       87         // 接受連接
       88         int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &len);
       89 
       90         struct sockInfo * pinfo;
       91         for(int i = 0; i < max; i++) {
       92             // 從這個數組中找到一個可以用的sockInfo元素
       93             if(sockinfos[i].fd == -1) {
       94                 pinfo = &sockinfos[i];
       95                 break;
       96             }
       97             if(i == max - 1) {
       98                 sleep(1);
       99                 i--;
      100             }
      101         }
      102 
      103         pinfo->fd = cfd;
      104         memcpy(&pinfo->addr, &cliaddr, len);
      105 
      106         // 創建子線程
      107         pthread_create(&pinfo->tid, NULL, working, pinfo);
      108 
      109         pthread_detach(pinfo->tid);
      110     }
      111 
      112     close(lfd);
      113     return 0;
      114 }

       

       半關閉

       

       

       

       

      端口復用

       

       

       

       

      代碼

      client.c

       1 #include <stdio.h>
       2 #include <arpa/inet.h>
       3 #include <stdlib.h>
       4 #include <unistd.h>
       5 #include <string.h>
       6 
       7 int main() {
       8 
       9     // 創建socket
      10     int fd = socket(PF_INET, SOCK_STREAM, 0);
      11     if(fd == -1) {
      12         perror("socket");
      13         return -1;
      14     }
      15 
      16     struct sockaddr_in seraddr;
      17     inet_pton(AF_INET, "127.0.0.1", &seraddr.sin_addr.s_addr);
      18     seraddr.sin_family = AF_INET;
      19     seraddr.sin_port = htons(9999);
      20 
      21     // 連接服務器
      22     int ret = connect(fd, (struct sockaddr *)&seraddr, sizeof(seraddr));
      23 
      24     if(ret == -1){
      25         perror("connect");
      26         return -1;
      27     }
      28 
      29     while(1) {
      30         char sendBuf[1024] = {0};
      31         fgets(sendBuf, sizeof(sendBuf), stdin);
      32 
      33         write(fd, sendBuf, strlen(sendBuf) + 1);
      34 
      35         // 接收
      36         int len = read(fd, sendBuf, sizeof(sendBuf));
      37         if(len == -1) {
      38             perror("read");
      39             return -1;
      40         }else if(len > 0) {
      41             printf("read buf = %s\n", sendBuf);
      42         } else {
      43             printf("服務器已經斷開連接...\n");
      44             break;
      45         }
      46     }
      47 
      48     close(fd);
      49 
      50     return 0;
      51 }

       

      server.c

       1 #include <stdio.h>
       2 #include <ctype.h>
       3 #include <arpa/inet.h>
       4 #include <unistd.h>
       5 #include <stdlib.h>
       6 #include <string.h>
       7 
       8 int main(int argc, char *argv[]) {
       9 
      10     // 創建socket
      11     int lfd = socket(PF_INET, SOCK_STREAM, 0);
      12 
      13     if(lfd == -1) {
      14         perror("socket");
      15         return -1;
      16     }
      17 
      18     struct sockaddr_in saddr;
      19     saddr.sin_family = AF_INET;
      20     saddr.sin_addr.s_addr = INADDR_ANY;
      21     saddr.sin_port = htons(9999);
      22     
      23     //int optval = 1;
      24     //setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
      25 
      26     int optval = 1;
      27     setsockopt(lfd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
      28 
      29     // 綁定
      30     int ret = bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));
      31     if(ret == -1) {
      32         perror("bind");
      33         return -1;
      34     }
      35 
      36     // 監聽
      37     ret = listen(lfd, 8);
      38     if(ret == -1) {
      39         perror("listen");
      40         return -1;
      41     }
      42 
      43     // 接收客戶端連接
      44     struct sockaddr_in cliaddr;
      45     socklen_t len = sizeof(cliaddr);
      46     int cfd = accept(lfd, (struct sockaddr *)&cliaddr, &len);
      47     if(cfd == -1) {
      48         perror("accpet");
      49         return -1;
      50     }
      51 
      52     // 獲取客戶端信息
      53     char cliIp[16];
      54     inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, cliIp, sizeof(cliIp));
      55     unsigned short cliPort = ntohs(cliaddr.sin_port);
      56 
      57     // 輸出客戶端的信息
      58     printf("client's ip is %s, and port is %d\n", cliIp, cliPort );
      59 
      60     // 接收客戶端發來的數據
      61     char recvBuf[1024] = {0};
      62     while(1) {
      63         int len = recv(cfd, recvBuf, sizeof(recvBuf), 0);
      64         if(len == -1) {
      65             perror("recv");
      66             return -1;
      67         } else if(len == 0) {
      68             printf("客戶端已經斷開連接...\n");
      69             break;
      70         } else if(len > 0) {
      71             printf("read buf = %s\n", recvBuf);
      72         }
      73 
      74         // 小寫轉大寫
      75         for(int i = 0; i < len; ++i) {
      76             recvBuf[i] = toupper(recvBuf[i]);
      77         }
      78 
      79         printf("after buf = %s\n", recvBuf);
      80 
      81         // 大寫字符串發給客戶端
      82         ret = send(cfd, recvBuf, strlen(recvBuf) + 1, 0);
      83         if(ret == -1) {
      84             perror("send");
      85             return -1;
      86         }
      87     }
      88     
      89     close(cfd);
      90     close(lfd);
      91 
      92     return 0;
      93 }

       

      I/O多路復用(I/O多路轉接)

      I/O 多路復用使得程序能同時監聽多個文件描述符,能夠提高程序的性能,Linux 下實現 I/O 多路復用的系統調用主要有 select、poll 和 epoll。

       

      1、阻塞方式:

       

       

       

       

      2、非阻塞的方式:

       

       

       

       

       

      3、IO多路復用方式:

       

       

       

       

      select API介紹

       

       

       代碼

       1 // sizeof(fd_set) = 128 1024
       2 #include <sys/time.h>
       3 #include <sys/types.h>
       4 #include <unistd.h>
       5 #include <sys/select.h>
       6 int select(int nfds, fd_set *readfds, fd_set *writefds,
       7 fd_set *exceptfds, struct timeval *timeout);
       8     - 參數:
       9     - nfds : 委托內核檢測的最大文件描述符的值 + 1
      10     - readfds : 要檢測的文件描述符的讀的集合,委托內核檢測哪些文件描述符的讀的屬性
      11         - 一般檢測讀操作
      12         - 對應的是對方發送過來的數據,因為讀是被動的接收數據,檢測的就是讀緩沖
      13 14         - 是一個傳入傳出參數
      15     - writefds : 要檢測的文件描述符的寫的集合,委托內核檢測哪些文件描述符的寫的屬性
      16         - 委托內核檢測寫緩沖區是不是還可以寫數據(不滿的就可以寫)
      17     - exceptfds : 檢測發生異常的文件描述符的集合
      18     - timeout : 設置的超時時間
      19         struct timeval {
      20         long tv_sec; /* seconds */
      21         long tv_usec; /* microseconds */
      22         };
      23         - NULL : 永久阻塞,直到檢測到了文件描述符有變化
      24         - tv_sec = 0 tv_usec = 0, 不阻塞
      25         - tv_sec > 0 tv_usec > 0, 阻塞對應的時間
      26     - 返回值 :
      27         - -1 : 失敗
      28         - >0(n) : 檢測的集合中有n個文件描述符發生了變化
      29 // 將參數文件描述符fd對應的標志位設置為0
      30 void FD_CLR(int fd, fd_set *set);
      31 // 判斷fd對應的標志位是0還是1, 返回值 : fd對應的標志位的值,0,返回0, 1,返回1
      32 int FD_ISSET(int fd, fd_set *set);
      33 // 將參數文件描述符fd 對應的標志位,設置為1
      34 void FD_SET(int fd, fd_set *set);
      35 // fd_set一共有1024 bit, 全部初始化為0
      36 void FD_ZERO(fd_set *set);

       

       

       

      select代碼編寫

       代碼

      client.c

       1 #include <stdio.h>
       2 #include <arpa/inet.h>
       3 #include <stdlib.h>
       4 #include <unistd.h>
       5 #include <string.h>
       6 
       7 int main() {
       8 
       9     // 創建socket
      10     int fd = socket(PF_INET, SOCK_STREAM, 0);
      11     if(fd == -1) {
      12         perror("socket");
      13         return -1;
      14     }
      15 
      16     struct sockaddr_in seraddr;
      17     inet_pton(AF_INET, "127.0.0.1", &seraddr.sin_addr.s_addr);
      18     seraddr.sin_family = AF_INET;
      19     seraddr.sin_port = htons(9999);
      20 
      21     // 連接服務器
      22     int ret = connect(fd, (struct sockaddr *)&seraddr, sizeof(seraddr));
      23 
      24     if(ret == -1){
      25         perror("connect");
      26         return -1;
      27     }
      28 
      29     int num = 0;
      30     while(1) {
      31         char sendBuf[1024] = {0};
      32         sprintf(sendBuf, "send data %d", num++);
      33         write(fd, sendBuf, strlen(sendBuf) + 1);
      34 
      35         // 接收
      36         int len = read(fd, sendBuf, sizeof(sendBuf));
      37         if(len == -1) {
      38             perror("read");
      39             return -1;
      40         }else if(len > 0) {
      41             printf("read buf = %s\n", sendBuf);
      42         } else {
      43             printf("服務器已經斷開連接...\n");
      44             break;
      45         }
      46         // sleep(1);
      47         usleep(1000);
      48     }
      49 
      50     close(fd);
      51 
      52     return 0;
      53 }

       

      select.c

       1 #include <stdio.h>
       2 #include <arpa/inet.h>
       3 #include <unistd.h>
       4 #include <stdlib.h>
       5 #include <string.h>
       6 #include <sys/select.h>
       7 
       8 int main() {
       9 
      10     // 創建socket
      11     int lfd = socket(PF_INET, SOCK_STREAM, 0);
      12     struct sockaddr_in saddr;
      13     saddr.sin_port = htons(9999);
      14     saddr.sin_family = AF_INET;
      15     saddr.sin_addr.s_addr = INADDR_ANY;
      16 
      17     // 綁定
      18     bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));
      19 
      20     // 監聽
      21     listen(lfd, 8);
      22 
      23     // 創建一個fd_set的集合,存放的是需要檢測的文件描述符
      24     fd_set rdset, tmp;
      25     FD_ZERO(&rdset);
      26     FD_SET(lfd, &rdset);
      27     int maxfd = lfd;
      28 
      29     while(1) {
      30 
      31         tmp = rdset;
      32 
      33         // 調用select系統函數,讓內核幫檢測哪些文件描述符有數據
      34         int ret = select(maxfd + 1, &tmp, NULL, NULL, NULL);
      35         if(ret == -1) {
      36             perror("select");
      37             exit(-1);
      38         } else if(ret == 0) {
      39             continue;
      40         } else if(ret > 0) {
      41             // 說明檢測到了有文件描述符的對應的緩沖區的數據發生了改變
      42             if(FD_ISSET(lfd, &tmp)) {
      43                 // 表示有新的客戶端連接進來了
      44                 struct sockaddr_in cliaddr;
      45                 int len = sizeof(cliaddr);
      46                 int cfd = accept(lfd, (struct sockaddr *)&cliaddr, &len);
      47 
      48                 // 將新的文件描述符加入到集合中
      49                 FD_SET(cfd, &rdset);
      50 
      51                 // 更新最大的文件描述符
      52                 maxfd = maxfd > cfd ? maxfd : cfd;
      53             }
      54 
      55             for(int i = lfd + 1; i <= maxfd; i++) {
      56                 if(FD_ISSET(i, &tmp)) {
      57                     // 說明這個文件描述符對應的客戶端發來了數據
      58                     char buf[1024] = {0};
      59                     int len = read(i, buf, sizeof(buf));
      60                     if(len == -1) {
      61                         perror("read");
      62                         exit(-1);
      63                     } else if(len == 0) {
      64                         printf("client closed...\n");
      65                         close(i);
      66                         FD_CLR(i, &rdset);
      67                     } else if(len > 0) {
      68                         printf("read buf = %s\n", buf);
      69                         write(i, buf, strlen(buf) + 1);
      70                     }
      71                 }
      72             }
      73 
      74         }
      75 
      76     }
      77     close(lfd);
      78     return 0;
      79 }

       

      poll API介紹及代碼編寫

       

       

       

       代碼

      client.c

       1 #include <stdio.h>
       2 #include <arpa/inet.h>
       3 #include <stdlib.h>
       4 #include <unistd.h>
       5 #include <string.h>
       6 
       7 int main() {
       8 
       9     // 創建socket
      10     int fd = socket(PF_INET, SOCK_STREAM, 0);
      11     if(fd == -1) {
      12         perror("socket");
      13         return -1;
      14     }
      15 
      16     struct sockaddr_in seraddr;
      17     inet_pton(AF_INET, "127.0.0.1", &seraddr.sin_addr.s_addr);
      18     seraddr.sin_family = AF_INET;
      19     seraddr.sin_port = htons(9999);
      20 
      21     // 連接服務器
      22     int ret = connect(fd, (struct sockaddr *)&seraddr, sizeof(seraddr));
      23 
      24     if(ret == -1){
      25         perror("connect");
      26         return -1;
      27     }
      28 
      29     int num = 0;
      30     while(1) {
      31         char sendBuf[1024] = {0};
      32         sprintf(sendBuf, "send data %d", num++);
      33         write(fd, sendBuf, strlen(sendBuf) + 1);
      34 
      35         // 接收
      36         int len = read(fd, sendBuf, sizeof(sendBuf));
      37         if(len == -1) {
      38             perror("read");
      39             return -1;
      40         }else if(len > 0) {
      41             printf("read buf = %s\n", sendBuf);
      42         } else {
      43             printf("服務器已經斷開連接...\n");
      44             break;
      45         }
      46         // sleep(1);
      47         usleep(1000);
      48     }
      49 
      50     close(fd);
      51 
      52     return 0;
      53 }

       

      poll.c

       1 #include <stdio.h>
       2 #include <arpa/inet.h>
       3 #include <unistd.h>
       4 #include <stdlib.h>
       5 #include <string.h>
       6 #include <poll.h>
       7 
       8 
       9 int main() {
      10 
      11     // 創建socket
      12     int lfd = socket(PF_INET, SOCK_STREAM, 0);
      13     struct sockaddr_in saddr;
      14     saddr.sin_port = htons(9999);
      15     saddr.sin_family = AF_INET;
      16     saddr.sin_addr.s_addr = INADDR_ANY;
      17 
      18     // 綁定
      19     bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));
      20 
      21     // 監聽
      22     listen(lfd, 8);
      23 
      24     // 初始化檢測的文件描述符數組
      25     struct pollfd fds[1024];
      26     for(int i = 0; i < 1024; i++) {
      27         fds[i].fd = -1;
      28         fds[i].events = POLLIN;
      29     }
      30     fds[0].fd = lfd;
      31     int nfds = 0;
      32 
      33     while(1) {
      34 
      35         // 調用poll系統函數,讓內核幫檢測哪些文件描述符有數據
      36         int ret = poll(fds, nfds + 1, -1);
      37         if(ret == -1) {
      38             perror("poll");
      39             exit(-1);
      40         } else if(ret == 0) {
      41             continue;
      42         } else if(ret > 0) {
      43             // 說明檢測到了有文件描述符的對應的緩沖區的數據發生了改變
      44             if(fds[0].revents & POLLIN) {
      45                 // 表示有新的客戶端連接進來了
      46                 struct sockaddr_in cliaddr;
      47                 int len = sizeof(cliaddr);
      48                 int cfd = accept(lfd, (struct sockaddr *)&cliaddr, &len);
      49 
      50                 // 將新的文件描述符加入到集合中
      51                 for(int i = 1; i < 1024; i++) {
      52                     if(fds[i].fd == -1) {
      53                         fds[i].fd = cfd;
      54                         fds[i].events = POLLIN;
      55                         break;
      56                     }
      57                 }
      58 
      59                 // 更新最大的文件描述符的索引
      60                 nfds = nfds > cfd ? nfds : cfd;
      61             }
      62 
      63             for(int i = 1; i <= nfds; i++) {
      64                 if(fds[i].revents & POLLIN) {
      65                     // 說明這個文件描述符對應的客戶端發來了數據
      66                     char buf[1024] = {0};
      67                     int len = read(fds[i].fd, buf, sizeof(buf));
      68                     if(len == -1) {
      69                         perror("read");
      70                         exit(-1);
      71                     } else if(len == 0) {
      72                         printf("client closed...\n");
      73                         close(fds[i].fd);
      74                         fds[i].fd = -1;
      75                     } else if(len > 0) {
      76                         printf("read buf = %s\n", buf);
      77                         write(fds[i].fd, buf, strlen(buf) + 1);
      78                     }
      79                 }
      80             }
      81 
      82         }
      83 
      84     }
      85     close(lfd);
      86     return 0;
      87 }

       

       

      epoll

       

       

       

       

       

       

       

       

       

      epoll代碼編寫

      client.c

       1 #include <stdio.h>
       2 #include <arpa/inet.h>
       3 #include <stdlib.h>
       4 #include <unistd.h>
       5 #include <string.h>
       6 
       7 int main() {
       8 
       9     // 創建socket
      10     int fd = socket(PF_INET, SOCK_STREAM, 0);
      11     if(fd == -1) {
      12         perror("socket");
      13         return -1;
      14     }
      15 
      16     struct sockaddr_in seraddr;
      17     inet_pton(AF_INET, "127.0.0.1", &seraddr.sin_addr.s_addr);
      18     seraddr.sin_family = AF_INET;
      19     seraddr.sin_port = htons(9999);
      20 
      21     // 連接服務器
      22     int ret = connect(fd, (struct sockaddr *)&seraddr, sizeof(seraddr));
      23 
      24     if(ret == -1){
      25         perror("connect");
      26         return -1;
      27     }
      28 
      29     int num = 0;
      30     while(1) {
      31         char sendBuf[1024] = {0};
      32         sprintf(sendBuf, "send data %d", num++);
      33         write(fd, sendBuf, strlen(sendBuf) + 1);
      34 
      35         // 接收
      36         int len = read(fd, sendBuf, sizeof(sendBuf));
      37         if(len == -1) {
      38             perror("read");
      39             return -1;
      40         }else if(len > 0) {
      41             printf("read buf = %s\n", sendBuf);
      42         } else {
      43             printf("服務器已經斷開連接...\n");
      44             break;
      45         }
      46         // sleep(1);
      47         usleep(1000);
      48     }
      49 
      50     close(fd);
      51 
      52     return 0;
      53 }

       

      epoll.c

       1 #include <stdio.h>
       2 #include <arpa/inet.h>
       3 #include <unistd.h>
       4 #include <stdlib.h>
       5 #include <string.h>
       6 #include <sys/epoll.h>
       7 
       8 int main() {
       9 
      10     // 創建socket
      11     int lfd = socket(PF_INET, SOCK_STREAM, 0);
      12     struct sockaddr_in saddr;
      13     saddr.sin_port = htons(9999);
      14     saddr.sin_family = AF_INET;
      15     saddr.sin_addr.s_addr = INADDR_ANY;
      16 
      17     // 綁定
      18     bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));
      19 
      20     // 監聽
      21     listen(lfd, 8);
      22 
      23     // 調用epoll_create()創建一個epoll實例
      24     int epfd = epoll_create(100);
      25 
      26     // 將監聽的文件描述符相關的檢測信息添加到epoll實例中
      27     struct epoll_event epev;
      28     epev.events = EPOLLIN;
      29     epev.data.fd = lfd;
      30     epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &epev);
      31 
      32     struct epoll_event epevs[1024];
      33 
      34     while(1) {
      35 
      36         int ret = epoll_wait(epfd, epevs, 1024, -1);
      37         if(ret == -1) {
      38             perror("epoll_wait");
      39             exit(-1);
      40         }
      41 
      42         printf("ret = %d\n", ret);
      43 
      44         for(int i = 0; i < ret; i++) {
      45 
      46             int curfd = epevs[i].data.fd;
      47 
      48             if(curfd == lfd) {
      49                 // 監聽的文件描述符有數據達到,有客戶端連接
      50                 struct sockaddr_in cliaddr;
      51                 int len = sizeof(cliaddr);
      52                 int cfd = accept(lfd, (struct sockaddr *)&cliaddr, &len);
      53 
      54                 epev.events = EPOLLIN;
      55                 epev.data.fd = cfd;
      56                 epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &epev);
      57             } else {
      58                 if(epevs[i].events & EPOLLOUT) {
      59                     continue;
      60                 }   
      61                 // 有數據到達,需要通信
      62                 char buf[1024] = {0};
      63                 int len = read(curfd, buf, sizeof(buf));
      64                 if(len == -1) {
      65                     perror("read");
      66                     exit(-1);
      67                 } else if(len == 0) {
      68                     printf("client closed...\n");
      69                     epoll_ctl(epfd, EPOLL_CTL_DEL, curfd, NULL);
      70                     close(curfd);
      71                 } else if(len > 0) {
      72                     printf("read buf = %s\n", buf);
      73                     write(curfd, buf, strlen(buf) + 1);
      74                 }
      75 
      76             }
      77 
      78         }
      79     }
      80 
      81     close(lfd);
      82     close(epfd);
      83     return 0;
      84 }

        

      epoll的兩種工作模式

       

       

       

      epoll_et.c

       1 #include <stdio.h>
       2 #include <arpa/inet.h>
       3 #include <unistd.h>
       4 #include <stdlib.h>
       5 #include <string.h>
       6 #include <sys/epoll.h>
       7 #include <fcntl.h>
       8 #include <errno.h>
       9 
      10 int main() {
      11 
      12     // 創建socket
      13     int lfd = socket(PF_INET, SOCK_STREAM, 0);
      14     struct sockaddr_in saddr;
      15     saddr.sin_port = htons(9999);
      16     saddr.sin_family = AF_INET;
      17     saddr.sin_addr.s_addr = INADDR_ANY;
      18 
      19     // 綁定
      20     bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));
      21 
      22     // 監聽
      23     listen(lfd, 8);
      24 
      25     // 調用epoll_create()創建一個epoll實例
      26     int epfd = epoll_create(100);
      27 
      28     // 將監聽的文件描述符相關的檢測信息添加到epoll實例中
      29     struct epoll_event epev;
      30     epev.events = EPOLLIN;
      31     epev.data.fd = lfd;
      32     epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &epev);
      33 
      34     struct epoll_event epevs[1024];
      35 
      36     while(1) {
      37 
      38         int ret = epoll_wait(epfd, epevs, 1024, -1);
      39         if(ret == -1) {
      40             perror("epoll_wait");
      41             exit(-1);
      42         }
      43 
      44         printf("ret = %d\n", ret);
      45 
      46         for(int i = 0; i < ret; i++) {
      47 
      48             int curfd = epevs[i].data.fd;
      49 
      50             if(curfd == lfd) {
      51                 // 監聽的文件描述符有數據達到,有客戶端連接
      52                 struct sockaddr_in cliaddr;
      53                 int len = sizeof(cliaddr);
      54                 int cfd = accept(lfd, (struct sockaddr *)&cliaddr, &len);
      55 
      56                 // 設置cfd屬性非阻塞
      57                 int flag = fcntl(cfd, F_GETFL);
      58                 flag | O_NONBLOCK;
      59                 fcntl(cfd, F_SETFL, flag);
      60 
      61                 epev.events = EPOLLIN | EPOLLET;    // 設置邊沿觸發
      62                 epev.data.fd = cfd;
      63                 epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &epev);
      64             } else {
      65                 if(epevs[i].events & EPOLLOUT) {
      66                     continue;
      67                 }  
      68 
      69                 // 循環讀取出所有數據
      70                 char buf[5];
      71                 int len = 0;
      72                 while( (len = read(curfd, buf, sizeof(buf))) > 0) {
      73                     // 打印數據
      74                     // printf("recv data : %s\n", buf);
      75                     write(STDOUT_FILENO, buf, len);
      76                     write(curfd, buf, len);
      77                 }
      78                 if(len == 0) {
      79                     printf("client closed....");
      80                 }else if(len == -1) {
      81                     if(errno == EAGAIN) {
      82                         printf("data over.....");
      83                     }else {
      84                         perror("read");
      85                         exit(-1);
      86                     }
      87                     
      88                 }
      89 
      90             }
      91 
      92         }
      93     }
      94 
      95     close(lfd);
      96     close(epfd);
      97     return 0;
      98 }

       

      epoll_lt.c

       1 #include <stdio.h>
       2 #include <arpa/inet.h>
       3 #include <unistd.h>
       4 #include <stdlib.h>
       5 #include <string.h>
       6 #include <sys/epoll.h>
       7 
       8 int main() {
       9 
      10     // 創建socket
      11     int lfd = socket(PF_INET, SOCK_STREAM, 0);
      12     struct sockaddr_in saddr;
      13     saddr.sin_port = htons(9999);
      14     saddr.sin_family = AF_INET;
      15     saddr.sin_addr.s_addr = INADDR_ANY;
      16 
      17     // 綁定
      18     bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));
      19 
      20     // 監聽
      21     listen(lfd, 8);
      22 
      23     // 調用epoll_create()創建一個epoll實例
      24     int epfd = epoll_create(100);
      25 
      26     // 將監聽的文件描述符相關的檢測信息添加到epoll實例中
      27     struct epoll_event epev;
      28     epev.events = EPOLLIN;
      29     epev.data.fd = lfd;
      30     epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &epev);
      31 
      32     struct epoll_event epevs[1024];
      33 
      34     while(1) {
      35 
      36         int ret = epoll_wait(epfd, epevs, 1024, -1);
      37         if(ret == -1) {
      38             perror("epoll_wait");
      39             exit(-1);
      40         }
      41 
      42         printf("ret = %d\n", ret);
      43 
      44         for(int i = 0; i < ret; i++) {
      45 
      46             int curfd = epevs[i].data.fd;
      47 
      48             if(curfd == lfd) {
      49                 // 監聽的文件描述符有數據達到,有客戶端連接
      50                 struct sockaddr_in cliaddr;
      51                 int len = sizeof(cliaddr);
      52                 int cfd = accept(lfd, (struct sockaddr *)&cliaddr, &len);
      53 
      54                 epev.events = EPOLLIN;
      55                 epev.data.fd = cfd;
      56                 epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &epev);
      57             } else {
      58                 if(epevs[i].events & EPOLLOUT) {
      59                     continue;
      60                 }   
      61                 // 有數據到達,需要通信
      62                 char buf[5] = {0};
      63                 int len = read(curfd, buf, sizeof(buf));
      64                 if(len == -1) {
      65                     perror("read");
      66                     exit(-1);
      67                 } else if(len == 0) {
      68                     printf("client closed...\n");
      69                     epoll_ctl(epfd, EPOLL_CTL_DEL, curfd, NULL);
      70                     close(curfd);
      71                 } else if(len > 0) {
      72                     printf("read buf = %s\n", buf);
      73                     write(curfd, buf, strlen(buf) + 1);
      74                 }
      75 
      76             }
      77 
      78         }
      79     }
      80 
      81     close(lfd);
      82     close(epfd);
      83     return 0;
      84 }

       

       

      UDP通信

       

       

       

       

       1 #include <stdio.h>
       2 #include <stdlib.h>
       3 #include <unistd.h>
       4 #include <string.h>
       5 #include <arpa/inet.h>
       6 
       7 int main() {
       8 
       9     // 1.創建一個通信的socket
      10     int fd = socket(PF_INET, SOCK_DGRAM, 0);
      11     
      12     if(fd == -1) {
      13         perror("socket");
      14         exit(-1);
      15     }   
      16 
      17     struct sockaddr_in addr;
      18     addr.sin_family = AF_INET;
      19     addr.sin_port = htons(9999);
      20     addr.sin_addr.s_addr = INADDR_ANY;
      21 
      22     // 2.綁定
      23     int ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
      24     if(ret == -1) {
      25         perror("bind");
      26         exit(-1);
      27     }
      28 
      29     // 3.通信
      30     while(1) {
      31         char recvbuf[128];
      32         char ipbuf[16];
      33 
      34         struct sockaddr_in cliaddr;
      35         int len = sizeof(cliaddr);
      36 
      37         // 接收數據
      38         int num = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&cliaddr, &len);
      39 
      40         printf("client IP : %s, Port : %d\n", 
      41             inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, ipbuf, sizeof(ipbuf)),
      42             ntohs(cliaddr.sin_port));
      43 
      44         printf("client say : %s\n", recvbuf);
      45 
      46         // 發送數據
      47         sendto(fd, recvbuf, strlen(recvbuf) + 1, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
      48 
      49     }
      50 
      51     close(fd);
      52     return 0;
      53 }

       

      廣播

       

       

       

      bro_client.c

       1 #include <stdio.h>
       2 #include <stdlib.h>
       3 #include <unistd.h>
       4 #include <string.h>
       5 #include <arpa/inet.h>
       6 
       7 int main() {
       8 
       9     // 1.創建一個通信的socket
      10     int fd = socket(PF_INET, SOCK_DGRAM, 0);
      11     if(fd == -1) {
      12         perror("socket");
      13         exit(-1);
      14     }   
      15 
      16     struct in_addr in;
      17 
      18     // 2.客戶端綁定本地的IP和端口
      19     struct sockaddr_in addr;
      20     addr.sin_family = AF_INET;
      21     addr.sin_port = htons(9999);
      22     addr.sin_addr.s_addr = INADDR_ANY;
      23 
      24     int ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
      25     if(ret == -1) {
      26         perror("bind");
      27         exit(-1);
      28     }
      29 
      30     // 3.通信
      31     while(1) {
      32         
      33         char buf[128];
      34         // 接收數據
      35         int num = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
      36         printf("server say : %s\n", buf);
      37 
      38     }
      39 
      40     close(fd);
      41     return 0;
      42 }

       

       

      bro_server.c

       1 #include <stdio.h>
       2 #include <stdlib.h>
       3 #include <unistd.h>
       4 #include <string.h>
       5 #include <arpa/inet.h>
       6 
       7 int main() {
       8 
       9     // 1.創建一個通信的socket
      10     int fd = socket(PF_INET, SOCK_DGRAM, 0);
      11     if(fd == -1) {
      12         perror("socket");
      13         exit(-1);
      14     }   
      15 
      16     // 2.設置廣播屬性
      17     int op = 1;
      18     setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &op, sizeof(op));
      19     
      20     // 3.創建一個廣播的地址
      21     struct sockaddr_in cliaddr;
      22     cliaddr.sin_family = AF_INET;
      23     cliaddr.sin_port = htons(9999);
      24     inet_pton(AF_INET, "192.168.193.255", &cliaddr.sin_addr.s_addr);
      25 
      26     // 3.通信
      27     int num = 0;
      28     while(1) {
      29        
      30         char sendBuf[128];
      31         sprintf(sendBuf, "hello, client....%d\n", num++);
      32         // 發送數據
      33         sendto(fd, sendBuf, strlen(sendBuf) + 1, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
      34         printf("廣播的數據:%s\n", sendBuf);
      35         sleep(1);
      36     }
      37 
      38     close(fd);
      39     return 0;
      40 }

      組播(多播)

       

       

       

       

       multi_client.c

       1 #include <stdio.h>
       2 #include <stdlib.h>
       3 #include <unistd.h>
       4 #include <string.h>
       5 #include <arpa/inet.h>
       6 
       7 int main() {
       8 
       9     // 1.創建一個通信的socket
      10     int fd = socket(PF_INET, SOCK_DGRAM, 0);
      11     if(fd == -1) {
      12         perror("socket");
      13         exit(-1);
      14     }   
      15 
      16     struct in_addr in;
      17     // 2.客戶端綁定本地的IP和端口
      18     struct sockaddr_in addr;
      19     addr.sin_family = AF_INET;
      20     addr.sin_port = htons(9999);
      21     addr.sin_addr.s_addr = INADDR_ANY;
      22 
      23     int ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
      24     if(ret == -1) {
      25         perror("bind");
      26         exit(-1);
      27     }
      28 
      29     struct ip_mreq op;
      30     inet_pton(AF_INET, "239.0.0.10", &op.imr_multiaddr.s_addr);
      31     op.imr_interface.s_addr = INADDR_ANY;
      32 
      33     // 加入到多播組
      34     setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &op, sizeof(op));
      35 
      36     // 3.通信
      37     while(1) {
      38         
      39         char buf[128];
      40         // 接收數據
      41         int num = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
      42         printf("server say : %s\n", buf);
      43 
      44     }
      45 
      46     close(fd);
      47     return 0;
      48 }

      multi_server.c

       1 #include <stdio.h>
       2 #include <stdlib.h>
       3 #include <unistd.h>
       4 #include <string.h>
       5 #include <arpa/inet.h>
       6 
       7 int main() {
       8 
       9     // 1.創建一個通信的socket
      10     int fd = socket(PF_INET, SOCK_DGRAM, 0);
      11     if(fd == -1) {
      12         perror("socket");
      13         exit(-1);
      14     }   
      15 
      16     // 2.設置多播的屬性,設置外出接口
      17     struct in_addr imr_multiaddr;
      18     // 初始化多播地址
      19     inet_pton(AF_INET, "239.0.0.10", &imr_multiaddr.s_addr);
      20     setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &imr_multiaddr, sizeof(imr_multiaddr));
      21     
      22     // 3.初始化客戶端的地址信息
      23     struct sockaddr_in cliaddr;
      24     cliaddr.sin_family = AF_INET;
      25     cliaddr.sin_port = htons(9999);
      26     inet_pton(AF_INET, "239.0.0.10", &cliaddr.sin_addr.s_addr);
      27 
      28     // 3.通信
      29     int num = 0;
      30     while(1) {
      31        
      32         char sendBuf[128];
      33         sprintf(sendBuf, "hello, client....%d\n", num++);
      34         // 發送數據
      35         sendto(fd, sendBuf, strlen(sendBuf) + 1, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
      36         printf("組播的數據:%s\n", sendBuf);
      37         sleep(1);
      38     }
      39 
      40     close(fd);
      41     return 0;
      42 }

       

       

      本地套接字通信

       

       

       ipc_client.c

       1 #include <stdio.h>
       2 #include <string.h>
       3 #include <unistd.h>
       4 #include <stdlib.h>
       5 #include <arpa/inet.h>
       6 #include <sys/un.h>
       7 
       8 int main() {
       9 
      10     unlink("client.sock");
      11 
      12     // 1.創建套接字
      13     int cfd = socket(AF_LOCAL, SOCK_STREAM, 0);
      14     if(cfd == -1) {
      15         perror("socket");
      16         exit(-1);
      17     }
      18 
      19     // 2.綁定本地套接字文件
      20     struct sockaddr_un addr;
      21     addr.sun_family = AF_LOCAL;
      22     strcpy(addr.sun_path, "client.sock");
      23     int ret = bind(cfd, (struct sockaddr *)&addr, sizeof(addr));
      24     if(ret == -1) {
      25         perror("bind");
      26         exit(-1);
      27     }
      28 
      29     // 3.連接服務器
      30     struct sockaddr_un seraddr;
      31     seraddr.sun_family = AF_LOCAL;
      32     strcpy(seraddr.sun_path, "server.sock");
      33     ret = connect(cfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
      34     if(ret == -1) {
      35         perror("connect");
      36         exit(-1);
      37     }
      38 
      39     // 4.通信
      40     int num = 0;
      41     while(1) {
      42 
      43         // 發送數據
      44         char buf[128];
      45         sprintf(buf, "hello, i am client %d\n", num++);
      46         send(cfd, buf, strlen(buf) + 1, 0);
      47         printf("client say : %s\n", buf);
      48 
      49         // 接收數據
      50         int len = recv(cfd, buf, sizeof(buf), 0);
      51 
      52         if(len == -1) {
      53             perror("recv");
      54             exit(-1);
      55         } else if(len == 0) {
      56             printf("server closed....\n");
      57             break;
      58         } else if(len > 0) {
      59             printf("server say : %s\n", buf);
      60         }
      61 
      62         sleep(1);
      63 
      64     }
      65 
      66     close(cfd);
      67     return 0;
      68 }

      ipc_server.c

       1 #include <stdio.h>
       2 #include <string.h>
       3 #include <unistd.h>
       4 #include <stdlib.h>
       5 #include <arpa/inet.h>
       6 #include <sys/un.h>
       7 
       8 int main() {
       9 
      10     unlink("server.sock");
      11 
      12     // 1.創建監聽的套接字
      13     int lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
      14     if(lfd == -1) {
      15         perror("socket");
      16         exit(-1);
      17     }
      18 
      19     // 2.綁定本地套接字文件
      20     struct sockaddr_un addr;
      21     addr.sun_family = AF_LOCAL;
      22     strcpy(addr.sun_path, "server.sock");
      23     int ret = bind(lfd, (struct sockaddr *)&addr, sizeof(addr));
      24     if(ret == -1) {
      25         perror("bind");
      26         exit(-1);
      27     }
      28 
      29     // 3.監聽
      30     ret = listen(lfd, 100);
      31     if(ret == -1) {
      32         perror("listen");
      33         exit(-1);
      34     }
      35 
      36     // 4.等待客戶端連接
      37     struct sockaddr_un cliaddr;
      38     int len = sizeof(cliaddr);
      39     int cfd = accept(lfd, (struct sockaddr *)&cliaddr, &len);
      40     if(cfd == -1) {
      41         perror("accept");
      42         exit(-1);
      43     }
      44 
      45     printf("client socket filename: %s\n", cliaddr.sun_path);
      46 
      47     // 5.通信
      48     while(1) {
      49 
      50         char buf[128];
      51         int len = recv(cfd, buf, sizeof(buf), 0);
      52 
      53         if(len == -1) {
      54             perror("recv");
      55             exit(-1);
      56         } else if(len == 0) {
      57             printf("client closed....\n");
      58             break;
      59         } else if(len > 0) {
      60             printf("client say : %s\n", buf);
      61             send(cfd, buf, len, 0);
      62         }
      63 
      64     }
      65 
      66     close(cfd);
      67     close(lfd);
      68 
      69     return 0;
      70 }

       

      posted @ 2022-02-28 22:06  白雪兒  Views(173)  Comments(0)    收藏  舉報
      主站蜘蛛池模板: 久久精品国产亚洲av麻豆小说| 顶级欧美熟妇xx| 女人腿张开让男人桶爽| 国产午夜精品久久精品电影| 亚洲理论在线A中文字幕| 无码免费中文字幕视频| 中国国产免费毛卡片| 久久亚洲精品成人av秋霞| 男女性高爱潮免费网站| 十八禁日本一区二区三区| 精品日韩精品国产另类专区| 米奇影院888奇米色99在线| 男女激情一区二区三区| 亚洲精品一区二区18禁| 一区二区三区鲁丝不卡| 乱女乱妇熟女熟妇综合网| 最新午夜男女福利片视频| 亚洲成人精品一区二区中| 在线观看AV永久免费| 中文字幕国产精品资源| 国产亚洲精品在av| 亚洲精品无码成人A片九色播放| 亚洲精品国产电影| 天堂va欧美ⅴa亚洲va在线| 精品偷自拍另类精品在线| 成人特黄特色毛片免费看| 亚洲色最新高清AV网站| 国产精品熟女一区二区三区| 亚洲av无码专区在线厂| 日韩有码中文在线观看| 蜜桃av无码免费看永久| 丰满人妻一区二区三区高清精品| 91中文字幕一区在线| 国产精品综合一区二区三区| 成人看的污污超级黄网站免费| 成人无遮挡裸免费视频在线观看| 亚洲天堂男人影院| 在线看无码的免费网站| 饥渴的熟妇张开腿呻吟视频| 四虎影视www在线播放| 高清在线一区二区三区视频|