前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >并发服务器代码实现(多进程/多线程)

并发服务器代码实现(多进程/多线程)

作者头像
mindtechnist
发布于 2025-05-09 04:16:08
发布于 2025-05-09 04:16:08
8700
代码可运行
举报
文章被收录于专栏:机器和智能机器和智能
运行总次数:0
代码可运行

什么是并发服务器

当涉及到构建高性能的服务器应用程序时,我们通常会考虑使用并发服务器来处理多个客户端请求。在并发服务器中,多进程和多线程是两种常见的并发模型,它们都有各自的优点和适用场景。本文将介绍多进程和多线程并发服务器的基础知识。

多进程并发服务器

多进程并发服务器通过创建多个子进程来处理客户端请求。每个子进程是操作系统中独立运行的单位,拥有自己的内存空间和资源。当有新的客户端连接请求到达时,服务器创建一个新的子进程来处理该请求。子进程负责与客户端通信并提供所需的服务。

多进程并发服务器的优点是稳定性高。由于每个子进程都是相互独立的,一个子进程的崩溃或错误不会影响其他子进程的执行。这种独立性使得多进程并发服务器能够有效地隔离错误,提高服务器的可靠性。

然而,多进程并发服务器也有一些缺点。创建和管理多个进程需要消耗更多的系统资源,包括内存和CPU时间。进程间的通信也需要特殊的机制,例如管道或共享内存,以便在不同进程之间传递数据。此外,由于每个进程都有自己的内存空间,进程间的数据共享和同步可能会变得复杂。

多线程并发服务器

多线程并发服务器通过创建多个线程来处理客户端请求。线程是在进程内部运行的独立执行流,共享同一个进程的内存空间和资源。与多进程不同,多线程服务器不需要创建新的进程来处理请求,而是在同一个进程中创建多个线程。

多线程并发服务器的优点是资源消耗较少。与进程相比,线程的创建和切换开销更小,因为它们共享进程的资源。这使得多线程并发服务器更加轻量级,能够更高效地利用系统资源。

然而,多线程并发服务器也存在一些问题。首先,线程共享进程的内存空间,因此在多线程环境中访问共享数据需要特殊的同步机制,以避免竞态条件和数据不一致。其次,由于线程共享相同的地址空间,一个线程的错误可能会影响整个进程,导致服务器崩溃或不稳定。

选择适合的并发模型

在选择多进程还是多线程并发服务器时,需要根据具体的应用需求和性能要求进行权衡。以下是一些建议:

- 如果稳定性和容错性是首要考虑因素,多进程并发服务器可能是更好的选择。每个子进程的独立性可以有效地隔离错误,提高服务器的可靠性。

- 如果服务器需要处理大量的并发连接并需要更高的性能和资源利用率,多线程并发服务器可能更适合。线程的创建和切换开销相对较小,可以更高效地处理并发请求。

- 如果同时需要稳定性和性能,可以考虑使用混合模型,即在每个进程中创建多个线程,以实现更好的负载平衡和资源利用率。

无论选择多进程还是多线程并发服务器,都需要注意正确处理并发访问共享数据的问题,使用适当的同步机制(如锁、信号量)来保证数据的一致性和正确性。

总结起来,多进程和多线程并发服务器是实现高性能服务器的常见方式。它们各有优劣,选择合适的并发模型需要考虑应用需求和性能要求,并注意处理并发访问共享数据的问题。

多进程并发服务器代码实现

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

- 父进程最大文件描述个数(父进程中需要close关闭accept返回的新文件描述符);

- 系统内创建进程个数(与内存大小相关);

-进程创建过多是否降低整体服务性能(进程调度);

server

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* server.c */
#include<stdio.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>
#include<sys/wait.h>
#include<sys/types.h>
#include"wrap.h"

#define MAXLINE 80
#define SERV_PORT 800

