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;
}作业:多进程多线程并发服务器实

思维导图

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

初学STM32 ---高级定时器互补输出带死区控制

互补输出&#xff0c;还带死区控制&#xff0c;什么意思&#xff1f; 带死区控制的互补输出应用之H桥 捕获/比较通道的输出部分&#xff08;通道1至3&#xff09; 死区时间计算 举个栗子&#xff08;F1为例&#xff09;&#xff1a;DTG[7:0]250&#xff0c;250即二进制&#x…

brupsuite的基础用法常用模块(1)

proxy模块&#xff1a; Options: 设置代理端口&#xff0c;默认为8080端口&#xff0c;若8080端口被占用可在该界面更改代理端口. HTTP history: 拦截的历史请求&#xff0c;右键可做更多操作&#xff0c;很多操作与其他模块有关。&#xff08;清除历史的话右键选择clear p…

Linux 笔记 SELinux 常见操作与介绍

SELinux&#xff08;Security-Enhanced Linux&#xff09;是 Linux 操作系统中的一种安全模块&#xff0c;旨在提供更细粒度的访问控制。它最初由美国国家安全局&#xff08;NSA&#xff09;开发&#xff0c;目的是增强 Linux 系统的安全性。SELinux 通过强制访问控制&#xff…

Postman接口测试03|执行接口测试、全局变量和环境变量、接口关联、动态参数、断言

目录 七、Postman 1、安装 2、postman的界面介绍 八、Postman执行接口测试 1、请求页签 3、响应页签 九、Postman的环境变量和全局变量 1、创建环境变量和全局变量可以解决的问题 2、postman中的操作-全局变量 1️⃣手动设置 2️⃣代码设置 3️⃣界面获取 4️⃣代…

旅游管理系统|Java|SSM|VUE| 前后端分离

【技术栈】 1⃣️&#xff1a;架构: B/S、MVC 2⃣️&#xff1a;系统环境&#xff1a;Windowsh/Mac 3⃣️&#xff1a;开发环境&#xff1a;IDEA、JDK1.8、Maven、Mysql5.7 4⃣️&#xff1a;技术栈&#xff1a;Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5⃣️数据库…

vulhub-wordpress靶场

一.主题上传漏洞 来到靶场点击主题选择add new 这里有一个上传主题的地方 我们可以去网上找到wordpress主题下载一个 wordpress模板 网页设计模板 免费 免费下载 - 爱给网 下载完成后对我们有用的东西只有这一个目录&#xff0c;把它拖出来 点开moban目录后&#xff0c;创建…

【人工智能视角下的计算机系统:硬件、操作系统与进程管理基础】

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 电脑硬件的基本常识电脑操作系统&#xff08;软件&#xff09;的基本常识进程进程操作PCB的属性PCB…

Flink源码解析之:如何根据算法生成StreamGraph过程

Flink源码解析之&#xff1a;如何根据算法生成StreamGraph过程 在我们日常编写Flink应用的时候&#xff0c;会首先创建一个StreamExecutionEnvironment.getExecutionEnvironment()对象&#xff0c;在添加一些自定义处理算子后&#xff0c;会调用env.execute来执行定义好的Flin…

IntelliJ IDEA Docker集成

一、概述 Docker是一种用于在隔离和可复制环境中部署和运行可执行文件的工具。这可能很有用&#xff0c;例如&#xff0c;在与生产相同的环境中测试代码。 IntelliJ IDEA集成了Docker功能&#xff0c;并为创建Docker映像、运行Docker容器、管理Docker Compose应用程序、使用公…

【closerAI ComfyUI】快速洗图!高效快速的提示词反推节点——cliption,让洗图出图快人一步不爆显存!

添加图片注释,不超过 140 字(可选) 【closerAI ComfyUI】快速洗图!高效快速的提示词反推节点——cliption,让洗图出图快人一步不爆显存! 大家好,我是Jimmy。反推提示词的节点有很多,像Florence2 、Joycaption2、喵手等。都是非常优秀的。但是呢,就是占用设备资源,加…

