几种并发服务器模型的实现


 

客户端使用select模型:

复制代码
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <errno.h>
  5 #include <sys/types.h>
  6 #include <sys/socket.h>
  7 #include <netinet/in.h>
  8 #include <arpa/inet.h>
  9 #include <sys/select.h>
 10 #include <signal.h>
 11 
 12 #define ERR_EXIT(m) \
 13     do { \
 14         perror(m);\
 15         exit(EXIT_FAILURE);\
 16     }while(0)
 17 
 18 static void do_client(int fd)
 19 {
 20     char recvbuf[MAXLINE + 1] = {0};
 21     char sendbuf[MAXLINE + 1] = {0};
 22 
 23     fd_set reade, ready;
 24     FD_ZERO(&reade);
 25     int fd_stdin = fileno(stdin);
 26     FD_SET(fd_stdin, &reade);
 27     FD_SET(fd, &reade);
 28     int fd_max = (fd_stdin > fd) ? fd_stdin : fd;
 29 
 30     int ret;
 31     while(1)
 32     {
 33         ready = reade;
 34         ret = select( fd_max+1, &ready, NULL, NULL, NULL);//轮询
 35         if(ret == -1)
 36         {
 37             if(errno == EINTR)
 38                 continue;
 39             ERR_EXIT("select");
 40         }else if(ret ==  0)
 41         {
 42             continue;
 43         }
 44 
 45         if(FD_ISSET(fd_stdin, &ready))
 46         {
 47             if(fgets(sendbuf, sizeof(sendbuf), stdin) == NULL)
 48             {
 49                 close(fd);
 50                break;
 51             }else
 52             {
 53                 if( -1 == write(fd, sendbuf, strlen(sendbuf)))
 54                     printf("write\n");
 55             }
 56         }
 57 
 58 
 59         if(FD_ISSET(fd, &ready))
 60         {
 61             int nread = read(fd, recvbuf, MAXLINE);
 62             if(nread < 0)
 63                 ERR_EXIT("read");
 64             if(nread == 0)//如果没接收到消息,打印关闭描述符,退出循环
 65             {
 66                 fprintf(stdout, "fd close\n");
 67                 break;
 68             }
 69             fprintf(stdout, "receive:%s", recvbuf);
 70         }
 71         memset(recvbuf, 0, sizeof recvbuf);
 72         memset(sendbuf, 0, sizeof sendbuf);
 73     }
 74 }
 75 void handle(int signum)
 76 {
 77 printf("sigpipe\n");
 78 }
 79 
 80 int main(int argc, const char *argv[])
 81 {
 82     signal(SIGPIPE, SIG_IGN);
 83     int fd = socket(AF_INET, SOCK_STREAM, 0);
 84     if(fd < 0)
 85         ERR_EXIT("socket");
 86 
 87     struct sockaddr_in cliaddr;
 88     cliaddr.sin_family = AF_INET;
 89     cliaddr.sin_port = htons(8888);
 90     cliaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
 91     socklen_t len = sizeof cliaddr;
 92 
 93     int ret ;
 94     if((ret = connect(fd, (struct sockaddr*)&cliaddr, len)) == -1)
 95     {
 96         close(fd);
 97         ERR_EXIT("connect");
 98     }
 99     do_client(fd);
100     close(fd);
101     return 0;
102 }
复制代码

 

 

1.并发多进程服务器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "rio.h"//封装了网络编程中的readn  writen   readline 3个函数
#include <signal.h>
 
#define ERR_EXIT(m) \
     do { \
         perror (m);\
         exit (EXIT_FAILURE);\
     } while (0)
 
static void do_service( int fd)
{
     rio_t rt;
     rio_init(&rt, fd);
     char recvbuf[1024] = {0};
     int ret;
     while (1)
     {
         memset (recvbuf, 0, sizeof recvbuf);
         ret = rio_readline(&rt, recvbuf, 1024);
         if (ret == 0)  
         {
             close(fd);
             exit (EXIT_SUCCESS);
         }
         rio_writen(fd, recvbuf, strlen (recvbuf)) ;
     }
}
 
void handle( int signum) //对SIGCHLD信号的处理函数
{
     while (waitpid(-1, NULL, WNOHANG) > 0);
     return ;
}
 
int listenf(); //封装了socket,bind,listen3个函数,返回需要监听的连接socket描述符
 
