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 }

浙公網安備 33010602011771號