【Linux C编程】第十八章 高并发服务器(一)

举报
Yuchuan 发表于 2021/05/12 16:46:56 2021/05/12
【摘要】 高并发服务器一

f高并发服务器

一、多进程并发服务器

    1. 实现示意图

    2. 使用多进程并发服务器时要考虑以下几点:

  • 父进程最大文件描述个数(父进程中需要close关闭accept返回的新文件描述符)
  • 系统内创建进程个数(与内存大小相关)
  • 进程创建过多是否降低整体服务性能(进程调度)

    3. 使用多进程的方式, 解决服务器处理多连接的问题:

    (1)共享

  • 读时共享, 写时复制
  • 文件描述符
  • 内存映射区 -- mmap

    (2)父进程 的角色是什么?

     等待接受客户端连接 -- accept

     有链接:

  • 创建一个子进程 fork()
  • 将通信的文件描述符关闭

    (3)子进程的角色是什么?

      1)通信

  • 使用accept返回值 - fd

      2)关掉监听的文件描述符

  • 浪费资源

    (4)创建的进程的个数有限制吗?

  • 受硬件限制
  • 文件描述符默认也是有上限的1024

    (5)子进程资源回收

      1)wait/waitpid

     2)使用信号回收

  • 信号捕捉

           signal

           sigaction - 推荐

  • 捕捉信号: SIGCHLD

    代码实现:

wrap.c

1 #include <stdlib.h>
  2 #include <stdio.h>
  3 #include <unistd.h>
  4 #include <errno.h>
  5 #include <sys/socket.h>
  6 
  7 void perr_exit(const char *s)
  8 {
  9     perror(s);
 10     exit(-1);
 11 }
 12 
 13 int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
 14 {
 15     int n;
 16 
 17 again:
 18     if ((n = accept(fd, sa, salenptr)) < 0) {
 19         if ((errno == ECONNABORTED) || (errno == EINTR))
 20             goto again;
 21         else
 22             perr_exit("accept error");
 23     }
 24     return n;
 25 }
 26 
 27 int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
 28 {
 29     int n;
 30 
 31     if ((n = bind(fd, sa, salen)) < 0)
 32         perr_exit("bind error");
 33 
 34     return n;
 35 }
 36 
 37 int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
 38 {
 39     int n;
 40 
 41     if ((n = connect(fd, sa, salen)) < 0)
 42         perr_exit("connect error");
 43 
 44     return n;
 45 }
 46 
 47 int Listen(int fd, int backlog)
 48 {
 49     int n;
 50 
 51     if ((n = listen(fd, backlog)) < 0)
 52         perr_exit("listen error");
 53 
 54     return n;
 55 }
 56 
 57 int Socket(int family, int type, int protocol)
 58 {
 59     int n;
 60 
 61     if ((n = socket(family, type, protocol)) < 0)
 62         perr_exit("socket error");
 63 
 64     return n;
 65 }
 66 
 67 ssize_t Read(int fd, void *ptr, size_t nbytes)
 68 {
 69     ssize_t n;
 70 
 71 again:
 72     if ( (n = read(fd, ptr, nbytes)) == -1) {
 73         if (errno == EINTR)
 74             goto again;
 75         else
 76             return -1;
 77     }
 78     return n;
 79 }
 80 
 81 ssize_t Write(int fd, const void *ptr, size_t nbytes)
 82 {
 83     ssize_t n;
 84 
 85 again:
 86     if ( (n = write(fd, ptr, nbytes)) == -1) {
 87         if (errno == EINTR)
 88             goto again;
 89         else
 90             return -1;
 91     }
 92     return n;
 93 }
 94 
 95 int Close(int fd)
 96 {
 97     int n;
 98     if ((n = close(fd)) == -1)
 99         perr_exit("close error");
100 
101     return n;
102 }
103 
104 /*参三: 应该读取的字节数*/
105 ssize_t Readn(int fd, void *vptr, size_t n)
106 {
107     size_t  nleft;              //usigned int 剩余未读取的字节数
108     ssize_t nread;              //int 实际读到的字节数
109     char   *ptr;
110 
111     ptr = vptr;
112     nleft = n;
113 
114     while (nleft > 0) {
115         if ((nread = read(fd, ptr, nleft)) < 0) {
116             if (errno == EINTR)
117                 nread = 0;
118             else
119                 return -1;
120         } else if (nread == 0)
121             break;
122 
123         nleft -= nread;
124         ptr += nread;
125     }
126     return n - nleft;
127 }
128 
129 ssize_t Writen(int fd, const void *vptr, size_t n)
130 {
131     size_t nleft;
132     ssize_t nwritten;
133     const char *ptr;
134 
135     ptr = vptr;
136     nleft = n;
137     while (nleft > 0) {
138         if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
139             if (nwritten < 0 && errno == EINTR)
140                 nwritten = 0;
141             else
142                 return -1;
143         }
144 
145         nleft -= nwritten;
146         ptr += nwritten;
147     }
148     return n;
149 }
150 
151 static ssize_t my_read(int fd, char *ptr)
152 {
153     static int read_cnt;
154     static char *read_ptr;
155     static char read_buf[100];
156 
157     if (read_cnt <= 0) {
158 again:
159         if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
160             if (errno == EINTR)
161                 goto again;
162             return -1;
163         } else if (read_cnt == 0)
164             return 0;
165         read_ptr = read_buf;
166     }
167     read_cnt--;
168     *ptr = *read_ptr++;
169 
170     return 1;
171 }
172 
173 ssize_t Readline(int fd, void *vptr, size_t maxlen)
174 {
175     ssize_t n, rc;
176     char    c, *ptr;
177 
178     ptr = vptr;
179     for (n = 1; n < maxlen; n++) {
180         if ( (rc = my_read(fd, &c)) == 1) {
181             *ptr++ = c;
182             if (c  == '\n')
183                 break;
184         } else if (rc == 0) {
185             *ptr = 0;
186             return n - 1;
187         } else
188             return -1;
189     }
190     *ptr  = 0;
191 
192     return n;
193 }

