盘算机网络编程 | 并发服务器代码实现(多进程/多线程) ...

打印 上一主题 下一主题

主题 1016|帖子 1016|积分 3048


   接待关注博主 Mindtechnist 或到场【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,呆板人运动控制、多呆板人协作,智能优化算法,滤波估计、多传感器信息融合,呆板学习,人工智能等相关领域的知识和技术。
  
  
   
  
  专栏:《网络编程》
  
什么是并发服务器

当涉及到构建高性能的服务器应用步伐时,我们通常会考虑利用并发服务器来处置惩罚多个客户端哀求。在并发服务器中,多进程和多线程是两种常见的并发模型,它们都有各自的优点和实用场景。本文将介绍多进程和多线程并发服务器的基础知识。
多进程并发服务器
多进程并发服务器通过创建多个子进程来处置惩罚客户端哀求。每个子进程是操纵系统中独立运行的单位,拥有自己的内存空间和资源。当有新的客户端连接哀求到达时,服务器创建一个新的子进程来处置惩罚该哀求。子进程负责与客户端通讯并提供所需的服务。
多进程并发服务器的优点是稳定性高。由于每个子进程都是相互独立的,一个子进程的瓦解或错误不会影响其他子进程的实验。这种独立性使得多进程并发服务器能够有效地隔离错误,提高服务器的可靠性。
然而,多进程并发服务器也有一些缺点。创建和管理多个进程必要消耗更多的系统资源,包罗内存和CPU时间。进程间的通讯也必要特殊的机制,例如管道或共享内存,以便在差别进程之间传递数据。别的,由于每个进程都有自己的内存空间,进程间的数据共享和同步可能会变得复杂。
多线程并发服务器
多线程并发服务器通过创建多个线程来处置惩罚客户端哀求。线程是在进程内部运行的独立实验流,共享同一个进程的内存空间和资源。与多进程差别,多线程服务器不必要创建新的进程来处置惩罚哀求,而是在同一个进程中创建多个线程。
多线程并发服务器的优点是资源消耗较少。与进程相比,线程的创建和切换开销更小,因为它们共享进程的资源。这使得多线程并发服务器更加轻量级,能够更高效地利用系统资源。
然而,多线程并发服务器也存在一些问题。起首,线程共享进程的内存空间,因此在多线程环境中访问共享数据必要特殊的同步机制,以克制竞态条件和数据不一致。其次,由于线程共享相同的地点空间,一个线程的错误可能会影响整个进程,导致服务器瓦解或不稳定。
选择适合的并发模型
在选择多进程还是多线程并发服务器时,必要根据具体的应用需求和性能要求举行权衡。以下是一些发起:


  • 假如稳定性和容错性是首要考虑因素,多进程并发服务器可能是更好的选择。每个子进程的独立性可以有效地隔离错误,提高服务器的可靠性。
  • 假如服务器必要处置惩罚大量的并发连接并必要更高的性能和资源利用率,多线程并发服务器可能更适合。线程的创建和切换开销相对较小,可以更高效地处置惩罚并发哀求。
  • 假如同时必要稳定性和性能,可以考虑利用混淆模型,即在每个进程中创建多个线程,以实现更好的负载平衡和资源利用率。
无论选择多进程还是多线程并发服务器,都必要留意正确处置惩罚并发访问共享数据的问题,利用适当的同步机制(如锁、信号量)来保证数据的一致性和正确性。
总结起来,多进程和多线程并发服务器是实现高性能服务器的常见方式。它们各有优劣,选择符合的并发模型必要考虑应用需求和性能要求,并留意处置惩罚并发访问共享数据的问题。
多进程并发服务器代码实现

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


  • 父进程最大文件描述个数(父进程中必要close关闭accept返回的新文件描述符);
  • 系统内创建进程个数(与内存巨细相关);
  • 进程创建过多是否低沉整体服务性能(进程调度);
server
  1. /* server.c */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>
  6. #include <signal.h>
  7. #include <sys/wait.h>
  8. #include <sys/types.h>
  9. #include "wrap.h"
  10. #define MAXLINE 80
  11. #define SERV_PORT 800
  12. void do_sigchild(int num)
  13. {
  14.         while (waitpid(0, NULL, WNOHANG) > 0)
  15.                 ;
  16. }
  17. int main(void)
  18. {
  19.         struct sockaddr_in servaddr, cliaddr;
  20.         socklen_t cliaddr_len;
  21.         int listenfd, connfd;
  22.         char buf[MAXLINE];
  23.         char str[INET_ADDRSTRLEN];
  24.         int i, n;
  25.         pid_t pid;
  26.         struct sigaction newact;
  27.         newact.sa_handler = do_sigchild;
  28.         sigemptyset(&newact.sa_mask);
  29.         newact.sa_flags = 0;
  30.         sigaction(SIGCHLD, &newact, NULL);
  31.         listenfd = Socket(AF_INET, SOCK_STREAM, 0);
  32.         bzero(&servaddr, sizeof(servaddr));
  33.         servaddr.sin_family = AF_INET;
  34.         servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  35.         servaddr.sin_port = htons(SERV_PORT);
  36.         Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
  37.         Listen(listenfd, 20);
  38.         printf("Accepting connections ...\n");
  39.         while (1) {
  40.                 cliaddr_len = sizeof(cliaddr);
  41.                 connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
  42.                 pid = fork();
  43.                 if (pid == 0) {
  44.                         Close(listenfd);
  45.                         while (1) {
  46.                                 n = Read(connfd, buf, MAXLINE);
  47.                                 if (n == 0) {
  48.                                         printf("the other side has been closed.\n");
  49.                                         break;
  50.                                 }
  51.                                 printf("received from %s at PORT %d\n",
  52.                                                 inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
  53.                                                 ntohs(cliaddr.sin_port));
  54.                                 for (i = 0; i < n; i++)
  55.                                         buf[i] = toupper(buf[i]);
  56.                                 Write(connfd, buf, n);
  57.                         }
  58.                         Close(connfd);
  59.                         return 0;
  60.                 } else if (pid > 0) {
  61.                         Close(connfd);
  62.                 } else
  63.                         perr_exit("fork");
  64.         }
  65.         Close(listenfd);
  66.         return 0;
  67. }
