• 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 }
  • 相关阅读:
    FastApi下载文件
    测试平台系列(74) 测试计划定时执行初体验
    [CF895C]Square Subsets
    [bzoj2157/lgoj1505]旅游
    [luogu3674]小清新人渣的本愿
    关于Web前端 编程时流程控制中的流程控制图和 if 判断及九九乘法表
    关于流程控制语句中switch选择和各种循环
    SUSE Linux Enterprise Server 11 SP3安装详解(转)
    SVN代码管理
    安卓app开发服务器端开发
  • 原文地址:https://www.cnblogs.com/weixq351/p/15947859.html
Copyright © 2020-2023  润新知