voiddo_sigchild(int num)
{
while (waitpid(0, NULL, WNOHANG) > 0)
    ;
}
intmain(void)
{
structsockaddr_inservaddr, cliaddr;
socklen_t cliaddr_len;
int listenfd, connfd;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
int i, n;
pid_t pid;

structsigactionnewact;
  newact.sa_handler = do_sigchild;
  sigemptyset(&newact.sa_mask);
  newact.sa_flags = 0;
  sigaction(SIGCHLD, &newact, NULL);

  listenfd = Socket(AF_INET, SOCK_STREAM, 0);

  bzero(&servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(SERV_PORT);

  Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

  Listen(listenfd, 20);

printf("Accepting connections ...\n");
while (1) {
    cliaddr_len = sizeof(cliaddr);
    connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);

    pid = fork();
if (pid == 0) {
      Close(listenfd);
while (1) {
        n = Read(connfd, buf, MAXLINE);
if (n == 0) {
printf("the other side has been closed.\n");
break;
        }
printf("received from %s at PORT %d\n",
            inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
            ntohs(cliaddr.sin_port));
for (i = 0; i < n; i++)
          buf[i] = toupper(buf[i]);
        Write(connfd, buf, n);
      }
      Close(connfd);
return0;
    } elseif (pid > 0) {
      Close(connfd);
    } else
      perr_exit("fork");
  }
  Close(listenfd);
return0;
}

client:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* client.c */
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<netinet/in.h>
#include"wrap.h"

#define MAXLINE 80
#define SERV_PORT 6666

intmain(int argc, char *argv[])
{
structsockaddr_inservaddr;
char buf[MAXLINE];
int sockfd, n;

  sockfd = Socket(AF_INET, SOCK_STREAM, 0);

  bzero(&servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
  servaddr.sin_port = htons(SERV_PORT);

  Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

while (fgets(buf, MAXLINE, stdin) != NULL) {
    Write(sockfd, buf, strlen(buf));
    n = Read(sockfd, buf, MAXLINE);
if (n == 0) {
printf("the other side has been closed.\n");
break;
    } else
      Write(STDOUT_FILENO, buf, n);
  }
  Close(sockfd);
return0;
}

多线程并发服务器代码实现

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

- 调整进程内最大文件描述符上限;

- 线程如有共享数据,考虑线程同步;

- 服务于客户端线程退出时,退出处理(退出值,分离态);

- 系统负载,随着链接客户端增加,导致其它线程不能及时得到CPU;

server:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* server.c */
#include<stdio.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>

#include"wrap.h"
#define MAXLINE 80
#define SERV_PORT 6666

structs_info {
structsockaddr_incliaddr;
int connfd;
};
void *do_work(void *arg)
{
int n,i;
structs_info *ts = (structs_info*)arg;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
/* 可以在创建线程前设置线程创建属性,设为分离态,哪种效率高内?*/
  pthread_detach(pthread_self());
while (1) {
    n = Read(ts->connfd, buf, MAXLINE);
if (n == 0) {
printf("the other side has been closed.\n");
break;
    }
printf("received from %s at PORT %d\n",
        inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
        ntohs((*ts).cliaddr.sin_port));
for (i = 0; i < n; i++)
      buf[i] = toupper(buf[i]);
    Write(ts->connfd, buf, n);
  }
  Close(ts->connfd);
}

intmain(void)
{
structsockaddr_inservaddr, cliaddr;
socklen_t cliaddr_len;
int listenfd, connfd;
int i = 0;
pthread_t tid;
structs_infots[256];

  listenfd = Socket(AF_INET, SOCK_STREAM, 0);

  bzero(&servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(SERV_PORT);

  Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
  Listen(listenfd, 20);

printf("Accepting connections ...\n");
while (1) {
    cliaddr_len = sizeof(cliaddr);
    connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
    ts[i].cliaddr = cliaddr;
    ts[i].connfd = connfd;
/* 达到线程最大数时,pthread_create出错处理, 增加服务器稳定性 */
    pthread_create(&tid, NULL, do_work, (void*)&ts[i]);
    i++;
  }
return0;
}

client:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* client.c */
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<netinet/in.h>
#include"wrap.h"
#define MAXLINE 80
#define SERV_PORT 6666
intmain(int argc, char *argv[])
{
structsockaddr_inservaddr;
char buf[MAXLINE];
int sockfd, n;

  sockfd = Socket(AF_INET, SOCK_STREAM, 0);

  bzero(&servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
  servaddr.sin_port = htons(SERV_PORT);

  Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

while (fgets(buf, MAXLINE, stdin) != NULL) {
    Write(sockfd, buf, strlen(buf));
    n = Read(sockfd, buf, MAXLINE);
if (n == 0)
printf("the other side has been closed.\n");
else
      Write(STDOUT_FILENO, buf, n);
  }
  Close(sockfd);
return0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-05-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器和智能 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档