Webserver(4.4)多进程/多线程实现并发服务器

ops/2024/11/13 15:34:36/

目录

多进程实现并发服务器

要实现TCP服务器处理并发的任务,使用多线程或者多进程来解决
一个父进程,多个子进程
父进程负责等待并接受客户端的连接
子进程:完成通信,接收一个客户端连接,就创建一个子进程用于通信

#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<wait.h>
#include<errno.h>void recyleChild(int arg){while(1){int ret=waitpid(-1,NULL,WNOHANG);if(ret==-1){//所有子进程都回收了break;}else if(ret==0){//还有子进程活着break;}else if(ret>0){//被回收了printf("子进程 %d 被回收了\n",ret);}}
}
int main(){struct sigaction act;act.sa_flags=0;sigemptyset(&act.sa_mask);act.sa_handler=recyleChild;//注册信号捕捉sigaction(SIGCHLD,&act,NULL);//创建socketint lfd=socket(PF_INET,SOCK_STREAM,0);if(lfd==-1){perror("socket");exit(-1);}struct sockaddr_in saddr;saddr.sin_family=AF_INET;saddr.sin_port=htons(9999);saddr.sin_addr.s_addr=INADDR_ANY;//绑定int ret=bind(lfd,(struct sockaddr *)&saddr,sizeof(saddr));if(ret==-1){perror("bind");exit(0);}//监听ret=listen(lfd,128);if(ret==-1){perror("listen");exit(-1);}//不断循环,等待客户端连接while(1){struct sockaddr_in cliaddr;int len=sizeof(cliaddr);//接受连接int cfd=accept(lfd,(struct sockaddr*)&cliaddr,&len);if(cfd==-1){if(errno==EINTR){continue;}perror("accept");exit(-1);}//每一个连接进来,创建一个子进程跟客户端通信pid_t pid=fork();if(pid==0){//子进程//获取客户端的信息char cliIp[16];inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,cliIp,sizeof(cliIp));unsigned short cliPort=ntohs(cliaddr.sin_port);printf("client ip is:%s,port is %d\n",cliIp,cliPort);//接收客户端发来的数据char recvBuf[1024]={0};while(1){int len=read(cfd,&recvBuf,sizeof(recvBuf));if(len==-1){perror("read");exit(-1);}else if(len>0){printf("recv client data:%s\n",recvBuf);}else {printf("client close...");break;}write(cfd,recvBuf,strlen(recvBuf));}close(cfd);exit(0);//退出当前子进程}}close(lfd);return 0;
}
#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>int main(){//1.创建套接字int fd=socket(AF_INET,SOCK_STREAM,0);if(fd==-1){perror("socket");exit(-1);}//2.连接服务器struct sockaddr_in serveraddr;serveraddr.sin_family=AF_INET;inet_pton(AF_INET,"192.168.227.129",&serveraddr.sin_addr.s_addr);serveraddr.sin_port=htons(9999);int ret=connect(fd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));if(ret==-1){perror("connect");exit(-1);}char recvBuf[1024]={0};int i=0;//3.通信while(1){sprintf(recvBuf,"data:%d\n",i++);//给服务器发送数据write(fd,recvBuf,strlen(recvBuf));sleep(1);int len=read(fd,recvBuf,sizeof(recvBuf));if(len==-1){perror("read");exit(-1);}else if(len>0){printf("recv server data:%s\n",recvBuf);}else if(len==0){//表示客户端断开连接printf("server closed...");break;}}//关闭连接close(fd);return 0;
}

在这里插入图片描述
同时开启两个客户端,会交叉接收信息

在这里插入图片描述
这样就支持了并发,多个客户端

多线程实现并发服务器