wrap.h

1 #ifndef __WRAP_H_
 2 #define __WRAP_H_
 3 
 4 void perr_exit(const char *s);
 5 int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
 6 int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
 7 int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
 8 int Listen(int fd, int backlog);
 9 int Socket(int family, int type, int protocol);
10 ssize_t Read(int fd, void *ptr, size_t nbytes);
11 ssize_t Write(int fd, const void *ptr, size_t nbytes);
12 int Close(int fd);
13 ssize_t Readn(int fd, void *vptr, size_t n);
14 ssize_t Writen(int fd, const void *vptr, size_t n);
15 ssize_t my_read(int fd, char *ptr);
16 ssize_t Readline(int fd, void *vptr, size_t maxlen);
17 
18 #endif

server.c

1 #include <stdio.h>
  2 #include <string.h>
  3 #include <netinet/in.h>
  4 #include <arpa/inet.h>
  5 #include <signal.h>
  6 #include <sys/wait.h>
  7 #include <ctype.h>
  8 #include <unistd.h>
  9 
 10 #include "wrap.h"
 11 
 12 #define MAXLINE 8192
 13 #define SERV_PORT 8000
 14 
 15 void do_sigchild(int num)
 16 {
 17     while (waitpid(0, NULL, WNOHANG) > 0);
 18 }
 19 
 20 int main(void)
 21 {
 22     struct sockaddr_in servaddr, cliaddr;
 23     socklen_t cliaddr_len;
 24     int listenfd, connfd;
 25     char buf[MAXLINE];
 26     char str[INET_ADDRSTRLEN];
 27     int i, n;
 28     pid_t pid;
 29 
 30     //临时屏蔽sigchld信号
 31     sigset_t myset;
 32     sigemptyset(&myset);
 33     sigaddset(&myset, SIGCHLD);
 34     // 自定义信号集 -》 内核阻塞信号集
 35     sigprocmask(SIG_BLOCK, &myset, NULL);
 36 
 37 
 38     listenfd = Socket(AF_INET, SOCK_STREAM, 0);
 39 
 40     int opt = 1;
 41     // 设置端口复用
 42     setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
 43 
 44     bzero(&servaddr, sizeof(servaddr));
 45     servaddr.sin_family = AF_INET;
 46     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 47     servaddr.sin_port = htons(SERV_PORT);
 48 
 49     Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
 50 
 51     Listen(listenfd, 20);
 52 
 53     printf("Accepting connections ...\n");
 54     while (1) 
 55     {
 56         cliaddr_len = sizeof(cliaddr);
 57         connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
 58 
 59         // 有新的连接则创建一个进程
 60         pid = fork();
 61         if (pid == 0) 
 62         {
 63             Close(listenfd);
 64             while (1) 
 65             {
 66                 n = Read(connfd, buf, MAXLINE);
 67                 if (n == 0) 
 68                 {
 69                     printf("the other side has been closed.\n");
 70                     break;
 71                 }
 72                 printf("received from %s at PORT %d\n",
 73                         inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
 74                         ntohs(cliaddr.sin_port));
 75 
 76                 for (i = 0; i < n; i++)
 77                     buf[i] = toupper(buf[i]);
 78 
 79                 Write(STDOUT_FILENO, buf, n);
 80                 Write(connfd, buf, n);
 81             }
 82             Close(connfd);
 83             return 0;
 84         } 
 85         else if (pid > 0) 
 86         {
 87             struct sigaction act;
 88             act.sa_flags = 0;
 89             act.sa_handler = do_sigchild;
 90             sigemptyset(&act.sa_mask);
 91             sigaction(SIGCHLD, &act, NULL);
 92             // 解除对sigchld信号的屏蔽
 93             sigprocmask(SIG_UNBLOCK, &myset, NULL);
 94 
 95             Close(connfd);
 96         }  
 97         else
 98         {
 99             perr_exit("fork");
100         }
101     }
102     return 0;
103 }

