基于LinuxC语言实现的TCP多线程/进程服务器
多进程并发服务器
设计流程
框架一(使用信号回收僵尸进程)
void handler(int sig)
{while(waitpid(-1, NULL, WNOHANG) > 0);
}int main()
{//回收僵尸进程siganl(17, handler);//创建服务器监听套接字 serverserver = socket();//给服务器地址信息结构体赋值,并绑定bind();//监听指定端口,设置监听队列listen();while(1){//创建与客户端通信的套接字client = accept();//创建子进程if(fork() == 0){//关闭拷贝的服务器套接字close(server);while(1){//接收消息recv();//发送消息send();}//通信结束关闭套接字close(client);//退出进程exit(0);}//关闭父进程的通信套接字close(client);}//服务器关闭close(server);
}
实例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <time.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>#define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s);void cil(int client, struct sockaddr_in caddr);void handler(int sig)
{while(waitpid(-1, NULL, WNOHANG) > 0);
}int main(int argc, char *argv[])
{//回收僵尸进程signal(17, handler);//创建服务器int server = -1;if((server = socket(AF_INET, SOCK_STREAM, 0)) == -1){LOG("socket error");return -1;}//给服务器地址信息结构体赋值,并绑定struct sockaddr_in saddr = {0};saddr.sin_family = AF_INET;saddr.sin_port = htons(8888);saddr.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1){LOG("bind error");return -1;}//监听指定端口,设置监听队列if(listen(server, 5) == -1){LOG("listen error");return -1;}puts("Tcp server start success");int client = -1;struct sockaddr_in caddr = {0};socklen_t len = sizeof(caddr);pid_t pid = -1;while(1){//创建与客户端通信的套接字if((client = accept(server, (struct sockaddr*)&caddr, &len)) == -1){LOG("accpet error");return -1;}printf("[%s/%d] client已上线\n", inet_ntoa(caddr.sin_addr), ntohl(caddr.sin_port));//创建子进程if((pid = fork()) < 0){LOG("fork error");return -1;}else if(pid == 0){cil(client, caddr);exit(0);}close(client);}close(server);return 0;
}void cil(int client, struct sockaddr_in caddr)
{char buf[128] = "";int res = 0;while(1){bzero(buf, sizeof(buf));if((res = read(client, buf, sizeof(buf))) < 0){LOG("read error");break;}else if(res == 0){printf("[%s/%d] client已下线\n", inet_ntoa(caddr.sin_addr), ntohl(caddr.sin_port));close(client);break;}printf("[%s/%d] client: %s\n", inet_ntoa(caddr.sin_addr), ntohl(caddr.sin_port), buf);bzero(buf, sizeof(buf));strcpy(buf, "ok");if(write(client, buf, sizeof(buf)) < 0){LOG("write error");break;}}}
框架二(使用孤儿进程机制避免僵尸进程产生)
int main()
{//创建服务器监听套接字 serverserver = socket();//给服务器地址信息结构体赋值,并绑定bind();//监听指定端口,设置监听队列listen();while(1){//创建子进程if((pid = fork()) == 0){//子进程创建用于与客户端通信的clientclient = accept();//创建孙进程if(pid = fork() == 0){while(1){//孙进程负责与客户端通信recv();send();}//通信结束关闭套接字close(client);//退出进程exit(0);}//子进程else if(pid > 0){//关闭多余的文件描述符close(server);close(client);//退出子进程exit(0);}}//父进程else if(pid > 0){//回收子进程while(waitpid() == pid)}}//关闭文件描述符close(server);
}
实例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <time.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>#define LOG(s) printf("[%s] {%s:%d} %s\n", __DATE__, __FILE__, __LINE__, s);void deal_cil_msg(int client, struct sockaddr_in caddr);int main(int argc, char *argv[])
{//创建服务器socketint server = 0;if((server = socket(AF_INET, SOCK_STREAM, 0)) == -1){LOG("socket error");return -1;}//绑定服务器IP和端口号//给地址信息结构体赋值struct sockaddr_in saddr = {0};saddr.sin_family = AF_INET;saddr.sin_port = htons(8888);saddr.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1){LOG("bind error");return -1;}//监听对应的端口号if(listen(server, 5) == -1){LOG("listen error");return -1;}puts("server start success");//创建用于与客户端通信的socketstruct sockaddr_in caddr = {0};int client = 0;socklen_t asize = sizeof(caddr);pid_t pid = -1;int status = 0;while(1){//父进程只负责生儿子pid = fork();if(pid < 0){LOG("fork error");return -1;}//子进程负责创建通信socketif(pid == 0){//创建用于与客户端通信的socketif((client = accept(server, (struct sockaddr*)&caddr, &asize)) == -1){LOG("accept error");return -1;}printf("[%s/%d]client已上线\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));//孙进程负责通信pid = fork();if(pid < 0){LOG("fork error");return -1;}else if(pid == 0){deal_cil_msg(client, caddr);close(client);exit(0);}else if(pid > 0){close(server);close(client);//退出子进程exit(0);}}else if(pid > 0){printf("wait child = %d\n", pid);//父进程等待子进程结束,准备收尸while(waitpid(pid, &status, 0) == pid){printf("Parent is over - child: %d, status = %x\n", pid, status);}}}//关闭文件描述符close(server);return 0;
}void deal_cil_msg(int client, struct sockaddr_in caddr)
{//接收消息char buf[128] = " ";while(1){int len = 0;bzero(buf, sizeof(buf));if((len = recv(client, buf, sizeof(buf), 0)) < 0){ LOG("recv error");}else if(len == 0){printf("[%s/%d]client已下线\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));break;}printf("[%s/%d]client: %s\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), buf);bzero(buf, sizeof(buf));//发送消息strcpy(buf, "ok");write(client, buf, len);}}
多线程并发服务器
设计流程
//线程参数结构体
typedef struct
{int client;struct sockaddr_in caddr;
} Client_msg;int main()
{//创建服务器监听套接字 serverserver = socket();//给服务器地址信息结构体赋值,并绑定bind();//监听指定端口,设置监听队列listen();while(1){//创建用于与客户端通信的套接字client = accpet();//创建线程pthread_create();while(1){//读写//关闭文件描述符//退出线程}//解离线程pthread_detach();}//关闭文件描述符close(server);
}
实例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <time.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>#define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s);void* cil(void* arg);//线程参数结构体
typedef struct
{int client;struct sockaddr_in caddr;
} Cli_msg;int main(int argc, char *argv[])
{//创建服务器监听分套接字 serverint server = -1;if((server = socket(AF_INET, SOCK_STREAM, 0)) == -1){LOG("socket error");return -1;}//给服务器地址信息结构体赋值,并绑定struct sockaddr_in saddr = {0};saddr.sin_family = AF_INET;saddr.sin_port = htons(8899);saddr.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1){LOG("bind error");return -1;}//监听端口if(listen(server, 5) == -1){LOG("listen error");return -1;}puts("tcp server start success");struct sockaddr_in caddr = {0};socklen_t len = sizeof(caddr);pthread_t tid = -1;int client = -1;Cli_msg cli_msg;while(1){//创建用于与客户端通信的套接字 clientif((client = accept(server, (struct sockaddr*)&caddr, &len)) == -1){LOG("accept error");return -1;}printf("[%s/%d]client已上线\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));cli_msg.client = client;cli_msg.caddr = caddr;//创建线程if(pthread_create(&tid, NULL, cil, &cli_msg) != 0){LOG("pthread_create error");return -1;}pthread_detach(tid);}close(server);return 0;
}void* cil(void* arg)
{int client = ((Cli_msg*)arg)->client;struct sockaddr_in caddr = ((Cli_msg*)arg)->caddr;char buf[128] = "";int res = 0;while(1){bzero(buf, sizeof(buf));if((res = read(client, buf, sizeof(buf))) < 0){LOG("read error");break;}else if(res == 0){printf("[%s/%d]client已下线\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));close(client);pthread_exit(NULL);}printf("[%s/%d]client: %s\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), buf);bzero(buf, sizeof(buf));strcpy(buf, "ok");if(write(client, buf, sizeof(buf)) < 0){LOG("write error");break;}}}相关文章:
基于LinuxC语言实现的TCP多线程/进程服务器
多进程并发服务器 设计流程 框架一(使用信号回收僵尸进程) void handler(int sig) {while(waitpid(-1, NULL, WNOHANG) > 0); }int main() {//回收僵尸进程siganl(17, handler);//创建服务器监听套接字 serverserver socket();//给服务器地址信息…...
浅谈JVM垃圾回收机制
一、HotSpot VM中的GC分为两大类 1.部分收集(Partial GC): 新生代收集(Minor GC/Young GC):只对新生代进行垃圾收集老年代收集(Major GC/Old GC):只队老年代进行垃圾收集混合收集(Mixed GC):对整个新生代和老年代进行垃圾收集 2.整堆收集(Full GC) 收集整个Java堆和方法区 …...
【80天学习完《深入理解计算机系统》】第十二天3.6数组和结构体
专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录) 文章字体风格: 红色文字表示&#…...
基于Python+OpenCV智能答题卡识别系统——深度学习和图像识别算法应用(含Python全部工程源码)+训练与测试数据集
目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境PyCharm安装OpenCV环境 模块实现1. 信息识别2. Excel导出模块3. 图形用户界面模块4. 手写识别模块 系统测试1. 系统识别准确率2. 系统识别应用 工程源代码下载其它资料下载 前言 本项目基于Python和OpenCV图像处…...
Redis集群操作-----主从互换
一、将节点cluster1的主节点7000端口的redis关掉 [rootredis-cluster1 src]# ps -ef |grep redis 二、查看集群信息:...
肖sir __linux命令拓展__05
linux命令拓展 1.追加内容到某文件 echo “i like learn linux” >>quzhi.txt 2.删除指定的空目录: rmdir 目录名 rmdir -p 目录名 (删除指定的空目录及其内子空目录) 3.显示zip包信息 zipinfo 压缩包名 (显示压缩包内的文…...
大白菜清理电脑密码教程
首先安装大白菜: 插入u盘一键制作启动盘 制作成功,重启进入u盘启动模式...
[libglog][FFmpeg] 如何把 ffmpeg 的库日志输出到 libglog里
ffmpeg 提供了自己的 log 模块 av_log,会默认把输出打印到 stderr 上,因此无法方便地跟踪日志。但是 ffmpeg 提供了一个接口 av_log_set_callback 以供外界自定义自己的日志输出。 libglog 提供的是c 形式的日志输出样式,因此需要将二者关联起…...
【Unity-Cinemachine相机】虚拟相机(Virtual Camera)的本质与基本属性
我们可以在游戏进行时修改各个属性,但在概念上,最好将Virtual Camera 当作一种相机行为的“配置文件”,而不是一个组件。 我们的相机有几种行为就为它准备几种虚拟相机,比如角色移动就为它第三人称相机,瞄准就准备一个…...
LeetCode:718. 最长重复子数组 - Python
718. 最长重复子数组 问题描述: 给两个整数数组 nums1 和 nums2 ,返回 两个数组中 公共的 、长度最长 的 子数组 的 长度 。 示例 1: 输入:nums1 [1,2,3,2,1], nums2 [3,2,1,4,7] 输出:3 解释:长度最长…...
【面试题精讲】Redis如何实现分布式锁
首发博客地址 系列文章地址 Redis 可以使用分布式锁来实现多个进程或多个线程之间的并发控制,以确保在给定时间内只有一个进程或线程可以访问临界资源。以下是一种使用 Redis 实现分布式锁的常见方法: 获取锁: 客户端尝试使用 SETNX命令在 Re…...
list【2】模拟实现(含迭代器实现超详解哦)
模拟实现list 引言(实现概述)list迭代器实现默认成员函数operator* 与 operator->operator 与 operator--operator 与 operator!迭代器实现概览 list主要接口实现默认成员函数构造函数析构函数赋值重载 迭代器容量元素访问数据修改inserterasepush_ba…...
Nginx+Tomcat的动静分离与负载均衡
目录 前言 一、案例 二、Nginx的高级用法 三、tomcat部署 四、Nginx部署 五、测试 总结 前言 通常情况下,一个 Tomcat 站点由于可能出现单点故障及无法应付过多客户复杂多样的请求等情况,不能单独应用于生产环境下,所以我们需要一套更…...
【设计模式】Head First 设计模式——策略模式 C++实现
设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。 设计思想 将行为想象为一族算法,定义算法族…...
c#object类中方法的使用
C#中的Object类是所有类的基类,它定义了一些通用的方法和属性,可以在任何对象上使用。以下是Object类中常用的方法和属性的使用: 1.ToString():将对象转换为字符串表示形式。 string str obj.ToString();2.Equals():…...
三种常用盒子布局的方法
在Vue中,可以使用各种CSS布局属性和技巧来设置盒子的布局。以下是一些常用的方法: 1.使用Flexbox布局:在包含盒子的父元素上设置display: flex,然后可以使用flex-direction、justify-content和align-items 等属性来控制盒子的布局…...
GB28181学习(二)——注册与注销
概念 使用REGISTER方法进行注册和注销;注册和注销应进行认证,认证方式应支持数字摘要认证方式,高安全级别的宜支持数字证书认证;注册成后,SIP代理在注册过期时间到来之前,应向注册服务器进行刷新注册&…...
【Linux】线程安全-信号量
文章目录 信号量原理信号量保证同步和互斥的原理探究信号量相关函数初始化信号量函数等待信号量函数释放信号量函数销毁信号量函数 信号量实现生产者消费者模型 信号量原理 信号量的原理:资源计数器 PCB等待队列 函数接口 资源计数器:对共享资源的计…...
数字IC验证——PSS可移植测试用例
PSS是Accellera组织定义的测试用例生成规范,其思想是定义一个抽象模型,EDA工具可以从中生成适用于每个设计层次结构和每个验证平台的测试,即PSS定义了统一的测试场景,而场景的使用可以横跨不同验证层次和配置。 这种特性决定了PSS…...
java设计模式---策略模式
策略模式的定义 策略设计模式是一种行为设计模式。当在处理一个业务时,有多种处理方式,并且需要再运行时决定使哪一种具体实现时,就会使用策略模式。 策略模式的类图: 策略模式的实现 在支付业务中,有三种付款方式&…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...
0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化
是不是受够了安装了oracle database之后sqlplus的简陋,无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话,配置.bahs_profile后也能解决上下翻页这些,但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可,…...
【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL
ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...