#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include<errno.h>struct sockInfo{int fd;//通信的文件描述符struct sockaddr_in addr;pthread_t tid;//线程号
};struct sockInfo sockinfos[128];void * working(void * arg){//子线程和客户端通信//获取客户端的信息struct sockInfo * pinfo =(struct sockInfo *)arg;char cliIp[16];inet_ntop(AF_INET,&pinfo->addr.sin_addr.s_addr,cliIp,sizeof(cliIp));unsigned short cliPort=ntohs(pinfo->addr.sin_port);printf("client ip is:%s,port is %d\n",cliIp,cliPort);//接收客户端发来的数据char recvBuf[1024];while(1){int len=read(pinfo->fd,&recvBuf,sizeof(recvBuf));if(len==-1){perror("read");exit(-1);}else if(len>0){printf("recv client data:%s\n",recvBuf);}else if(len==0) {printf("client closed...\n");break;}write(pinfo->fd,recvBuf,strlen(recvBuf)+1);}close(pinfo->fd);return NULL;
}
int main(){//创建socketint lfd=socket(PF_INET,SOCK_STREAM,0);if(lfd==-1){perror("socket");exit(-1);}struct sockaddr_in saddr;saddr.sin_family=AF_INET;saddr.sin_port=htons(9999);saddr.sin_addr.s_addr=INADDR_ANY;//绑定int ret=bind(lfd,(struct sockaddr *)&saddr,sizeof(saddr));if(ret==-1){perror("bind");exit(0);}//监听ret=listen(lfd,128);if(ret==-1){perror("listen");exit(-1);}//初始化数据int max=sizeof(sockinfos)/sizeof(sockinfos[0]);for(int i=0;i<max;i++){bzero(&sockinfos[i],sizeof(sockinfos[i]));sockinfos[i].fd=-1;sockinfos[i].tid=-1;}//循环等待客户端连接while(1){struct sockaddr_in cliaddr;int len=sizeof(cliaddr);//接受连接int cfd=accept(lfd,(struct sockaddr*)&cliaddr,&len);struct sockInfo * pinfo;for(int i=0;i<max;i++){//从这个数组中找到一个可以用的sockInfo元素if(sockinfos[i].fd==-1){pinfo=&sockinfos[i];break;}if(i==max-1){sleep(1);i--;}}pinfo->fd=cfd;memcpy(&pinfo->addr,&cliaddr,len);//创建子线程pthread_create(&pinfo->tid,NULL,working,pinfo);pthread_detach(pinfo->tid);}close(lfd);return 0;
}
#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>int main(){//1.创建套接字int fd=socket(AF_INET,SOCK_STREAM,0);if(fd==-1){perror("socket");exit(-1);}//2.连接服务器struct sockaddr_in serveraddr;serveraddr.sin_family=AF_INET;inet_pton(AF_INET,"192.168.227.129",&serveraddr.sin_addr.s_addr);serveraddr.sin_port=htons(9999);int ret=connect(fd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));if(ret==-1){perror("connect");exit(-1);}char recvBuf[1024]={0};int i=0;//3.通信while(1){sprintf(recvBuf,"data:%d\n",i++);//给服务器发送数据write(fd,recvBuf,strlen(recvBuf));int len=read(fd,recvBuf,sizeof(recvBuf));if(len==-1){perror("read");exit(-1);}else if(len>0){printf("recv server data:%s\n",recvBuf);}else if(len==0){//表示客户端断开连接printf("server closed...\n");break;}sleep(1);}//关闭连接close(fd);return 0;
}

在这里插入图片描述

TCP状态转换


http://www.ppmy.cn/ops/132698.html

相关文章

qt配合映美精取图开发

最近开发一个项目&#xff0c;用映美精相机配合halcon做取图开发&#xff0c;由于网上资料小特意写个记录。到映美精官网下载驱动&#xff0c;映美精官网&#xff0c;下载映美精的工具开发包SDK 映美精的SDK下载SDK后找到classlib文件夹 里面就是SDK新建一个qt程序&#xff0c…

安全编码实践:反射API的“间谍游戏”

在编程的世界里&#xff0c;反射API就像是一把双刃剑&#xff0c;它既强大又危险。它能让你的代码像007一样灵活多变&#xff0c;但稍不留神&#xff0c;就可能引发安全危机。今天&#xff0c;我们就来聊聊如何在这场“间谍游戏”中&#xff0c;安全地使用反射API进行数据操作。…

JAVA-顺序表ArrayList(实现ArrayList)

1.线性表 线性表 &#xff08; linear list &#xff09; 是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线。…

设计模式-七个基本原则之一-开闭原则 + SpringBoot案例

开闭原则:(SRP) 面向对象七个基本原则之一 对扩展开放&#xff1a;软件实体&#xff08;类、模块、函数等&#xff09;应该能够通过增加新功能来进行扩展。对修改关闭&#xff1a;一旦软件实体被开发完成&#xff0c;就不应该修改它的源代码。 要看实际场景&#xff0c;比如组内…

(自用复习题)常微分方程08

题目来源 常微分方程(第四版) (王高雄,周之铭,朱思铭,王寿松) 高等教育出版社 书中习题4.1 对应知识 非齐次线性微分方程 3.已知齐次线性微分方程的基本解组 x 1 , x 2 x_1,x_2 x1​,x2​&#xff0c;求下列方程对应的非齐次线性微分方程的通解 三道题都是常数变易法 (1)…

PHP常用的安全函数作用

在PHP开发中&#xff0c;安全是非常重要的一个方面。以下是一些常用的PHP安全函数及其作用&#xff1a; 这些函数和方法有助于提升PHP应用的安全性&#xff0c;但安全是一个综合性的问题&#xff0c;需要综合使用多种手段&#xff0c;如输入验证、输出编码、会话管理、错误处理…

最长公共子序列python

一、问题描述 一个序列的子序列是在该序列中删去若干元素后得到的序列。例:“ABCD”和“BDF”都是“ABCDEFG”的子序列。 最长公共子序列(LCS)问题:给定两个序列X和Y&#xff0c;求X和Y长度最大的公共子序列 例:X"ABBCBDE" Y"DBBCDB" LCS(X,Y)"BB…

PySide6百炼成真(6)

布局控件 布局用处的介绍 常用的三种布局 垂直布局水平布局格子布局 项目&#xff1a;使用格子布局重新制作一个计算器 项目&#xff1a;重新制作进制转换器 其实还有一种布局QFormLayout但是后期开发用的比较少 from PySide6.QtWidgets import QApplication, QWidget, QVB…