client.c

1 /* client.c */
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <netinet/in.h>
 6 #include <arpa/inet.h>
 7 
 8 #include "wrap.h"
 9 
10 #define MAXLINE 8192
11 #define SERV_PORT 8000
12 
13 int main(int argc, char *argv[])
14 {
15     struct sockaddr_in servaddr;
16     char buf[MAXLINE];
17     int sockfd, n;
18 
19     sockfd = Socket(AF_INET, SOCK_STREAM, 0);
20 
21     bzero(&servaddr, sizeof(servaddr));
22     servaddr.sin_family = AF_INET;
23     inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
24     servaddr.sin_port = htons(SERV_PORT);
25 
26     Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
27 
28     while (fgets(buf, MAXLINE, stdin) != NULL) 
29     {
30         Write(sockfd, buf, strlen(buf));
31         n = Read(sockfd, buf, MAXLINE);
32         if (n == 0) 
33         {
34             printf("the other side has been closed.\n");
35             break;
36         }
37         else
38             Write(STDOUT_FILENO, buf, n);
39     }
40 
41     Close(sockfd);
42 
43     return 0;
44 }

makefile

1 src = $(wildcard *.c)
 2 obj = $(patsubst %.c, %.o, $(src))
 3 
 4 all: server client
 5 
 6 server: server.o wrap.o
 7     gcc server.o wrap.o -o server -Wall
 8 client: client.o wrap.o
 9     gcc client.o wrap.o -o client -Wall
10 
11 %.o:%.c
12     gcc -c $< -Wall
13 
14 .PHONY: clean all
15 clean: 
16     -rm -rf server client $(obj)

二、多线程并发服务器

    1. 实现示意图

    2. 使用线程模型开发服务器时需考虑以下问题:

  • 调整进程内最大文件描述符上限
  • 线程如有共享数据,考虑线程同步
  • 服务于客户端线程退出时,退出处理。(退出值,分离态)
  • 系统负载,随着链接客户端增加,导致其它线程不能及时得到CPU

    3. 线程共享:

  • 全局数据区
  • 堆区
  • 一块有效内存的地址

    代码实现:

wrap.c

1 #include <stdlib.h>
  2 #include <stdio.h>
  3 #include <unistd.h>
  4 #include <errno.h>
  5 #include <sys/socket.h>
  6 
  7 void perr_exit(const char *s)
  8 {
  9     perror(s);
 10     exit(-1);
 11 }
 12 
 13 int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
 14 {
 15     int n;
 16 
 17 again:
 18     if ((n = accept(fd, sa, salenptr)) < 0) {
 19         if ((errno == ECONNABORTED) || (errno == EINTR))
 20             goto again;
 21         else
 22             perr_exit("accept error");
 23     }
 24     return n;
 25 }
 26 
 27 int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
 28 {
 29     int n;
 30 
 31     if ((n = bind(fd, sa, salen)) < 0)
 32         perr_exit("bind error");
 33 
 34     return n;
 35 }
 36 
 37 int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
 38 {
 39     int n;
 40 
 41     if ((n = connect(fd, sa, salen)) < 0)
 42         perr_exit("connect error");
 43 
 44     return n;
 45 }
 46 
 47 int Listen(int fd, int backlog)
 48 {
 49     int n;
 50 
 51     if ((n = listen(fd, backlog)) < 0)
 52         perr_exit("listen error");
 53 
 54     return n;
 55 }
 56 
 57 int Socket(int family, int type, int protocol)
 58 {
 59     int n;
 60 
 61     if ((n = socket(family, type, protocol)) < 0)
 62         perr_exit("socket error");
 63 
 64     return n;
 65 }
 66 
 67 ssize_t Read(int fd, void *ptr, size_t nbytes)
 68 {
 69     ssize_t n;
 70 
 71 again:
 72     if ( (n = read(fd, ptr, nbytes)) == -1) {
 73         if (errno == EINTR)
 74             goto again;
 75         else
 76             return -1;
 77     }
 78     return n;
 79 }
 80 
 81 ssize_t Write(int fd, const void *ptr, size_t nbytes)
 82 {
 83     ssize_t n;
 84 
 85 again:
 86     if ( (n = write(fd, ptr, nbytes)) == -1) {
 87         if (errno == EINTR)
 88             goto again;
 89         else
 90             return -1;
 91     }
 92     return n;
 93 }
 94 
 95 int Close(int fd)
 96 {
 97     int n;
 98     if ((n = close(fd)) == -1)
 99         perr_exit("close error");
100 
101     return n;
102 }
103 
104 /*参三: 应该读取的字节数*/
105 ssize_t Readn(int fd, void *vptr, size_t n)
106 {
107     size_t  nleft;              //usigned int 剩余未读取的字节数
108     ssize_t nread;              //int 实际读到的字节数
109     char   *ptr;
110 
111     ptr = vptr;
112     nleft = n;
113 
114     while (nleft > 0) {
115         if ((nread = read(fd, ptr, nleft)) < 0) {
116             if (errno == EINTR)
117                 nread = 0;
118             else
119                 return -1;
120         } else if (nread == 0)
121             break;
122 
123         nleft -= nread;
124         ptr += nread;
125     }
126     return n - nleft;
127 }
128 
129 ssize_t Writen(int fd, const void *vptr, size_t n)
130 {
131     size_t nleft;
132     ssize_t nwritten;
133     const char *ptr;
134 
135     ptr = vptr;
136     nleft = n;
137     while (nleft > 0) {
138         if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
139             if (nwritten < 0 && errno == EINTR)
140                 nwritten = 0;
141             else
142                 return -1;
143         }
144 
145         nleft -= nwritten;
146         ptr += nwritten;
147     }
148     return n;
149 }
150 
151 static ssize_t my_read(int fd, char *ptr)
152 {
153     static int read_cnt;
154     static char *read_ptr;
155     static char read_buf[100];
156 
157     if (read_cnt <= 0) {
158 again:
159         if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
160             if (errno == EINTR)
161                 goto again;
162             return -1;
163         } else if (read_cnt == 0)
164             return 0;
165         read_ptr = read_buf;
166     }
167     read_cnt--;
168     *ptr = *read_ptr++;
169 
170     return 1;
171 }
172 
173 ssize_t Readline(int fd, void *vptr, size_t maxlen)
174 {
175     ssize_t n, rc;
176     char    c, *ptr;
177 
178     ptr = vptr;
179     for (n = 1; n < maxlen; n++) {
180         if ( (rc = my_read(fd, &c)) == 1) {
181             *ptr++ = c;
182             if (c  == '\n')
183                 break;
184         } else if (rc == 0) {
185             *ptr = 0;
186             return n - 1;
187         } else
188             return -1;
189     }
190     *ptr  = 0;
191 
192     return n;
193 }