Pandas-数据组合

文章目录 一. 连接数据1.简介2. 加载数据1. 添加行① 添加行-DataFrame连接② 添加行-DataFrame和Series连接③ 添加行-append函数④ 添加行-重置索引 2. 添加列① 添加列-concat函数② 添加列-通过dataframe[列名] [值]③ 添加列-通过dataframe[列名] Series对象④ 添加列-重…

软件架构设计——数据表状态切换开关—未来之窗行业应用跨平台架构

一、样式 二、样式 /*开关示例*/.东方仙盟_灵颜妙手 {position: relative;display: inline-block;width: 60px;height: 34px;border-radius: 17px; /* 添加圆角效果&#xff0c;使开关看起来更圆润美观 */box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); /* 添加淡淡的阴影效果&…

django --递归查询评论

表数据 树状结构 action(methods(GET, ), detailFalse) def get_info_pinglun(self, request, *args, **kwargs) -> Response:根据评论id查所有回复params wenxian_pinglun_id --> 评论id;wenxian_pinglun_id self.request.GET.get(wenxian_pinglun_id)results se…

适用于项目经理的跨团队协作实践:Atlassian Jira与Confluence集成

适用于项目经理的跨团队协作实践&#xff1a;Atlassian Jira与Confluence集成 现代项目经理的核心职责是提供可视性、保持团队一致&#xff0c;并确保团队拥有交付出色工作所需的资源。在过去几年中&#xff0c;由于分布式团队的需求不断增加&#xff0c;项目经理这一角色已迅速…

基于JAVA+SpringBoot+Vue的问卷调查系统

基于JAVASpringBootVue的问卷调查系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f345; 哈喽兄…

Vue开发环境搭建上篇:安装NVM和NPM(cpnm、pnpm)

文章目录 引言I 安装NVM1.1 Windows系统安装NVM,实现Node.js多版本管理1.2 配置下载镜像1.3 NVM常用操作命令II NPM永久使用淘宝源安装 cnpm安装pnpm【推荐】see also: vscode常用插件引言 淘宝镜像:http://npm.taobao.org 和 http://registry.npm.taobao.org 已在 2022.06.3…

Kimi进行学术方向选择精讲!

目录 1.文献搜索 2.辅助选题 3.选题判断 在我们之前的文章中&#xff0c;小编都强调了选题在文章价值中的核心作用。一篇优秀的文章背后&#xff0c;肯定有一个精心挑选的选题。选题的好坏直接影响着文章能够发表的期刊等级。许多宝子们却采取了相反的做法&#xff0c;将大量…

YOLO系列正传(五)YOLOv4论文精解(上):从CSPNet、SPP、PANet到CSPDarknet-53

系列文章 YOLO系列基础 YOLO系列基础合集——小白也看得懂的论文精解-CSDN博客 YOLO系列正传 YOLO系列正传&#xff08;一&#xff09;类别损失与MSE损失函数、交叉熵损失函数-CSDN博客 YOLO系列正传&#xff08;二&#xff09;YOLOv3论文精解(上)——从FPN到darknet-53-C…

Vulnhub靶场-Driftingblues 6靶机(至获取shell)

靶机安装好后&#xff0c;照例扫描IP 端口 目录 首页为一个图片&#xff0c;没有什么信息 访问robots.txt&#xff0c;存在一个textpattern/textpattern目录&#xff0c;我们访问为一个登录窗口&#xff0c;sqlmap无法注入 提示我们扫目录时添加.zip扩展名&#xff0c;所以我们…

基于springboot的汽车租赁系统丨源码+数据库+万字文档+PPT

作者简介&#xff1a; 作者&#xff1a;学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等 文末获取“源码数据库万字文档PPT”&#xff0c;支持远程部署调试、运行安装。 技术框架 开发语言&#xff1a;Java 框架&#xff1a;spring…