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

在这里插入图片描述

欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。


多进程多线程并发服务器

  • 什么是并发服务器
  • 多进程并发服务器代码实现
  • 多线程并发服务器代码实现
  • 618图书推荐


专栏:《网络编程》


什么是并发服务器

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

多进程并发服务器
多进程并发服务器通过创建多个子进程来处理客户端请求。每个子进程是操作系统中独立运行的单位,拥有自己的内存空间和资源。当有新的客户端连接请求到达时,服务器创建一个新的子进程来处理该请求。子进程负责与客户端通信并提供所需的服务。
多进程并发服务器的优点是稳定性高。由于每个子进程都是相互独立的,一个子进程的崩溃或错误不会影响其他子进程的执行。这种独立性使得多进程并发服务器能够有效地隔离错误,提高服务器的可靠性。
然而,多进程并发服务器也有一些缺点。创建和管理多个进程需要消耗更多的系统资源,包括内存和CPU时间。进程间的通信也需要特殊的机制,例如管道或共享内存,以便在不同进程之间传递数据。此外,由于每个进程都有自己的内存空间,进程间的数据共享和同步可能会变得复杂。

多线程并发服务器
多线程并发服务器通过创建多个线程来处理客户端请求。线程是在进程内部运行的独立执行流,共享同一个进程的内存空间和资源。与多进程不同,多线程服务器不需要创建新的进程来处理请求,而是在同一个进程中创建多个线程。
多线程并发服务器的优点是资源消耗较少。与进程相比,线程的创建和切换开销更小,因为它们共享进程的资源。这使得多线程并发服务器更加轻量级,能够更高效地利用系统资源。
然而,多线程并发服务器也存在一些问题。首先,线程共享进程的内存空间,因此在多线程环境中访问共享数据需要特殊的同步机制,以避免竞态条件和数据不一致。其次,由于线程共享相同的地址空间,一个线程的错误可能会影响整个进程,导致服务器崩溃或不稳定。

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

  • 如果稳定性和容错性是首要考虑因素,多进程并发服务器可能是更好的选择。每个子进程的独立性可以有效地隔离错误,提高服务器的可靠性。
  • 如果服务器需要处理大量的并发连接并需要更高的性能和资源利用率,多线程并发服务器可能更适合。线程的创建和切换开销相对较小,可以更高效地处理并发请求。
  • 如果同时需要稳定性和性能,可以考虑使用混合模型,即在每个进程中创建多个线程,以实现更好的负载平衡和资源利用率。

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

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

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

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

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

server