wrap.h

1 #ifndef __WRAP_H_
 2 #define __WRAP_H_
 3 
 4 void perr_exit(const char *s);
 5 int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
 6 int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
 7 int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
 8 int Listen(int fd, int backlog);
 9 int Socket(int family, int type, int protocol);
10 ssize_t Read(int fd, void *ptr, size_t nbytes);
11 ssize_t Write(int fd, const void *ptr, size_t nbytes);
12 int Close(int fd);
13 ssize_t Readn(int fd, void *vptr, size_t n);
14 ssize_t Writen(int fd, const void *vptr, size_t n);
15 ssize_t my_read(int fd, char *ptr);
16 ssize_t Readline(int fd, void *vptr, size_t maxlen);
17 
18 #endif

server.c

1 #include <stdio.h>
 2 #include <string.h>
 3 #include <arpa/inet.h>
 4 #include <pthread.h>
 5 #include <ctype.h>
 6 #include <unistd.h>
 7 #include <fcntl.h>
 8 
 9 #include "wrap.h"
10 
11 #define MAXLINE 8192
12 #define SERV_PORT 8000
13 
14 struct s_info 
15 {                     //定义一个结构体, 将地址结构跟cfd捆绑
16     struct sockaddr_in cliaddr;
17     int connfd;
18 };
19 
20 void *do_work(void *arg)
21 {
22     int n,i;
23     struct s_info *ts = (struct s_info*)arg;
24     char buf[MAXLINE];
25     char str[INET_ADDRSTRLEN];      //#define INET_ADDRSTRLEN 16  可用"[+d"查看
26 
27     while (1) 
28     {
29         n = Read(ts->connfd, buf, MAXLINE);                     //读客户端
30         if (n == 0) 
31         {
32             printf("the client %d closed...\n", ts->connfd);
33             break;                                              //跳出循环,关闭cfd
34         }
35         printf("received from %s at PORT %d\n",
36                 inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
37                 ntohs((*ts).cliaddr.sin_port));                 //打印客户端信息(IP/PORT)
38 
39         for (i = 0; i < n; i++) 
40         {
41             buf[i] = toupper(buf[i]);                           //小写-->大写
42         }
43 
44         Write(STDOUT_FILENO, buf, n);                           //写出至屏幕
45         Write(ts->connfd, buf, n);                              //回写给客户端
46     }
47     Close(ts->connfd);
48 
49     return NULL;
50 }
51 
52 int main(void)
53 {
54     struct sockaddr_in servaddr, cliaddr;
55     socklen_t cliaddr_len;
56     int listenfd, connfd;
57     pthread_t tid;
58     struct s_info ts[256];      //根据最大线程数创建结构体数组.
59     int i = 0;
60 
61     listenfd = Socket(AF_INET, SOCK_STREAM, 0);                     //创建一个socket, 得到lfd
62 
63     bzero(&servaddr, sizeof(servaddr));                             //地址结构清零
64     servaddr.sin_family = AF_INET;
65     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);                   //指定本地任意IP
66     servaddr.sin_port = htons(SERV_PORT);                           //指定端口号 8000
67 
68     Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); //绑定
69 
70     Listen(listenfd, 128);      //设置同一时刻链接服务器上限数
71 
72     printf("Accepting client connect ...\n");
73 
74     while (1) 
75     {
76         cliaddr_len = sizeof(cliaddr);
77         connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);   //阻塞监听客户端链接请求
78         ts[i].cliaddr = cliaddr;
79         ts[i].connfd = connfd;
80 
81         pthread_create(&tid, NULL, do_work, (void*)&ts[i]);
82         pthread_detach(tid);                                                    //子线程分离,防止僵线程产生.
83         i++;
84         if(i == 256)
85         {
86             break;
87         }
88     }
89 
90     return 0;
91 }