复制代码
client
  1. /* client.c */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <netinet/in.h>
  6. #include "wrap.h"
  7. #define MAXLINE 80
  8. #define SERV_PORT 6666
  9. int main(int argc, char *argv[])
  10. {
  11.         struct sockaddr_in servaddr;
  12.         char buf[MAXLINE];
  13.         int sockfd, n;
  14.         sockfd = Socket(AF_INET, SOCK_STREAM, 0);
  15.         bzero(&servaddr, sizeof(servaddr));
  16.         servaddr.sin_family = AF_INET;
  17.         inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
  18.         servaddr.sin_port = htons(SERV_PORT);
  19.         Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
  20.         while (fgets(buf, MAXLINE, stdin) != NULL) {
  21.                 Write(sockfd, buf, strlen(buf));
  22.                 n = Read(sockfd, buf, MAXLINE);
  23.                 if (n == 0) {
  24.                         printf("the other side has been closed.\n");
  25.                         break;
  26.                 } else
  27.                         Write(STDOUT_FILENO, buf, n);
  28.         }
  29.         Close(sockfd);
  30.         return 0;
  31. }
复制代码
多线程并发服务器代码实现

在利用线程模型开发服务器时需考虑以下问题:


  • 调解进程内最大文件描述符上限;
  • 线程如有共享数据,考虑线程同步;
  • 服务于客户端线程退出时,退出处置惩罚(退出值,分离态);
  • 系统负载,随着链接客户端增长,导致其它线程不能实时得到CPU;
server
  1. /* server.c */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>
  6. #include <pthread.h>
  7. #include "wrap.h"
  8. #define MAXLINE 80
  9. #define SERV_PORT 6666
  10. struct s_info {
  11.         struct sockaddr_in cliaddr;
  12.         int connfd;
  13. };
  14. void *do_work(void *arg)
  15. {
  16.         int n,i;
  17.         struct s_info *ts = (struct s_info*)arg;
  18.         char buf[MAXLINE];
  19.         char str[INET_ADDRSTRLEN];
  20.         /* 可以在创建线程前设置线程创建属性,设为分离态,哪种效率高内? */
  21.         pthread_detach(pthread_self());
  22.         while (1) {
  23.                 n = Read(ts->connfd, buf, MAXLINE);
  24.                 if (n == 0) {
  25.                         printf("the other side has been closed.\n");
  26.                         break;
  27.                 }
  28.                 printf("received from %s at PORT %d\n",
  29.                                 inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
  30.                                 ntohs((*ts).cliaddr.sin_port));
  31.                 for (i = 0; i < n; i++)
  32.                         buf[i] = toupper(buf[i]);
  33.                 Write(ts->connfd, buf, n);
  34.         }
  35.         Close(ts->connfd);
  36. }
  37. int main(void)
  38. {
  39.         struct sockaddr_in servaddr, cliaddr;
  40.         socklen_t cliaddr_len;
  41.         int listenfd, connfd;
  42.         int i = 0;
  43.         pthread_t tid;
  44.         struct s_info ts[256];
  45.         listenfd = Socket(AF_INET, SOCK_STREAM, 0);
  46.         bzero(&servaddr, sizeof(servaddr));
  47.         servaddr.sin_family = AF_INET;
  48.         servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  49.         servaddr.sin_port = htons(SERV_PORT);
  50.         Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
  51.         Listen(listenfd, 20);
  52.         printf("Accepting connections ...\n");
  53.         while (1) {
  54.                 cliaddr_len = sizeof(cliaddr);
  55.                 connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
  56.                 ts[i].cliaddr = cliaddr;
  57.                 ts[i].connfd = connfd;
  58.                 /* 达到线程最大数时,pthread_create出错处理, 增加服务器稳定性 */
  59.                 pthread_create(&tid, NULL, do_work, (void*)&ts[i]);
  60.                 i++;
  61.         }
  62.         return 0;
  63. }
复制代码
client
  1. /* client.c */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <netinet/in.h>
  6. #include "wrap.h"
  7. #define MAXLINE 80
  8. #define SERV_PORT 6666
  9. int main(int argc, char *argv[])
  10. {
  11.         struct sockaddr_in servaddr;
  12.         char buf[MAXLINE];
  13.         int sockfd, n;
  14.         sockfd = Socket(AF_INET, SOCK_STREAM, 0);
  15.         bzero(&servaddr, sizeof(servaddr));
  16.         servaddr.sin_family = AF_INET;
  17.         inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
  18.         servaddr.sin_port = htons(SERV_PORT);
  19.         Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
  20.         while (fgets(buf, MAXLINE, stdin) != NULL) {
  21.                 Write(sockfd, buf, strlen(buf));
  22.                 n = Read(sockfd, buf, MAXLINE);
  23.                 if (n == 0)
  24.                         printf("the other side has been closed.\n");
  25.                 else
  26.                         Write(STDOUT_FILENO, buf, n);
  27.         }
  28.         Close(sockfd);
  29.         return 0;
  30. }
复制代码
618图书保举

   书籍是知识的海洋,盘算机好书保举

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

络腮胡菲菲

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表