int main( int argc, const char *argv[])
{
     if ( signal (SIGPIPE, SIG_IGN) == SIG_ERR) //对客户端关闭导致的信号的处理
         ERR_EXIT( "signal_pipe" );
     if ( signal (SIGCHLD, handle) == SIG_ERR) //对子进程结束后资源的回收
         ERR_EXIT( "signal_chld" );
 
 
     int listenfd = listenf();
 
     struct sockaddr_in cliaddr;
     bzero(&cliaddr, sizeof (cliaddr));
     socklen_t cli_len = sizeof cliaddr;
     int clientfd;
     while (1)
     {
         clientfd = accept(listenfd, ( struct sockaddr*)&cliaddr, &cli_len);
         if (clientfd == -1) 
         {
             close(listenfd);
             ERR_EXIT( "accept" );
         }
         
         int pid;
         if ((pid = fork()) == -1)
         {
             ERR_EXIT( "fork" );
         } else if (pid == 0)
         {
             close(listenfd);
             do_service(clientfd);
             exit (EXIT_SUCCESS);
         }
         close(clientfd);
     }
     close(listenfd);
     return 0;
}
 
int listenf()
{
     int listenfd = socket(AF_INET, SOCK_STREAM, 0); //准备一个socketfd
     if (listenfd == -1 )
         ERR_EXIT( "socket" );
 
     int on = 1;
     if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) == -1) //setsockopt设置端口复用
     {
         close(listenfd);
         ERR_EXIT( "setsockopt" );
     }
 
     struct sockaddr_in seraddr;
     seraddr.sin_family = AF_INET;
     seraddr.sin_port = htons(8888);
     seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
     socklen_t len = sizeof (seraddr);
     if (bind(listenfd, ( struct sockaddr*)&seraddr, len) == -1) //监听socket端口,
     {
         close(listenfd);
         ERR_EXIT( "bind" );
     }
 
     if (listen(listenfd, 6) == -1)
     {
         close(listenfd);
         ERR_EXIT( "listen" );
     }
     return listenfd;
}

 2.多线程服务器模型:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "rio.h"
#include <signal.h>
#include <pthread.h>
 
#define ERR_EXIT(m) \
     do { \
         perror (m);\
         exit (EXIT_FAILURE);\
     } while (0)
 
static void do_service( int fd)
{
     rio_t rt;
     rio_init(&rt, fd);
     char recvbuf[1024] = {0};
     int ret;
     int rcnt = 0;
     while (1)
     {
         memset (recvbuf, 0, sizeof recvbuf);
         ret = rio_readline(&rt, recvbuf, 1024);
          if (ret == 0)
          {
          close(fd);
//         break;
           pthread_exit(NULL);
          }
          write(fd, recvbuf, strlen (recvbuf)) ;
     }
}
 
void handle( int signum)
{
     printf ( "hello\n" );
}
 
void *pthread_func( void *arg)
{
     pthread_detach(pthread_self());
     int *q = ( int *)arg;
    int p = *( int *)arg;
    free (q);
      do_service(p);
      close(p);
}
int listenf();
 
int main( int argc, const char *argv[])
{
     if ( signal (SIGPIPE, handle) == SIG_ERR)
         ERR_EXIT( "signal" );
     int listenfd = listenf();
 
     struct sockaddr_in cliaddr;
     bzero(&cliaddr, sizeof (cliaddr));
     socklen_t cli_len = sizeof cliaddr;
     int clientfd;
     while (1)
     {
     clientfd = accept(listenfd, ( struct sockaddr*)&cliaddr, &cli_len);
     if (clientfd == -1) 
     {
         close(listenfd);
         ERR_EXIT( "accept" );
     }
 
     pthread_t tid;
     int *p = ( int *) malloc ( sizeof ( int ));
    *p = clientfd;
     pthread_create(&tid, NULL, pthread_func, p);
     }
     close(listenfd);
     return 0;
}
 
int listenf()
{
     int listenfd = socket(AF_INET, SOCK_STREAM, 0); //准备一个socketfd
     if (listenfd == -1 )
         ERR_EXIT( "listen" );
 
     int on = 1;
     if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) == -1) //setsockopt设置端口复用
     {
         close(listenfd);
         ERR_EXIT( "setsockopt" );
     }
 
     struct sockaddr_in seraddr;
     seraddr.sin_family = AF_INET;
     seraddr.sin_port = htons(8888);
     seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
     socklen_t len = sizeof (seraddr);
     if (bind(listenfd, ( struct sockaddr*)&seraddr, len) == -1) //监听socket端口,
     {
         close(listenfd);
         ERR_EXIT( "bind" );
     }
 
     if (listen(listenfd, 6) == -1)
     {
         close(listenfd);
         ERR_EXIT( "listen" );
     }
