基于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设计模式---策略模式
策略模式的定义 策略设计模式是一种行为设计模式。当在处理一个业务时,有多种处理方式,并且需要再运行时决定使哪一种具体实现时,就会使用策略模式。 策略模式的类图: 策略模式的实现 在支付业务中,有三种付款方式&…...

5-redis集群搭建安装
1.先决条件 1.1.OS基础配置 CentOS为了能够正常安装redis,需要对CentOS进行常规的一些基础配置,主要有:关闭防火墙与selinux,设置主机名,配置虚拟机IP地址使其能够与外网ping通,配置IP地址与主机名映射,配置yum源。具体配置参见: Linux常规基础配置_小黑要上天的博客…...

(数字图像处理MATLAB+Python)第十一章图像描述与分析-第七、八节:纹理描述和其他描述
文章目录 一:纹理描述(1)联合概率矩阵法A:定义B:基于联合概率矩阵的特征C:程序 (2)灰度差分统计法A:定义B:描述图像特征的参数 (3)行程…...

MySQL提权
参考: mysql提权篇 | Wh0ales Blog MySQL 提权方法整理 - Geekbys Blog MySQL_UDF提权漏洞复现-云社区-华为云 MYSQL UDF手动提权及自动化工具使用_udf提权工具_小直789的博客-CSDN博客 MySQL提权的三种方法 - FreeBuf网络安全行业门户 ......

FPGA优质开源项目 – UDP万兆光纤以太网通信
本文开源一个FPGA项目:UDP万兆光通信。该项目实现了万兆光纤以太网数据回环传输功能。Vivado工程代码结构和之前开源的《UDP RGMII千兆以太网》类似,只不过万兆以太网是调用了Xilinx的10G Ethernet Subsystem IP核实现。 下面围绕该IP核的使用、用户接口…...

如何中mac上安装多版本python并配置PATH
摘要 mac 默认安装的python是 python3,但是如果我们需要其他python版本时,该怎么办呢? 例如:需要python2 版本,如果使用homebrew安装会提示没有python2。同时使用python --version 会发现commond not found。 所以本…...

window 常用基础命令
0、起步 0-1) 获取命令的参数指引 netstat /? 0-2) 关于两个斜杠: window 文件路径中使用反斜杠:\ linux 文件路径中使用:/ 1、开关机类指令 shutdown /s # 关机shutdown /r # 重启shutdown /l …...

lintcode 1815 · 警报器 【simple vip 前缀和数组】
题目 https://www.lintcode.com/problem/1815 一个烟雾警报器会监测len秒内的烟雾值,如果这段时间烟雾值平均值大于k那么警报器会报警。现在给你n个数代表刚开始工作n秒内警报器监测的烟雾值(警报器从第len秒开始判断是否报警),…...

【强化学习】MDP马尔科夫链
基本元素 状态集:表示智能体所处所有状态的全部可能性的集合。类似的集合,行为集,回报集决策:规定我在某个状态下,我做出某个action马尔可夫链:学术上来说是无记忆性质。说白了就是我只在乎我目前的状态。…...

SpringBoot自写项目记录
设置静态资源映射 Slf4j 用来打印日志 Configuration Slf4j //设置静态资源映射 public class WebMvcConfig extends WebMvcConfigurationSupport {Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {log.info("开始静态资源配置");r…...

Windows10上使用llama-recipes(LoRA)来对llama-2-7b做fine-tune
刚刚在Windows10上搭建环境来对llama2做finetune,里面坑还是挺多的,这里把印象中的坑整理了一下以作备忘。 llama-recipes是meta的开源项目,Github地址为:GitHub - facebookresearch/llama-recipes: Examples and recipes for Ll…...