/* 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

void do_sigchild(int num)
{
	while (waitpid(0, NULL, WNOHANG) > 0)
		;
}
int main(void)
{
	struct sockaddr_in servaddr, cliaddr;
	socklen_t cliaddr_len;
	int listenfd, connfd;
	char buf[MAXLINE];
	char str[INET_ADDRSTRLEN];
	int i, n;
	pid_t pid;

	struct sigaction newact;
	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);
			return 0;
		} else if (pid > 0) {
			Close(connfd);
		} else
			perr_exit("fork");
	}
	Close(listenfd);
	return 0;
}

client

/* 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

int main(int argc, char *argv[])
{
	struct sockaddr_in servaddr;
	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);
	return 0;
}

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

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

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

server

/* 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

struct s_info {
	struct sockaddr_in cliaddr;
	int connfd;
};
void *do_work(void *arg)
{
	int n,i;
	struct s_info *ts = (struct s_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);
}

int main(void)
{
	struct sockaddr_in servaddr, cliaddr;
	socklen_t cliaddr_len;
	int listenfd, connfd;
	int i = 0;
	pthread_t tid;
	struct s_info ts[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++;
	}
	return 0;
}

client

/* 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
int main(int argc, char *argv[])
{
	struct sockaddr_in servaddr;
	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);
	return 0;
}

618图书推荐

书籍是知识的海洋,计算机好书推荐
在这里插入图片描述
🔥🔥🔥618,清华社 IT BOOK 多得图书活动开始啦!活动时间为2023 年6 月7 日至6 月18 日,清华社为您精选多款高分好书,涵盖了 C++、Java、Python、前端、后端、数据库、算法与机器学习等多个IT 开发领域,适合不同层次的读者。全场5 折,扫码领券更有优惠哦!快来京东点击链接 IT BOOK多得查看详情吧!


在这里插入图片描述
在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/247070.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入了解空号检测API:提升通信效率的关键

引言 随着通信技术的不断发展&#xff0c;人们对于通信效率的要求也越来越高。在通信过程中&#xff0c;空号检测是一个非常重要的环节&#xff0c;它可以帮助我们避免无效的通信&#xff0c;提高通信效率。而空号检测API则是实现空号检测功能的重要工具。 空号检测API 空号…

Seata Server与Nacos Server搭建(商城7)

一、Nacos简介 &#xff08;一&#xff09;Nacos是什么 1、Nacos是 Dynamic Naming and Configuration Service的首字母简称&#xff0c;相较之下&#xff0c;它更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 2、Nacos 帮助您发现、配置和管理微服务。Nacos…

【seata】 seata整合nacos + springcloud alibaba 真保姆级教程 解决各种坑点

前言&#xff1a; 坑点太多了&#xff0c;以至于需要单独写篇博客记录一下。 网上教程五花八门且不声明版本&#xff0c;文档不对应以及seata本身的bug&#xff0c;就造成了部署时各种踩坑&#xff0c;如果你和博主一样&#xff0c;已经又恰好很久没碰过nacos了&#xff0c;那可…

pandas读取Excel表指定数值 计算总和

题目要求&#xff1a;在一个文件夹里面有424个Excel表格&#xff0c;每个表格中都是统一的&#xff0c;如下图。要求计算所有表格中金额的总和。 上代码&#xff1a; import os import glob import pandas as pd# 指定文件夹路径 folder_path C:\\Users\\Administrator\\Desk…

Java—基于SpringBootWeb的综合小案例(智能学习辅助系统)

简介&#xff1a;这篇帖子是小编在看哔哩哔哩网课是的一个小案例&#xff0c;来自于黑马程序员&#xff0c;我觉得他们的课讲的很好&#xff0c;而且这个案例很有实用性&#xff0c;就在看视频的基础上&#xff0c;边温故知新&#xff0c;边实现了这个代码&#xff0c;在一些重…

Three.js中文网1-12入门案例

Three.js中文网 <template><div id"webgl"></div> </template><script setup> import * as THREE from three; import { OrbitControls } from three/addons/controls/OrbitControls.js;// 创建3D场景对象Scene const scene new THR…

【Axure RP9】动态面板使用------案例:包括轮播图和多方式登入及左侧菜单栏案例

目录 一 动态面板简介 1.1 动态面板是什么 二 轮播图 2.1 轮播图是什么 2.2 轮播图应用场景 2.3 制作实播图 三 多方式登入 3.1多方式登入是什么 3.3 多方式登入实现 四 左侧菜单栏 4.1左侧菜单栏是什么 4.2 左侧菜单栏实现 一 动态面板简介 1.1 动态面板是什么…

配置VRRP负载分担示例

一、组网需求&#xff1a; HostA和HostC通过Switch双归属到SwitchA和SwitchB。为减轻SwitchA上数据流量的承载压力&#xff0c;HostA以SwitchA为默认网关接入Internet&#xff0c;SwitchB作为备份网关&#xff1b;HostC以SwitchB为默认网关接入Internet&#xff0c;SwitchA作为…

【教程】从零开始的ORB-SLAM3的安装与配置

引言 最近项目需求需要接触vslam&#xff0c;博主选择从ORB-SLAM3下手并且记录下安装的基本流程。不得不说&#xff0c;这安装流程就像二大娘的裹脚布。 大致环境前提&#xff1a;Ubuntu20.04 一、ORB-SLAM3的源码下载 1、首先&#xff0c;为了方便管理文件&#xff0c;我们…

【infiniband】ibdump抓包

ibdump用于捕获和转储InfiniBand网络的流量。 这种工具通常用于调试和分析InfiniBand网络问题&#xff0c;包括性能瓶颈和配置错误。ibdump工具在Mellanox InfiniBand环境中较为常用&#xff0c;现由NVIDIA提供支持。 使用ibdump的基本步骤 请注意&#xff0c;您需要在安装了…

MATLAB六轴机械臂机器人的动力学分析

1、概述 动力学以牛顿第二定律为核心&#xff0c;这个定律指出了力、加速度、质量三者间的关系。 质点动力学有两类基本问题&#xff1a; 一是已知作用于质点上的力&#xff0c;求质点的运动&#xff0c;这个就是正动力学。 二是已知质点的运动&#xff0c;求作用于质点上的力…

SpringMVC-02

SpringMVC-02 SSM 框架集成与测试环境配置添加源代码 SSM 框架集成与测试 环境配置 IDEA 下创建项⽬ 创建Maven对应的Web项⽬ 配置 pom.xml 2.1. 修改 JDK 版本 <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><mav…

【Matlab】如何使用MATLAB可视化二重积分(附完整MATLAB代码)

可视化二重积分 前言正文完整代码代码实现可视化结果 前言 二重积分是指在二维空间中对函数进行积分。二重积分的公式如下&#xff1a; ∫ a b ∫ c d f ( x , y ) d x d y ∫_a^b ∫_c^d f(x, y) dx dy ∫ab​∫cd​f(x,y)dxdy 其中&#xff0c; a a a 和 b b b 是 x x x…

maven打包插件maven-jar-plugin与spring-boot-maven-plugin

maven几种打包插件介绍 文章目录 &#x1f50a;1.spring-boot-maven-plugin打包后效果 &#x1f4d5;2.maven-jar-plugin打包后效果&#x1f58a;️最后总结 &#x1f50a;1.spring-boot-maven-plugin <plugins><plugin><groupId>org.springframework.boot&…

每日一题SQL

以下题目来源微信公众号【SQL数据库开发】 1、编写一个 SQL 查询来实现分数排名。如果两个分数相同&#xff0c;则两个分数排名&#xff08;Rank&#xff09;相同。请注意&#xff0c;平分后的下一个名次应该是下一个连续的整数值。换句话说&#xff0c;名次之间不应该有“间隔…

HTML5+CSS3+JS小实例:自适应瀑布流布局

实例:自适应瀑布流布局 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" content=&quo…

九、 SpringBoot项目部署、项目打包、运行

5.5.1 项目打包 步骤1&#xff1a; 添加项目的pom.xml插件&#xff1b;在pom.xml要显式的加入插件spring-boot-maven-plugin&#xff0c;否则无法产生 jar 清单文件&#xff0c;导致打出来的 jar 无法使用命令运行&#xff1b; <build> <plugins> <!-- 打j…

2023 re:Invent使用 PartyRock 和 Amazon Bedrock 安全高效构建 AI 应用程序

前言 本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 亚马逊云科技开发者社区, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 “Your Data, Your AI, Your Future.&#xff08;你的数据&#xff0c;你的AI&…

接口自动化测试框架搭建

一、原理及特点 参数放在XML文件中进行管理用httpClient简单封装一个httpUtils工具类测试用例管理使用了testNg管理&#xff0c;使用了TestNG参数化测试&#xff0c;通过xml文件来执行case。测试报告这里用到第三方的包ReportNG 项目组织用Maven 二、准备 使用工具&#xff1…

2023-12-14 使用Qt画一条曲线(AI辅助)

点击 <C 语言编程核心突破> 快速C语言入门 使用Qt画一条曲线 前言一、Qchart简介二、代码总结 前言 要解决问题: 有一个函数, 生成一些点, 想画一条曲线. 想到的思路: 这个用Qchart比较简单. 其它的补充: 需要稍许配置 一、Qchart简介 QChart是Qt中的一个图表控件&a…