return listenfd;
}

 3.select服务器模型:

复制代码
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <unistd.h>
  5 #include <errno.h>
  6 #include <sys/types.h>
  7 #include <sys/stat.h>
  8 #include <sys/socket.h>
  9 #include <arpa/inet.h>
 10 #include <signal.h>
 11 #include <sys/select.h>
 12 #define MAXLEN 1024
 13 
 14 #define ERR_EXIT(m) \
 15     do { \
 16         perror(m);\
 17         exit(EXIT_FAILURE);\
 18     }while(0)
 19 
 20 int listenf();//封装了网络socket的socekt,bind,listen函数,返回监听的socket描述符
 21 void handle(int signum)//SIGPIPE(子进程结束)的信号的处理
 22 {
 23     printf("hello\n");
 24 }
 25 static void do_select(int);
 26 
 27 int main(int argc, const char *argv[])
 28 {
 29     if(signal(SIGPIPE, handle) == SIG_ERR)
 30         ERR_EXIT("signal");
 31     int listenfd = listenf();
 32     do_select(listenfd);
 33     close(listenfd);
 34     return 0;
 35 }
 36 
 37 int listenf()
 38 {
 39     int listenfd = socket(AF_INET, SOCK_STREAM, 0);//准备一个socketfd
 40     if(listenfd == -1 )
 41         ERR_EXIT("listen");
 42 
 43     int on = 1;
 44     if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)//setsockopt设置端口复用
 45     {
 46         close(listenfd);
 47         ERR_EXIT("setsockopt");
 48     }
 49 
 50     struct sockaddr_in seraddr;
 51     seraddr.sin_family = AF_INET;
 52     seraddr.sin_port = htons(8888);
 53     seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
 54     socklen_t len = sizeof(seraddr);
 55     if(bind(listenfd, (struct sockaddr*)&seraddr, len) == -1)//监听socket端口,
 56     {
 57         close(listenfd);
 58         ERR_EXIT("bind");
 59     }
 60 
 61     if(listen(listenfd, 6) == -1)
 62     {
 63         close(listenfd);
 64         ERR_EXIT("listen");
 65     }
 66     return listenfd;
 67 }
 68 
 69 void do_select(int fd)
 70 {
 71     //struct sockaddr_in cliaddr;
 72     //memset(&cliaddr, 0, sizeof(cliaddr));//此处不需要客户端的地址信息
 73     fd_set set;
 74     fd_set rset;
 75     FD_ZERO(&rset);
 76     FD_SET(fd, &rset);
 77     int nready;
 78     int fd_set[MAXLEN];
 79 
 80     int i;
 81     for(i = 0;i < MAXLEN; ++i)
 82         fd_set[i] = -1;
 83     fd_set[0] = fd;
 84 
 85     int maxi = fd;//初始最大轮询fd是监听的fd
 86     int  arrlen = 1;//表示数组长度
 87    
 88    char recvbuf[1024] = {0};
 89     while(1)
 90     {
 91         set = rset;
 92         nready = select(maxi+1, &set, NULL, NULL, NULL);
 93         if(nready == -1)
 94         {
 95             ERR_EXIT("select");
 96         }
 97         if(FD_ISSET(fd, &set))//查看书否有新的客户端请求
 98         {
 99             int clifd = accept(fd, NULL, NULL);
100             if(clifd == -1)
101                 ERR_EXIT("accept");
102             for(i = 1; i < MAXLEN; ++i)
103             { if(fd_set[i] == -1)
104                 {
105                     fd_set[i] = clifd;
106                     break;
107                 }
108             }
109             FD_SET(clifd, &rset);
110             if(clifd > maxi)
111                 maxi = clifd;
112             arrlen++;
113             --nready;
114         }
115 
116         for(i = 1; i < arrlen; ++i)//轮询数据连接
117         {
118             int set_fd = fd_set[i];
119          if(FD_ISSET(set_fd, &set))
120          {
121             int n = read(set_fd, recvbuf, 1024);
122             if(n == -1)
123                 ERR_EXIT("read");
124             else if(n == 0)//客户端退出,
125             {
126               FD_CLR(set_fd, &rset);
127               close(set_fd);
128               fd_set[i] = -1;
129               arrlen--;
130             }
131             write(set_fd, recvbuf, strlen(recvbuf));
132                memset(recvbuf, 0, 1024);
133          if(--nready < 0)
134              break;
135          }
136         }
137     }
138 }
复制代码


