2024.12.29(进程线程实现并发服务器)
作业
多进程多线程并发服务器实现一遍提交。
服务器
#include <myhead.h>
#define PORT 12345
#define IP "192.168.124.123"void *fun(void *fd)
{int newfd = *(int *)fd;char buff[1024];while(1){int res = recv(newfd,buff,sizeof(buff),0);if(res == 0){printf("当前客户端已经退出\n");break;}printf("%s\n",buff);strcat(buff,"作业写完了");send(newfd,buff,sizeof(buff),0);}pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{//创建套接字int oldfd = socket(AF_INET,SOCK_STREAM,0);if(oldfd == -1){perror("socket");return -1;}//绑定struct sockaddr_in server = {.sin_family = AF_INET,.sin_port = htons(PORT),.sin_addr.s_addr = inet_addr(IP)};if(bind(oldfd,(struct sockaddr *)&server,sizeof(server))==-1){perror("bind");return -1;}//监听if(listen(oldfd,22)==-1){perror("listen");return -1;}struct sockaddr_in client;int client_len = sizeof(client);int newfd;pthread_t tid;while(1){//接收新客户端连入请求newfd = accept(oldfd,(struct sockaddr *)&client,&client_len);if(newfd == -1){perror("accept");return -1;}//创建子线程与客户端通话if(pthread_create(&tid,NULL,fun,&newfd)==-1){perror("pthread_create");return -1;}}pthread_join(tid,NULL);close(newfd);close(oldfd);return 0;
}
客户端
#include <myhead.h>
#define PORT 12345
#define IP "192.168.124.123"
int main(int argc, const char *argv[])
{//创建套接字int oldfd = socket(AF_INET,SOCK_STREAM,0);if(oldfd == -1){perror("socket");return -1;}//连接服务器struct sockaddr_in server = {.sin_family = AF_INET,.sin_port = htons(PORT),.sin_addr.s_addr = inet_addr(IP)};if(connect(oldfd,(struct sockaddr *)&server,sizeof(server))==-1){perror("connect");return -1;}//收发消息char buff[1024];while(1){fgets(buff,sizeof(buff),stdin);buff[strlen(buff)-1] = '\0';send(oldfd,buff,strlen(buff),0);if(strcmp(buff,"quit")==0){break;}bzero(buff,sizeof(buff));recv(oldfd,buff,sizeof(buff),0);printf("服务器发来消息:%s\n",buff);}return 0;
}
学习笔记
端口号快速复用函数
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
功能: 获取套接字或者其他层级的属性
参数1:套接字描述符
参数2:要获取的层级
参数3:操作名称每一层级名称都不一样,具体见下表。
参数4:变量的地址(表中的数据类型定义的变量)
参数5:参数4 的大小。
返回值:成功返回0,失败返回-1,并置位错误码
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
功能:设置套接字或者其他层级的属性
参数1:套接字描述符
参数2:要获取的层级
参数3:操作名称每一层级名称都不一样,具体见下表。
参数4:变量的地址(表中的数据类型定义的变量)
参数5:参数4 的大小。
返回值:成功返回0,失败返回-1,并置位错误码

函数使用:
#include <myhead.h>int main(int argc, const char *argv[])
{int oldfd= socket(AF_INET,SOCK_STREAM,0);if(oldfd==-1){return -1;}//获取端口号快速复用的属性(默认关闭)int k;int k_len = sizeof(int);if(getsockopt(oldfd,SOL_SOCKET,SO_REUSEADDR,&k,&k_len)==-1){perror("getsockopt");return -1;}printf("k = %d\n",k);//k=0//设置开启端口号快速复用属性(k!=0即可)k = 2;if(setsockopt(oldfd,SOL_SOCKET,SO_REUSEADDR,&k,sizeof(k))==-1){perror("setsockopt");return -1;}printf("开启端口号快速复用功能\n");return 0;
}
1、循环服务器模型
创建套接字
绑定
监听
循环:
创建新的用于通讯的套接字
收消息
发消息
关闭新的套接字
关闭旧的套接字
代码:
缺点:新客户端要通信,必须使旧的客户端先退出。
#include <myhead.h>
#define IP "192.168.124.34"
#define PORT 6666
int main(int argc, const char *argv[])
{//1、创建套接字//2、绑定//3、监听//4、循环连接不同客户端//5、循环收发信息//1创建套接字 int oldfd = socket(AF_INET,SOCK_STREAM,0);if(-1==oldfd){perror("socket");return -1;}//2、绑定struct sockaddr_in server = {.sin_family = AF_INET,.sin_port = htons(PORT),.sin_addr.s_addr = inet_addr(IP)};if(bind(oldfd,(struct sockaddr *)&server,sizeof(server))==-1){perror("bind");return -1;}//3、监听if(listen(oldfd,20)==-1){perror("listen");return -1;}//4、连接int newfd;struct sockaddr_in client;int client_len = sizeof(client);while(1){if((newfd = accept(oldfd,(struct sockaddr *)&client,&client_len))==-1){perror("accept");return -1;}//5、信息收发char buff[1024];while(1){int res = recv(newfd,buff,sizeof(buff),0);if(res==0){printf("您的客户端已经下线\n");break;}printf("%s\n",buff);strcat(buff,"中午吃啥");send(newfd,buff,sizeof(buff),0);}}close(oldfd);close(newfd);return 0;
}
2、基于TCP并发服务器,目前有多进程和多线程并发。
2.1、多进程并发服务器,父进程只负责处理不同客户端的链接请求,每一个客户端请求连接就创建出一个子进程进行处理通话。
多进程服务器模型
1、子进程在哪创建
2、子进程怎么回收
3、终端打开的文件描述符有限。
1、多进程并发执行
模型:
定义信号处理函数,非阻塞回收僵尸进程。
绑定子进程退出时的信号。
1、创建套接字
2、绑定
3、监听
4、循环接收客户端信息
5、让父进程接收客户端请求并关闭新文件描述符,子进程关闭旧的描述符只负责数据收发。
服务器代码:
#include <myhead.h>
#define IP "192.168.124.34"
#define PORT 8888
void handle(int sss)
{if(sss==SIGCHLD){while(waitpid(-1,NULL,WNOHANG)>0);//非阻塞循环回收子进程资源}printf("回收成功\n");
}
int main(int argc, const char *argv[])
{//1、创建套接字//2、绑定//3、监听//4、父进程连接新的客户端//5、创建子父进程,父进程关闭新的描述符//5、子进程负责数据收发并关闭旧的描述符//1、创建套接字int oldfd = socket(AF_INET,SOCK_STREAM,0);if(-1==oldfd){perror("socket");return -1;}//端口号快速复用int k = 999;if(setsockopt(oldfd,SOL_SOCKET,SO_REUSEADDR,&k,sizeof(k))==-1){perror("setsockopt");return -1;}printf("端口号快速复用成功\n");//2、绑定struct sockaddr_in server = {.sin_family = AF_INET,.sin_port = htons(PORT),.sin_addr.s_addr = inet_addr(IP)};if(bind(oldfd,(struct sockaddr *)&server,sizeof(server))==-1){perror("bind");return -1;}//3、监听if(listen(oldfd,88)==-1){perror("listen");return -1;}//4、父进程连接新的客户端 struct sockaddr_in client;int client_len = sizeof(client);while(1){int newfd = accept(oldfd,(struct sockaddr *)&client,&client_len);if(newfd==-1){perror("accept");return -1;}printf("%s:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));//输出新客户端信息//5、创建子父进程pid_t pid = fork();char buff[1024];if(pid>0){if(signal(SIGCHLD,handle)==SIG_ERR)//绑定子进程退出时的信号{perror("signal");return -1;}//父进程关闭新的描述符close(newfd);}else if(pid==0){//子进程关闭旧的描述符信息收发close(oldfd);while(1){int res = recv(newfd,buff,sizeof(buff),0);if(res==0){printf("客户端已经退出\n");break;}printf("%s\n",buff);strcat(buff,"今天周日啊");send(newfd,buff,sizeof(buff),0);}exit(EXIT_SUCCESS);//子进程退出}else{perror("fork");return -1;}}close(oldfd);return 0;
}
TCP客户端:
#include <myhead.h>
#define IP "192.168.124.34"
#define SERPORT 8888
int main(int argc, const char *argv[])
{//1、创建套接字//2、绑定(不是必须绑定)//3、连接//4、收发消息int oldfd = socket(AF_INET,SOCK_STREAM,0);if(oldfd==-1){perror("socket");return -1;}
#if 0//绑定固定的IP和端口号(不是必须的)struct sockaddr_in client = {.sin_family =AF_INET,.sin_port = htons(7899),//自定义端口号.sin_addr.s_addr = inet_addr("192.168.124.34")};if(bind(oldfd,(struct sockaddr *)&client,sizeof(client))==-1){perror("bind");return -1;}
#endif//连接服务器struct sockaddr_in server = {.sin_family =AF_INET,.sin_port = htons(SERPORT),//注意端口号需要服务器端口.sin_addr.s_addr = inet_addr(IP)};if(connect(oldfd,(struct sockaddr *)&server,sizeof(server))==-1){perror("connect");return -1;}//收发消息char buff[1024];while(1){fgets(buff,sizeof(buff),stdin);buff[strlen(buff)-1] = '\0';send(oldfd,buff,strlen(buff),0);if(strcmp(buff,"quit")==0)//退出客户端{break;}bzero(buff,sizeof(buff));recv(oldfd,buff,sizeof(buff),0);//阻塞接收服务器消息printf("服务器发来消息:%s\n",buff);}return 0;
}
2、多线程并发服务器
1、大部分的多任务并发执行,我们都选择多线程,而不是多进程,因为多线程资源开销小,而且创建销毁比进程容易。
2、如果客户端过多,需要建立一个线程池,有客户端请求,就从线程池拿出一个线程分配给该客户端。
3、由于线程是提前创建好的,所以响应速度很快。
4、客户端退出后,线程会被销毁,由于线程占用资源较少,销毁也不会占用太多开销。
模型:
线程函数:
收发消息
关闭新描述符
子线程退出
建立原始套接字
绑定主机IP 监听客户端
循环:
accept:获取客户端请求
建立子线程
线程挂起
关闭旧的文件描述符
多线程并发服务器
#include <myhead.h>
#define IP "192.168.124.34"
#define PORT 8888
void *fun(void *fd)
{int newfd = *(int *)fd; char buff[1024];while(1){int res = recv(newfd,buff,sizeof(buff),0);if(res==0){printf("客户端下线\n");break;}printf("%s\n",buff);strcat(buff,"5点放学");send(newfd,buff,sizeof(buff),0);}pthread_exit(NULL);//子线程退出
}int main(int argc, const char *argv[])
{//创建套接字int oldfd = socket(AF_INET,SOCK_STREAM,0);if(oldfd==-1){perror("socket");return -1;}//绑定struct sockaddr_in server = {.sin_family =AF_INET,.sin_port = htons(PORT),.sin_addr.s_addr =inet_addr(IP)};if(bind(oldfd,(struct sockaddr *)&server,sizeof(server))==-1){perror("bind");return -1;}//监听if(listen(oldfd,20)==-1){perror("listen");return -1;}struct sockaddr_in client;int client_len = sizeof(client);int newfd;pthread_t tid;while(1){//接收新客户端连入请求newfd = accept(oldfd,(struct sockaddr *)&client,&client_len);if(newfd==-1){perror("accept");return -1;}//创建子线程与客户端通话if(pthread_create(&tid,NULL,fun,&newfd)==-1){perror("pthread_create");return -1;}}pthread_join(tid,NULL);//回收子线程资源close(newfd);close(oldfd);return 0;
}
多线程客户端:
#include <myhead.h>
#define IP "192.168.124.34"
#define SERPORT 8888
int main(int argc, const char *argv[])
{//1、创建套接字//2、绑定(不是必须绑定)//3、连接//4、收发消息int oldfd = socket(AF_INET,SOCK_STREAM,0);if(oldfd==-1){perror("socket");return -1;}
#if 0//绑定固定的IP和端口号(不是必须的)struct sockaddr_in client = {.sin_family =AF_INET,.sin_port = htons(7899),//自定义端口号.sin_addr.s_addr = inet_addr("192.168.124.34")};if(bind(oldfd,(struct sockaddr *)&client,sizeof(client))==-1){perror("bind");return -1;}
#endif//连接服务器struct sockaddr_in server = {.sin_family =AF_INET,.sin_port = htons(SERPORT),//注意端口号需要服务器端口.sin_addr.s_addr = inet_addr(IP)};if(connect(oldfd,(struct sockaddr *)&server,sizeof(server))==-1){perror("connect");return -1;}//收发消息char buff[1024];while(1){fgets(buff,sizeof(buff),stdin);buff[strlen(buff)-1] = '\0';send(oldfd,buff,strlen(buff),0);if(strcmp(buff,"quit")==0)//退出客户端{break;}bzero(buff,sizeof(buff));recv(oldfd,buff,sizeof(buff),0);//阻塞接收服务器消息printf("服务器发来消息:%s\n",buff);}return 0;
}作业:多进程多线程并发服务器实
思维导图

相关文章:
2024.12.29(进程线程实现并发服务器)
作业 多进程多线程并发服务器实现一遍提交。 服务器 #include <myhead.h> #define PORT 12345 #define IP "192.168.124.123"void *fun(void *fd) {int newfd *(int *)fd;char buff[1024];while(1){int res recv(newfd,buff,sizeof(buff),0);if(res 0){p…...
如何在 Ubuntu 上安装 PyTorch
简介 PyTorch 因其易用性、动态计算图和高效性而日益流行,成为实现深度学习模型的首选。如果你想探索这个工具并学习如何在 Ubuntu 上安装 PyTorch,本指南将对你有所帮助! 在本教程中,我们将引导你完成在 Ubuntu 系统上使用 Pip…...
8-Gin 中间件 --[Gin 框架入门精讲与实战案例] 【文末有测试代码】
路由中间件 Gin 是一个用 Go (Golang) 编写的 HTTP web 框架。它以性能好、中间件支持灵活著称,非常适合用来构建微服务或 RESTful API 服务。下面我将提供三个使用 Gin 的路由中间件的完整示例。 示例 1: 简单的日志记录中间件 这个中间件会在每个请求处理前后打…...
【潜意识Java】深入详细理解分析Java中的toString()方法重写完整笔记总结,超级详细。
目录 一、toString() 方法是啥? (一)默认的 toString() 方法 (二)toString() 方法的作用 二、为啥要重写 toString() 方法? (一)提高代码的可读性 (二)…...
【论文笔记】Contrastive Learning for Sign Language Recognition and Translation
🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: Contrastive Learning for…...
Gitlab17.7+Jenkins2.4.91实现Fastapi/Django项目持续发布版本详细操作(亲测可用)
一、gitlab设置: 1、进入gitlab选择主页在左侧菜单的下面点击管理员按钮。 2、选择左侧菜单的设置,选择网络,在右侧选择出站请求后选择允许来自webhooks和集成对本地网络的请求 3、webhook设置 进入你自己的项目选择左侧菜单的设置ÿ…...
一起来看--红黑树
【欢迎关注编码小哥,学习更多实用的编程方法和技巧】 红黑树是一种自平衡的二叉搜索树,广泛应用于计算机科学中,尤其是在实现关联数组和集合时。它的设计旨在确保在最坏情况下,基本动态集合操作(如插入、删除和查找&am…...
SpringBoot整合篇 05、Springboot整合Redission
文章目录 前言Redission详细配置步骤pom依赖application.yaml配置类CacheConfigEnvironmentContext RedissionController单测 前言 本篇博客是SpringBoot整合Redission,若文章中出现相关问题,请指出! 所有博客文件目录索引:博客…...
供应链系统设计-供应链中台系统设计(六)- 商品中心概念篇
概述 我们在供应链系统设计-中台系统设计系列(五)- 供应链中台实践概述 中描述了什么是供应链中台,供应链中台主要包含了那些组成部门。包括业务中台、通用中台等概念。为了后续方便大家对于中台有更深入的理解,我会逐一针对中台…...
胡闹厨房练习(三)
ScriptableObject 一、初步了解 1、实质:是一种特殊类型的Unity对象, 2、作用:用于存储大量数据,而不必依附于游戏场景中的某个GameObject。 3、特点: 可以在不增加场景中对象数量的情况下,管理和存储复杂的数据结构、配置信息、游戏状态等。 4、适用:非常适合用来…...
关于ESD(静电放电)等级的划分
关于ESD(静电放电)等级的划分,主要依据不同的测试模型和测试标准。以下是对HBM(人体模型)和CDM(充电器件模型)两种测试模型下ESD等级划分的详细解释: HBM ESD等级划分 HBM ESD等级…...
探究步进电机与输入脉冲的关系
深入了解步进电机 前言一、 步进电机原理二、 细分三、脉冲数总结 前言 主要是探究以下内容: 1、步进电机的步进角。 2、什么是细分。 3、脉冲的计算。 最后再扩展以下STM32定时器的计算方法。 一、 步进电机原理 其实语言描述怎么样都不直观,我更建议…...
基于YOLOV5+Flask安全帽RTSP视频流实时目标检测
1、背景 在现代工业和建筑行业中,安全始终是首要考虑的因素之一。特别是在施工现场,工人佩戴安全帽是确保人身安全的基本要求。然而,人工监督难免会有疏漏,尤其是在大型工地或复杂环境中,确保每个人都佩戴安全帽变得非…...
Windows内置的服务器IIS(Internet Information Services)托管网站
一. 安装IIS 打开控制面板:在开始菜单搜索“控制面板”并打开它。程序和功能:点击“程序”然后选择“程序和功能”。启用或关闭Windows功能:在左侧菜单中选择“启用或关闭Windows功能”。查找并勾选IIS:在弹出的窗口中,…...
虚幻引擎结构之UObject
一. UObject 的介绍 UObject 是虚幻引擎中的核心基础类,所有其他游戏对象和资源类都直接或间接地继承自它。作为虚幻引擎的基石,UObject 提供了多项关键功能,包括内存管理、序列化、反射(introspection)、垃圾回收以及元数据支持。在虚幻引擎中,UObject 类的实例通常被称…...
js的Reflect对象
Reflect 对象是 JavaScript ES6 中引入的一个内建对象,它提供了一系列与对象操作相关的方法。这些方法与 Object 对象上的方法类似,但在行为上有一些差异,并且更加规范和统一。Reflect 对象并不是一个构造函数,不能被 new 操作符调…...
this指向了谁?
看函数在执行的时候是如何调用的, 1 如果这个函数是用普通函数调用模式来进行调用,它内部的this指向了window; 2 如果一个函数在调用的时候是通过对象方法模式来进行调用,则它内部的this就是我们的对象; 3 如果一个函数在调用的时候通过构…...
基于Resnet、LSTM、Shufflenet及CNN网络的Daily_and_Sports_Activities数据集仿真
在深度学习领域,不同的网络结构设计用于解决特定的问题。本文将详细分析四种主流网络结构:卷积神经网络(CNN)、残差网络(ResNet)、长短期记忆网络(LSTM)和洗牌网络(Shuff…...
mac系统vsCode中使用Better Comments在.vue文件里失效
问题:关于Better Comments默认在html、TS、JS中有效,在vue中无效,需要单独进行配置 windows系统可以参考友链Better Comments(注释高亮)在vue文件里失效的问题 关于Better Comments电脑的配置路径: Windows系统&…...
UE5.3 C++ Ceiusm中的POI 制作3DUI 结合坐标转化
一.核心思路WidgetComponent CesiumGloberAnchor 二.先制作POI 创建C Actor来制作,APOI。直接上代码 #pragma once#include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "CesiumGlobeAnchorComponent.h" #includ…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
