分别通过select、多进程、多线程实现一个并发服务器
多进程
#include<myhead.h>#define PORT 8888 //端口号
#define IP "192.168.114.74" //IP地址//定义函数处理客户端信息
int deal_cli_msg(int newfd, struct sockaddr_in cin)
{//5、收发数据使用newfd完成通信char buf[128] = "";while(1){//清空字符串bzero(buf, sizeof(buf));//read(newfd, buf, sizeof(buf)); //从套接字中读取客户端发来的消息int res = recv(newfd, buf, sizeof(buf), 0); //从套接字中读取客户端发来的消息//buf[strlen(buf)-1] = '\0';//判断收到的结果if(res == 0){printf("客户端已经下线\n");break;}else if(res < 0){perror("recv error");return -1;}printf("[%s:%d]:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);//将读取的信息,加上一些字符发送回去strcat(buf, "*_*");send(newfd, buf, sizeof(buf), 0); }close(newfd); //关闭通信的套接字return 0;
}//定义信号处理函数
void handler(int signo)
{if(signo == SIGCHLD){while(waitpid(-1, NULL, WNOHANG) > 0); //非阻塞形式回收僵尸进程}
}int main(int argc, const char *argv[])
{//1、创建用于接受连接的套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd == -1){perror("socket error");return -1;}printf("socket success sfd = %d\n", sfd); //4//设置端口号快速重用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1){perror("setsockopt error");return -1;}printf("设置端口快速重用成功 _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//2、绑定IP地址和端口号//2.1、填充要绑定的地址信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET; //表明是ipv4sin.sin_port = htons(PORT); //端口号sin.sin_addr.s_addr = inet_addr(IP); //IP地址//2.2、绑定if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin))==-1){perror("bind error");return -1;}printf("bind success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//3、将套接字设置成被动监听状态if(listen(sfd, 128) == -1){perror("listen error");return -1;}printf("listen success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//4、阻塞等待客户端连接请求,如果有新的客户端连接,则创建一个新的用于通信的套接字//4.1、定义客户端地址信息结构体struct sockaddr_in cin; //客户端地址信息结构体cin.sin_family = AF_INET;socklen_t socklen = sizeof(cin); //客户端地址信息的大小//定义子进程变量pid_t pid;//将SIGCHLD信号绑定到自定义信号处理函数中if(signal(SIGCHLD, handler) == SIG_ERR){perror("signal error");return -1;}while(1){ //4.2、阻塞接收客户端的链接请求,并且获取客户端的地址信息int newfd = accept(sfd, (struct sockaddr*)&cin, &socklen);if(newfd == -1){perror("accept error");return -1;}printf("accept success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//创建子进程,让子进程完成通信pid = fork();if(pid > 0){//关闭newfd,父进程不用close(newfd);}else if(pid == 0){ //对于子进程而言,sfd是没有用的,需要关闭close(sfd);//调用处理客户端函数、deal_cli_msg(newfd, cin);//退出子进程exit(EXIT_SUCCESS);}else{perror("fork error");return -1;}}//6、关闭所有套接字close(sfd); //关闭监听return 0;
}
多线程
#include<myhead.h>#define PORT 8888 //端口号
#define IP "192.168.114.74" //IP地址//定义用于向线程体传参的结构体类型
struct msg_info
{int newfd;struct sockaddr_in cin;
};//定义线程体函数
void *deal_cli_msg(void *arg)
{//获取主线程传递的信息int newfd = ((struct msg_info*)arg) -> newfd;struct sockaddr_in cin = ((struct msg_info*)arg) -> cin;//5、收发数据使用newfd完成通信char buf[128] = "";while(1){//清空字符串bzero(buf, sizeof(buf));//read(newfd, buf, sizeof(buf)); //从套接字中读取客户端发来的消息int res = recv(newfd, buf, sizeof(buf), 0); //从套接字中读取客户端发来的消息//buf[strlen(buf)-1] = '\0';//判断收到的结果if(res == 0){printf("客户端已经下线\n");break;}else if(res < 0){perror("recv error");return NULL;}printf("[%s:%d]:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);//将读取的信息,加上一些字符发送回去strcat(buf, "*_*");send(newfd, buf, sizeof(buf), 0); }close(newfd); //关闭通信的套接字ptread_exit(NULL); //退出线程}int main(int argc, const char *argv[])
{//1、创建用于接受连接的套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd == -1){perror("socket error");return -1;}printf("socket success sfd = %d\n", sfd); //4//设置端口号快速重用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1){perror("setsockopt error");return -1;}printf("设置端口快速重用成功 _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//2、绑定IP地址和端口号//2.1、填充要绑定的地址信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET; //表明是ipv4sin.sin_port = htons(PORT); //端口号sin.sin_addr.s_addr = inet_addr(IP); //IP地址//2.2、绑定if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin))==-1){perror("bind error");return -1;}printf("bind success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//3、将套接字设置成被动监听状态if(listen(sfd, 128) == -1){perror("listen error");return -1;}printf("listen success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//4、阻塞等待客户端连接请求,如果有新的客户端连接,则创建一个新的用于通信的套接字//4.1、定义客户端地址信息结构体struct sockaddr_in cin; //客户端地址信息结构体cin.sin_family = AF_INET;socklen_t socklen = sizeof(cin); //客户端地址信息的大小while(1){//4.2、阻塞接收客户端的链接请求,并且获取客户端的地址信息int newfd = accept(sfd, (struct sockaddr*)&cin, &socklen);if(newfd == -1){perror("accept error");return -1;}printf("accept success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//定义用于向线程体传参的结构体变量struct msg_info info = {newfd, cin};//创建分支线程用于通信pthread_t tid;if(pthread_create(&tid, NULL, deal_cli_msg, &info) != 0){printf("分支线程创建失败\n");return -1;}//将该线程分离if(pthread_detach(tid) != 0){printf("分离失败\n");return -1;}}//6、关闭所有套接字close(sfd); //关闭监听return 0;
}
select
#include<myhead.h>#define PORT 8888 //端口号
#define IP "192.168.114.142" //IP地址int main(int argc, const char *argv[])
{//1、创建用于接受连接的套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd == -1){perror("socket error");return -1;}printf("socket success sfd = %d\n", sfd); //4//设置端口号快速重用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1){perror("setsockopt error");return -1;}printf("设置端口快速重用成功 _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//2、绑定IP地址和端口号//2.1、填充要绑定的地址信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET; //表明是ipv4sin.sin_port = htons(PORT); //端口号sin.sin_addr.s_addr = inet_addr(IP); //IP地址//2.2、绑定if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin))==-1){perror("bind error");return -1;}printf("bind success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//3、将套接字设置成被动监听状态if(listen(sfd, 128) == -1){perror("listen error");return -1;}printf("listen success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//4、阻塞等待客户端连接请求,如果有新的客户端连接,则创建一个新的用于通信的套接字//4.1、定义客户端地址信息结构体struct sockaddr_in cin; //客户端地址信息结构体cin.sin_family = AF_INET;socklen_t socklen = sizeof(cin); //客户端地址信息的大小定义一个用于检测文件描述符的集合fd_set readfds, tempfds; //在栈区定义清空容器中的内容FD_ZERO(&readfds);将要检测的文件描述符放入集合中FD_SET(sfd, &readfds); //将sfd文件描述符放入FD_SET(0, &readfds); //将0号文件描述符放入//定义一个容器char buf[128] = "";int res = 0; //接收select的返回值int newfd = -1; //存放用于最新连接客户端的套接字int maxfd = sfd; //定义控制select函数中最大文件描述符struct sockaddr_in saveCin[1024]; //用于存放客户端地址信息结构体while(1){将集合内容复制一份tempfds = readfds;使用select阻塞等待集合中的文件描述符有事件产生res = select(maxfd+1, &tempfds, NULL, NULL, NULL);if(res == -1){perror("select error");return -1;}else if(res == 0){printf("time out\n");return -1;}//遍历所有集合中文件描述符for(int i=0; i<=maxfd; i++){//判断当前i是否在集合中,如果不在,直接判断下一个if(!FD_ISSET(i, &tempfds)){continue;}判断sfd是否还在集合中if( i == sfd){//4.2、阻塞接收客户端的链接请求,并且获取客户端的地址信息newfd = accept(sfd, (struct sockaddr*)&cin, &socklen);if(newfd == -1){perror("accept error");return -1;}printf("accept success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);将newfd放入readfds中FD_SET(newfd , &readfds);//更新maxfdif(newfd > maxfd){maxfd = newfd;}//将最新的客户端套接字放入数组的下标为new的位置saveCin[newfd] = cin;printf("newfd = %d\n", newfd);}else if(i == 0 ) //判断是否是终端输入{char buf1[128] = "";bzero(buf, sizeof(buf));//从终端获取数据fgets(buf, sizeof(buf), stdin); //从终端获取数据buf[strlen(buf)-1]='\0';printf("触发终端输入事件:%s\n", buf);sprintf(buf1, "%s%s", "系统消息:", buf);//将数据发送给所有客户端for(int j=4; j<=maxfd; j++){send(j, buf1,sizeof(buf1), 0);}}else{//5、收发数据使用newfd完成通信char buf[128] = "";//清空字符串bzero(buf, sizeof(buf));int ret = recv(i, buf, sizeof(buf), 0); //从套接字中读取客户端发来的消息//判断收到的结果if(ret == 0){printf("客户端已经下线\n"); close(i); //关闭通信的套接字将当前的文件描述符从集合中删除FD_CLR(i, &readfds);更新maxfdfor(int j=maxfd; j>=0; j--){//判断当前的j是否在集合中,如果在,则为maxfdif(FD_ISSET(j, &readfds)){maxfd = j;break;}}continue; //继续判断下一个}else if(ret < 0){perror("recv error");return -1;}printf("[%s:%d]:%s\n", inet_ntoa(saveCin[i].sin_addr), ntohs(saveCin[i].sin_port), buf);//将读取的信息,加上一些字符发送回去strcat(buf, "*_*");send(i, buf, sizeof(buf), 0); }}}//6、关闭所有套接字close(sfd); //关闭监听return 0;
}
相关文章:
分别通过select、多进程、多线程实现一个并发服务器
多进程 #include<myhead.h>#define PORT 8888 //端口号 #define IP "192.168.114.74" //IP地址//定义函数处理客户端信息 int deal_cli_msg(int newfd, struct sockaddr_in cin) {//5、收发数据使用newfd完成通信char buf[128] "&qu…...
如何在 emacs 上开始使用 Tree-Sitter (archlinux)
文章目录 如何在emacs上开始使用Tree-Sitter(archlinux) 如何在emacs上开始使用Tree-Sitter(archlinux) 在archlinux上使用比windows上不知道要方便多少倍! $ sudo pacman -S emacs $ sudo pacman -S tree-sitter这里…...
FL Studio2024最新中文版有哪些其新功能特点?
除了之前提到的特点外,FL Studio 21还有以下一些值得注意的特点: 高效的音频处理:FL Studio 21具备高效的音频处理能力,能够实时处理多轨道音频,提供低延迟的音频播放和录制,确保音乐制作过程中的流畅性和实…...
Oracle的学习心得和知识总结(三十二)|Oracle数据库数据库回放功能之论文四翻译及学习
目录结构 注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下: 1、参考书籍:《Oracle Database SQL Language Reference》 2、参考书籍:《PostgreSQL中文手册》 3、EDB Postgres Advanced Server User Gui…...
系统架构27 - 软件架构设计(6)
基于架构的软件开发方法 基于架构的软件开发方法(ABSD)概述概念与术语开发模型体系结构需求体系结构设计体系结构文档化体系结构复审体系结构实现体系结构的演化 基于架构的软件开发方法(ABSD) 基于体系结构的软件设计 (Architec…...
STM32 cubemx配置DMA+空闲中断接收不定长数据
文章目录 前言一、串口空闲中断二、DMA空闲中断接收不定长数据实现思路三、STM32Cubemx配置DMA空闲中断接收不定长数据四、代码编写总结 前言 本篇文章给大家讲解一下DMA串口空闲中断接收串口不定长数据,之前我们也是讲解过串口接收不定长数据的,那么本…...
Pycharm配置运行selenium教程
一、下载chrome浏览器和同版本的chromedriver chrome测试版版本120.0.6099.109 链接:https://pan.baidu.com/s/1pvFqL0WN8OkqPmURAs83kg?pwdvtsh 提取码:vtsh chromedriver版本120.0.6099.109 链接:https://pan.baidu.com/s/16fWWkrlD5C3J…...
银河麒麟V10开机后黑屏解决方法
情况描述: 单位的国产化电脑采用银河麒麟V10系统,在使用了近两个月时间后,开机到加载桌面那一步无法加载图形化桌面。 原理讲解 Linux本是纯命令行形式的系统,银河麒麟基于Linux中的Ubuntu LTS内核开发,其图形化的品牌…...
【Git版本控制 02】分支管理
目录 一、创建分支 二、切换分支 三、合并分支 四、删除分支 五、合并冲突 六、分支策略 七、bug分支 一、创建分支 # 当前仓库只有 master 一个主分支 # 可通过 git branch 是进行分支管理的命令,可通过不同参数对分支进行查看、创建、删除(base) [rootloc…...
基金分类
一、按基金运作方式分类 (一)封闭式基金 是基金份额总额在期限内固定不变,在期限内不可申购和赎回。 (二)开放式基金 是基金份额总额不固定,在期限内可以申购和赎回。 这里的开放式基金特指传统的开放式基…...
kali系统概述、nmap扫描应用、john破解密码、抓包概述、以太网帧结构、抓包应用、wireshark应用、nginx安全加固、Linux系统加固
目录 kali nmap扫描 使用john破解密码 抓包 封装与解封装 网络层数据包结构 TCP头部结构编辑 UDP头部结构 实施抓包 安全加固 nginx安全 防止缓冲区溢出 Linux加固 kali 实际上它就是一个预安装了很多安全工具的Debian Linux [rootmyhost ~]# kali resetkali …...
Spring Cloud 路由和消息传递 (HTTP 路由)
Spring Cloud 路由 Spring Cloud 路由是指将请求路由到特定服务的机制。Spring Cloud 提供了多种路由机制,包括: Ribbon: 一个基于 HTTP 和 TCP 的客户端负载均衡工具,提供软负载均衡、故障转移等功能。Feign: 一个声明式的 HTTP 客户端&am…...
【PyQt】12-滑块、计数控件
文章目录 前言一、滑块控件 QSlider运行结果 二、计数器控件 QSpinBox运行结果 总结 前言 1、滑块控件 2、计数控件 一、滑块控件 QSlider #Author :susocool #Creattime:2024/2/15 #FileName:28-滑块控件 #Description: 通过滑块选择字体大小 import sys from PyQ…...
【牛客面试必刷TOP101】Day21.BM11 链表相加(二)和BM12 单链表的排序
作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:牛客面试必刷TOP101 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!&…...
疑似针对安全研究人员的窃密与勒索
前言 笔者在某国外开源样本沙箱平台闲逛的时候,发现了一个有趣的样本,该样本伪装成安全研究人员经常使用的某个渗透测试工具的破解版压缩包,对安全研究人员进行窃密与勒索双重攻击,这种双重攻击的方式也是勒索病毒黑客组织常用的…...
Mamba-UNet:用于医学图像分割的类似UNet的纯视觉Mamba网络
摘要 在医学图像分析的最新进展中,卷积神经网络(CNN)和视觉转换器(ViT)都取得了显著的基准成绩。前者通过其卷积操作在捕获局部特征方面表现出色,而后者则通过利用自注意力机制实现了出色的全局上下文理解。然而,这两种架构在有效建模医学图像中的长距离依赖关系时都存…...
2024/2/14
1.1、若有下面的变量定义,以下语句中合法的是( A )。 int i,a[10],*p; A) pa2; B) pa[5]; C) pa[2]2; D) p&(i2); 1.2、有以下程序 …...
跟廖雪峰老师学习Git(持续更新)
Git简介 创建版本库 第一步,创建一个新目录 第二步,通过git init变成Git可以管理的仓库 把文件添加到文本库,不要使用Windows自带的记事本! 我用的是VS code 创建readme.txt 放入库中 commit可以一次提交很多文件࿰…...
2024,欢迎来到性价比时代
「不是XX买不起,而是YY更有性价比。」——翻开过去一年的商业消费史,这句话几乎可以贯穿始终。年轻消费者们追求性价比的眼光一旦定型,一些品牌过去被品质生活、消费升级包装出来的华丽外壳,很容易一击就碎。 胜出的「性价比之王…...
【国产MCU】-CH32V307-通用定时器(GPTM)-输入捕获模式测量脉冲
通用定时器(GPTM)-输入捕获模式测量脉冲 文章目录 通用定时器(GPTM)-输入捕获模式测量脉冲1、通用定时器(GPTM)介绍2、输入捕获模式3、驱动API介绍4、定时器输入捕获示例CH32V307的通用定时器模块包含一个16 位可自动重装的定时器(TIM2、TIM3、TIM4和TIM5),用于测量脉…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...
CSS3相关知识点
CSS3相关知识点 CSS3私有前缀私有前缀私有前缀存在的意义常见浏览器的私有前缀 CSS3基本语法CSS3 新增长度单位CSS3 新增颜色设置方式CSS3 新增选择器CSS3 新增盒模型相关属性box-sizing 怪异盒模型resize调整盒子大小box-shadow 盒子阴影opacity 不透明度 CSS3 新增背景属性ba…...