4

复制代码
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <unistd.h>
  5 #include <errno.h>
  6 #include <sys/types.h>
  7 #include <sys/stat.h>
  8 #include <sys/socket.h>
  9 #include <arpa/inet.h>
 10 #include <signal.h>
 11 #include <poll.h>
 12 #define MAXLEN 1024
 13 
 14 #define ERR_EXIT(m) \
 15     do { \
 16         perror(m);\
 17         exit(EXIT_FAILURE);\
 18     }while(0)
 19 
 20 static void do_service(int);
 21 int listenf();
 22 void handle(int signum)
 23 {
 24     printf("hello\n");
 25 }
 26 static void do_poll(int);
 27 
 28 int main(int argc, const char *argv[])
 29 {
 30     if(signal(SIGPIPE, handle) == SIG_ERR)
 31         ERR_EXIT("signal");
 32     int listenfd = listenf();
 33     do_poll(listenfd);
 34     close(listenfd);
 35     return 0;
 36 }
 37 
 38 int listenf()
 39 {
 40     int listenfd = socket(AF_INET, SOCK_STREAM, 0);//准备一个socketfd
 41     if(listenfd == -1 )
 42         ERR_EXIT("listen");
 43 
 44     int on = 1;
 45     if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)//setsockopt设置端口复用
 46     {
 47         close(listenfd);
 48         ERR_EXIT("setsockopt");
 49     }
 50 
 51     struct sockaddr_in seraddr;
 52     seraddr.sin_family = AF_INET;
 53     seraddr.sin_port = htons(8888);
 54     seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
 55     socklen_t len = sizeof(seraddr);
 56     if(bind(listenfd, (struct sockaddr*)&seraddr, len) == -1)//监听socket端口,
 57     {
 58         close(listenfd);
 59         ERR_EXIT("bind");
 60     }
 61 
 62     if(listen(listenfd, 6) == -1)
 63     {
 64         close(listenfd);
 65         ERR_EXIT("listen");
 66     }
 67     return listenfd;
 68 }
 69 
 70 void do_poll(int fd)
 71 {
 72     struct pollfd pfd[MAXLEN];//设置的最大连接数,存放结构体信息
 73     char recvbuf[1024] = {0};
 74     int i;
 75     for(i = 0; i < MAXLEN; ++i)
 76         pfd[i].fd = -1;
 77 
 78     pfd[0].fd = fd;
 79     pfd[0].events = POLLIN;//将监听连接的描述符防止数组开头
 80 
 81     int nready;
 82     int maxi = 0;
 83     while(1)
 84     {
 85         nready = poll(pfd, maxi+1, -1);//轮询的是有效数组长度,不能少1
 86         if(nready == -1)
 87         {
 88             ERR_EXIT("select");
 89         }
 90 
 91         if(pfd[0].revents & POLLIN)//有客户端请求连接
 92         {
 93             int clifd = accept(fd, NULL, NULL);
 94             if(clifd == -1)
 95                 ERR_EXIT("accept");
 96             for(i = 1; i < MAXLEN; ++i)
 97             { 
 98                 if(pfd[i].fd == -1)
 99                 {
100                     pfd[i].fd = clifd;
101                     pfd[i].events = POLLIN;
102                     break;
103                 }
104             }
105             if(i > maxi)
106                 maxi = i;  
107             --nready;
108         }
109 
110         for(i = 1; i <= maxi; ++i)
111         {
112             if(pfd[i].fd == -1)
113                 continue;
114 
115             if( pfd[i].revents & POLLIN)
116             {
117                 int n = read(pfd[i].fd, recvbuf, 1024);
118                 if(n == -1)
119                     ERR_EXIT("read");
120                 else if(n == 0)//客户端退出,则从集合中清除
121                 {
122                     printf("%d close\n", pfd[i].fd);
123                     close(pfd[i].fd); 
124                     pfd[i].fd = -1;
125                     continue;
126                 }
127                 write(pfd[i].fd, recvbuf, strlen(recvbuf));
128                 memset(recvbuf, 0, 1024);
129 
130                 if(--nready < 0)
131                     break;
132             }
133         }
134     }
135 }
复制代码