client.c

1 /* client.c */
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <netinet/in.h>
 6 #include <arpa/inet.h>
 7 #include "wrap.h"
 8 
 9 #define MAXLINE 80
10 #define SERV_PORT 8000
11 
12 int main(int argc, char *argv[])
13 {
14     struct sockaddr_in servaddr;
15     char buf[MAXLINE];
16     int sockfd, n;
17 
18     sockfd = Socket(AF_INET, SOCK_STREAM, 0);
19 
20     bzero(&servaddr, sizeof(servaddr));
21     servaddr.sin_family = AF_INET;
22     inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr.s_addr);
23     servaddr.sin_port = htons(SERV_PORT);
24 
25     Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
26 
27     while (fgets(buf, MAXLINE, stdin) != NULL) 
28     {
29         Write(sockfd, buf, strlen(buf));
30         n = Read(sockfd, buf, MAXLINE);
31         if (n == 0)
32             printf("the other side has been closed.\n");
33         else
34             Write(STDOUT_FILENO, buf, n);
35     }
36 
37     Close(sockfd);
38 
39     return 0;
40 }

makefile

1 src = $(wildcard *.c)
 2 obj = $(patsubst %.c, %.o, $(src))
 3 
 4 all: server client
 5 
 6 server: server.o wrap.o
 7     gcc server.o wrap.o -o server -Wall -lpthread
 8 client: client.o wrap.o
 9     gcc client.o wrap.o -o client -Wall -lpthread
10 
11 %.o:%.c
12     gcc -c $< -Wall 
13 
14 .PHONY: clean all
15 clean: 
16     -rm -rf server client $(obj)

三、多路I/O转接服务器

    1. IO多路转接技术概述

     多路IO转接服务器也叫做多任务IO服务器。该类服务器实现的主旨思想是,不再由应用程序自己监视客户端连接,取而代之由内核替应用程序监视文件。

     1)先构造一张有关文件描述符的列表, 将要监听的文件描述符添加到该表中
     2)然后调用一个函数,监听该表中的文件描述符,直到这些描述符表中的一个进行I/O操作时,该函数才返回。

  • 该函数为阻塞函数
  • 函数对文件描述符的检测操作是由内核完成的

     3)在返回时,它告诉进程有多少(哪些)描述符要进行I/O操作。

     IO操作方式:

     (1)阻塞等待

  • 优点:不占用cpu宝贵的时间片
  • 缺点:同一时刻只能处理一个操作, 效率低

     (2)非阻塞, 忙轮询

  • 优点: 提高了程序的执行效率
  • 缺点: 需要占用更多的cpu和系统资源

     一个任务:

     多个任务:

     解决方案:使用IO多路转接技术 select/poll/epoll

     第一种: select/poll

    注意:select 代收员比较懒, 她只会告诉你有几个快递到了,但是哪个快递,你需要挨个遍历一遍。

    第二种: epoll

    注意:epoll代收快递员很勤快, 她不仅会告诉你有几个快递到了, 还会告诉你是哪个快递公司的快递。

    主要使用的方法有三种:select/poll/epoll

     2. select

    (1)首先分析select的工作原理?

  • select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开的文件描述符个数并不能改变select监听文件个数。
  • 解决1024以下客户端时使用select是很合适的,但如果链接客户端过多,select采用的是轮询模型,会大大降低服务器响应效率,不应在select上投入更多精力。

     结合下面select函数的介绍及下面的伪代码用select实现一个server端有助于上面select工作流程的理解:

【Linux C编程】第十八章 高并发服务器(二)

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。