5.epoll服务器模型:

复制代码
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <unistd.h>
  5 #include <errno.h>
  6 #include <sys/types.h>
  7 #include <sys/stat.h>
  8 #include <sys/socket.h>
  9 #include <arpa/inet.h>
 10 #include <signal.h>
 11 #include <sys/epoll.h>
 12 #define MAXLEN 1024
 13 
 14 #define ERR_EXIT(m) \
 15     do { \
 16         perror(m);\
 17         exit(EXIT_FAILURE);\
 18     }while(0)
 19 
 20 int listenf();
 21 static void do_epoll(int);
 22 
 23 int main(int argc, const char *argv[])
 24 {
 25     int listenfd = listenf();
 26     do_epoll(listenfd);
 27     close(listenfd);
 28     return 0;
 29 }
 30 
 31 int listenf()
 32 {
 33     int listenfd = socket(AF_INET, SOCK_STREAM, 0);//准备一个socketfd
 34     if(listenfd == -1 )
 35         ERR_EXIT("listen");
 36 
 37     int on = 1;
 38     if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)//setsockopt设置端口复用
 39     {
 40         close(listenfd);
 41         ERR_EXIT("setsockopt");
 42     }
 43 
 44     struct sockaddr_in seraddr;
 45     seraddr.sin_family = AF_INET;
 46     seraddr.sin_port = htons(8888);
 47     seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
 48     socklen_t len = sizeof(seraddr);
 49     if(bind(listenfd, (struct sockaddr*)&seraddr, len) == -1)//监听socket端口,
 50     {
 51         close(listenfd);
 52         ERR_EXIT("bind");
 53     }
 54 
 55     if(listen(listenfd, 6) == -1)
 56     {
 57         close(listenfd);
 58         ERR_EXIT("listen");
 59     }
 60     return listenfd;
 61 }
 62 
 63 void do_epoll(int fd)
 64 {
 65     char recvbuf[MAXLEN] = {0};
 66     int epollfd = epoll_create(2048);//设置的最大连接数
 67     if(epollfd == -1)
 68         ERR_EXIT("epoll_create");
 69 
 70     struct epoll_event ev;
 71     ev.data.fd = fd;
 72     ev.events = EPOLLIN;
 73     if(epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1)//加入轮询
 74                  ERR_EXIT("epoll_ctl_add");
 75 
 76     struct epoll_event events[2048];//数组在epoll_wait返回结果的时候使用
 77     int ret;
 78     int i;//在下面while的for循环中遍历使用
 79     int rfd;
 80     int clientfd;
 81     int nread;
 82     while(1)
 83     {
 84         ret = epoll_wait(epollfd, events, 2048, -1);
 85         if(ret == -1)
 86             ERR_EXIT("epoll_wait");
 87 
 88         for(i = 0; i < ret; ++i )
 89         {
 90             rfd = events[i].data.fd;
 91             if(rfd == fd)
 92             {
 93                 if((clientfd = accept(fd, NULL, NULL)) == -1)
 94                 ERR_EXIT("accept");
 95                 ev.data.fd = clientfd;
 96                 ev.events = EPOLLIN;
 97                 if(epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &ev) == -1)
 98                     ERR_EXIT("epoll_ctl");
 99             }else
100             {
101                 int nread = read(rfd, recvbuf, MAXLEN);
102                 if(nread == -1)
103                 {
104                     if(errno == EINTR)
105                         continue;
106                     ERR_EXIT("read");
107                 }else if( nread == 0)//客户端退出,从epoll轮询中删除
108                 {
109                     printf("%d fd close\n", rfd);
110                     ev.data.fd = rfd;
111                     ev.events = EPOLLIN;
112                     if(epoll_ctl(epollfd, EPOLL_CTL_DEL, rfd, &ev) == -1)
113                         ERR_EXIT("epoll_ctl");
114                 }else
115                 {
116                     if(write(rfd, recvbuf, strlen(recvbuf)) == -1)
117                         ERR_EXIT("write");
118                     memset(recvbuf, 0, MAXLEN);
119                 }
120             }
121         }
122     }
123     close(epollfd);
124 }
复制代码

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在C语言中搭建一个多进程并发的Web服务器实现Web应用的一种常见方式。这种方式的主要优点是能够处理多个客户端的请求,并且能够实现并发处理,提高了服务器的性能。 实现一个多进程的Web服务器基本步骤如下: 1. 创建一个父进程,用于监听指定的网络端口,并接受客户端的连接请求。 2. 父进程接收到客户端的连接请求后,创建一个子进程来处理该请求。 3. 子进程负责接收和解析客户端的HTTP请求,并根据请求的内容生成相应的HTTP响应。 4. 子进程将生成的HTTP响应发送给客户端,完成请求处理后,子进程可以自行退出。 5. 父进程继续监听指定网络端口,接受下一个客户端的连接请求。 通过多进程的方式,可以实现同时处理多个客户端请求的能力并提高并发处理能力。父进程只负责接受连接请求并创建子进程,而子进程则负责具体的请求处理。不同的子进程之间相互独立,互不影响,可以同时处理多个请求。 需要注意的是,多进程的方式可能会导致一些资源的浪费,比如每个子进程都需要单独的内存空间和资源。另外,也要注意处理子进程的退出和异常情况,以及进程间的通信和同步问题。 总之,通过使用C语言搭建多进程并发的Web服务器,可以实现高性能的Web应用服务端,有效地处理多个客户端的请求,提供更好的用户体验。 ### 回答2: C语言通过使用多进程来实现Web服务器并发是一种常见的方法。这种方法基于操作系统提供的进程控制功能,可以同时处理多个客户端的请求。下面是一个使用C语言构建具有多进程并发功能的Web服务器的示例: 首先,我们需要使用C语言中的系统调用函数(如fork()和exec())来创建子进程。父进程负责监听客户端请求,而子进程负责处理请求并向客户端发送响应。 在主程序中,我们需要创建一个主进程,用于监听客户端的连接请求。主进程使用socket函数创建一个TCP连接,然后使用bind和listen函数将其绑定到一个特定的端口上,并开始监听客户端的连接请求。 一旦有客户端连接请求到达,主进程使用accept函数来接受该连接请求,并创建一个子进程来处理它。子进程通过调用fork函数来复制主进程的地址空间,并可以继续执行与主进程相同的代码。 在子进程中,我们需要使用exec函数来执行一个新的程序,比如一个CGI脚本或者是处理静态文件的函数。在这个过程中,子进程与客户端进行通信,接收并处理请求并再次发送响应。 当子进程完成处理后,它会关闭与客户端的连接,并通过exit函数退出。父进程会继续监听其他客户端的连接请求,并创建新的子进程来处理它们。 通过这种方式,我们可以实现一个基于C语言的多进程并发的Web服务器。这种方法可以提供快速的响应速度,允许服务器同时处理多个客户端请求。但是,它也会消耗更多的系统资源,并且在高并发情况下可能会导致系统负载过重。因此,在实际应用中,我们需要根据具体情况选择最合适的并发模型来构建Web服务器。 ### 回答3: C语言搭建Web服务器实现多进程并发主要有以下几个步骤: 1. 创建Socket:首先,我们需要使用Socket函数创建一个服务器端的套接字,指定服务器端监听的IP地址和端口号。 2. 绑定Socket:使用bind函数将服务器端套接字与指定的IP地址和端口号进行绑定。 3. 监听连接请求:使用listen函数开始监听来自客户端的连接请求。 4. 接受连接请求:使用accept函数等待并接受客户端的连接请求,当有客户端请求连接时,accept函数将返回一个新的套接字。 5. 创建子进程:当接受到客户端的连接请求后,使用fork函数创建一个子进程,子进程将负责与该客户端进行通信。 6. 子进程处理请求:在子进程中,使用recv函数接收来自客户端的HTTP请求,并根据请求的内容生成相应的HTTP响应。 7. 发送响应:使用send函数将生成的HTTP响应发送给客户端。 8. 关闭连接:在通信结束后,关闭子进程中的套接字,并终止子进程的执行。 9. 父进程继续监听:父进程在子进程处理完请求并关闭套接字后,继续监听其他客户端的连接请求,重复上述步骤。 通过以上步骤,我们就可以使用C语言搭建一个能够实现多进程并发的Web服务器。每个接收到的客户端请求都会创建一个独立的子进程进行处理,从而实现并发处理多个客户端请求的能力。这种方式可以提高服务器并发性能,同时确保每个客户端请求都能够得到及时的响应。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值