Linux学习之网络编程3(高并发服务器)

写在前面

Linux网络编程我是看视频学的,Linux网络编程,看完这个视频大概网络编程的基础差不多就掌握了。这个系列是我看这个Linux网络编程视频写的笔记总结。


高并发服务器

问题:

根据上一个笔记,我们可以写出一个简单的服务端和客户端通信,但是我们发现一个问题——服务器只能连接一个客户端。然而在实际生活中,我们发现一个服务器连接的客户端远远不止一个,所以我们就要做一个高并发服务器。

解决方法:

回看之前的代码,之所以只能一对一通信,是因为服务器只有一次执行accept的机会,一旦建立连接成功,就会去进行通信处理业务,而其他想要建立连接的服务器就没办法建立连接。因此我们想到在Linux系统编程中学的进程和线程,我们可以让父进程(主线程)去监听,一定有客户端请求建立连接,我们就创建子进程(其他线程)去和客户端建立连接进行通信,父进程(主线程)继续监听。


多进程并发服务器

思路(步骤):

  1. 前期准备工作:
    • 先用socket()生成一个套接字lfd用来监听
    • bind()对第一步生成的套接字绑定地址结构(绑的是服务器的地址结构)
    • listen()函数设置lfd的监听上限,最大是128.
  2. 进入循环,accept与客户端建立连接,得到用于通信的套接字的文件描述符cfd
  3. fork()创建子进程
  4. 对于父进程,由于父进程只是监听,不需要与客户端进行通信,所以我们就关闭cfd,注册信号捕捉函数,用来回收子进程,然后一直循环监听。
  5. 对于子进程,由于子进程只是进行通信,不需要监听,所以我们就关闭lfd,然后就与客户端进行通信,处理业务。

源代码:

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>	
#include<signal.h>#define PORT 6666void sys_err(char* str)
{perror(str);exit(-1);
}void wait_child(int signum)		//信号捕捉,回收子进程
{while((waitpid(0,NULL,WNOHANG))>0);
//	if(waitpid(0,NULL,0)!=-1)
//		printf("disconnect a client successfully\n");return;
}int main()
{struct sockaddr_in addr_s,addr_c;socklen_t addr_c_len=sizeof addr_c;int lfd,cfd,res,n;pid_t pid;struct sigaction act;char buf[BUFSIZ],client_IP[1024];lfd=socket(AF_INET,SOCK_STREAM,0);if(lfd<0)sys_err("socket error");addr_s.sin_family=AF_INET;addr_s.sin_port=htons(PORT);addr_s.sin_addr.s_addr=htonl(INADDR_ANY);res=bind(lfd,(struct sockaddr*)&addr_s,sizeof addr_s);if(res==-1)sys_err("bind error");res=listen(lfd,128);if(res==-1)sys_err("listen error");while(1){cfd=accept(lfd,(struct socket*)&addr_c,&addr_c_len);pid=fork();			//创建子进程if(pid==0)			//子进程{close(lfd);		//打印客户端的IP和端口号,可以省略printf("connect successfully,client IP:%s,port:%d\n",inet_ntop(AF_INET,&addr_c.sin_addr.s_addr,&client_IP,sizeof client_IP),ntohs(addr_c.sin_port));break;}else if(pid>0){close(cfd);act.sa_handler=wait_child;sigemptyset(&act.sa_mask);act.sa_flags=0;sigaction(SIGCHLD,&act,NULL);continue;}}if(pid==0)		//父进程{while(1){n=read(cfd,buf,sizeof buf);for(int i=0;i<n;i++)buf[i]=toupper(buf[i]);write(cfd,buf,n);write(STDOUT_FILENO,buf,n);}}close(cfd);close(lfd);return 0;
}

效果

1


多线程并发服务器

思路(步骤):

  1. 前期准备工作:
    • 先用socket()生成一个套接字lfd用来监听
    • bind()对第一步生成的套接字绑定地址结构(绑的是服务器的地址结构)
    • listen()函数设置lfd的监听上限,最大是128.
  2. 进入循环,accept与客户端建立连接,得到用于通信的套接字的文件描述符cfd
  3. 创建子线程
  4. 对于子线程,由于子线程只是进行通信,不需要监听,所以我们就关闭lfd,然后就与客户端进行通信,处理业务。
  5. 对于父进程,由于父线程只是监听,不需要与客户端进行通信,所以我们就关闭cfd,然后设置线程pthread_detach()分离或者使用pthread_join()回收子线程。

源代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<pthread.h>#define PORT 6666void sys_err(char* str)
{perror(str);exit(-1);
}void* fun(void* arg)
{int cfd=(int) arg,n;char buf[BUFSIZ];while(1){n=read(cfd,buf,sizeof buf);if(n==0){printf("one client closed......\n");break;}for(int i=0;i<n;i++)buf[i]=toupper(buf[i]);write(cfd,buf,n);write(STDOUT_FILENO,buf,n);}close(cfd);return NULL;
}int main()
{struct sockaddr_in addr_s,addr_c;socklen_t addr_c_len=sizeof addr_c;char c_IP[1024];int lfd,cfd,res;pthread_t tid;addr_s.sin_family=AF_INET;addr_s.sin_port=htons(PORT);addr_s.sin_addr.s_addr=htonl(INADDR_ANY);lfd=socket(AF_INET,SOCK_STREAM,0);if(lfd<0)sys_err("socket errro");res=bind(lfd,(struct sockaddr*)&addr_s,sizeof addr_s);if(res<0)sys_err("bind error");res=listen(lfd,128);	if(res<0)sys_err("listen error");printf("accepting connect........\n");while(1){cfd=accept(lfd,(struct sockaddr*)& addr_c,&addr_c_len);if(cfd==-1)sys_err("accept error");printf("connect successfully,client ip:%s,port:%d\n",inet_ntop(AF_INET,&addr_c.sin_addr.s_addr,c_IP,sizeof c_IP),ntohs(addr_c.sin_port));res=pthread_create(&tid,NULL,fun,(void*)cfd);if(res!=0)fprintf(stderr,"pthread create error:%s",strerror(res));pthread_detach(tid);	if(res!=0)fprintf(stderr,"pthread create error:%s",strerror(res));}close(lfd);return 0;
}

效果

1


写在最后

个人亲身经验:我们学习的一系列Linux命令,一定要自己亲手去敲。不要只是看别人敲代码,不要只是停留在眼睛看,脑袋以为自己懂了,等你实际上手去敲会发现许许多多的这样那样的问题。毕竟“实践出真知”。


如果你觉得我写的题解还不错的,请各位王子公主移步到我的其他题解看看

  1. 数据结构与算法部分(还在更新中):
  • C++ STL总结 - 基于算法竞赛(强力推荐
  • 动态规划——01背包问题
  • 动态规划——完全背包问题
  • 动态规划——多重背包问题
  • 动态规划——分组背包问题
  • 动态规划——最长上升子序列(LIS)
  • 二叉树的中序遍历(三种方法)
  • 最长回文子串
  • 最短路算法——Dijkstra(C++实现)
  • 最短路算法———Bellman_Ford算法(C++实现)
  • 最短路算法———SPFA算法(C++实现)
  • 最小生成树算法———prim算法(C++实现)
  • 最小生成树算法———Kruskal算法(C++实现)
  • 染色法判断二分图(C++实现)
  1. Linux部分(还在更新中):
  • Linux学习之初识Linux
  • Linux学习之命令行基础操作
  • Linux学习之基础命令(适合小白)
  • Linux学习之权限管理和用户管理
  • Linux学习之制作静态库和动态库
  • Linux学习之makefile
  • Linux学习之系统编程1(关于读写系统函数)
  • Linux学习之系统编程2(关于进程及其相关的函数)
  • Linux学习之系统编程3(进程及wait函数)
  • Linux学习之系统编程4(进程间通信)
  • Linux学习之系统编程5(信号)
  • Linux学习之系统编程6(线程)
  • Linux学习之系统编程7(线程同步/互斥锁/信号量/条件变量)
  • Linux学习之网络编程(纯理论)
  • Linux学习之网络编程2(socket,简单C/S模型)

✨🎉总结

“种一颗树最好的是十年前,其次就是现在”
所以,
“让我们一起努力吧,去奔赴更高更远的山海”
在这里插入图片描述
如果有错误❌,欢迎指正哟😋

🎉如果觉得收获满满,可以动动小手,点点赞👍,支持一下哟🎉

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

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

相关文章

七、HorizontalPodAutoscaler(HPA)

目录 一、HPA概述&#xff1a; 二、HPA工作机制&#xff1a; 三、HPA流程: 四、HPA API对象: 五、示例&#xff1a; 1、基于CPU的HPA 2、常见问题&#xff1a; 3、基于内存的HPA 一、HPA概述&#xff1a; Horizontal Pod Autoscaler&#xff0c;中文就是水平自动伸缩可…

【洛谷千题详解】P7072 [CSP-J2020] 直播获奖

输入样例&#xff1a; 10 60 200 300 400 500 600 600 0 300 200 100 输出样例&#xff1a; 200 300 400 400 400 500 400 400 300 300 #include<bits/stdc.h> using namespace std; int main() {int n,w,s,a[605]{0};cin>>n>>w;for(int i1;i<n;i){sca…

【MySQL】数据处理之增删改

文章目录 一、增加&#xff08;插入&#xff09;INSERT INTO...VALUES(...,...)VALUES的方式添加情况一&#xff1a;为表的所有字段按默认顺序插入数据情况二&#xff1a;为表的指定字段插入数据情况三&#xff1a;同时插入多条记录 将查询结果插入到表中 二、修改&#xff08;…

AcWing 843. n-皇后问题

#include <iostream> #include <cstring> #include <algorithm>using namespace std; const int N 10; int n; int col[N], dg[N N], rdg[N N]; // 列占用// 正对角线占用// 副对角线占用 char table[N][N]; // 棋盘void dfs(int index) {if(i…

彻底理解字符编码

一、前言 为什么要进行编码&#xff0c;这些编码的关系如何&#xff0c;如ASCII&#xff0c;IOS-8859-1&#xff0c;GB2312&#xff0c;GBK&#xff0c;Unicode之间的关系&#xff0c;笔者想要彻底理解字符编码背后的故事&#xff0c;遂进行了探索&#xff0c;具体笔记如下。如…

“绿智中国”亚洲绿色数字生态发展论坛暨中泰基业集团2024产品发布会在渝举行

绿智中国&#xff0c;逐梦未来。2024年1月11日-12日&#xff0c;“绿智中国”亚洲绿色数字生态发展论坛暨中泰基业集团2024产品发布会在重庆盛大举行。以“以数字化引领绿色化&#xff0c;以绿色化带动数字化”为主题&#xff0c;共同见证“绿智中国”崛起的力量。 为积极响应《…

目标检测-One Stage-YOLOv7

文章目录 前言一、YOLOv7的不同版本二、YOLOv7的网络结构二、YOLOv7的创新点三、创新点的详细解读ELAN和E-ELANBoF训练技巧计划型重参化卷积辅助训练模块标签分配Lead head guided label assignerCoarse-to-fine lead head guided label assigner 基于级联模型的复合缩放方法 总…

canvas设置圆锥形渐变

查看专栏目录 canvas示例教程100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

隧道应用4-内网穿透EW的简单使用

与netsh端口映射内网类似&#xff0c;也是通过跳板机实现 EW官网地址&#xff1a;http://rootkiter.com/EarthWorm EW 是一套便携式的网络穿透工具&#xff0c;具有 SOCKS v5服务架设和端口转发两大核心功能&#xff0c;可在复杂网络环境下完成网络穿透。 注&#xff1a; 考虑…

【MATLAB源码-第111期】基于matlab的SCMA系统误码率仿真,采用polar码编码,输出误码率曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 SCMA&#xff08;Sparse Code Multiple Access&#xff09;系统是一种先进的多用户多输入多输出&#xff08;MU-MIMO&#xff09;通信系统&#xff0c;它采用了一种独特的多址访问技术&#xff0c;旨在提高无线通信网络的效率…

Ubuntu 22.04 Cron使用

需要定时处理的场景还是比较多的&#xff0c;比如信息推送、日志清理等。 这篇文章我们来说说如何使用cron来实现定时处理&#xff0c;以及监控任务的执行。 使用 Ubuntu中使用cron&#xff0c;要用到的命令是crontab。不加sudo时&#xff0c;处理的是个人的定时任务。当加上…

STEGNN

STEGNN 摘要 随着智能交通系统(ITS)逐渐融入我们的日常生活,人们普遍认为路网预测是智能交通系统的杀手锏,具有很高的社会和经济效益。然而,目前的解决方案忽视了时空交通数据的异质性,无法捕捉隐藏的时空相关性。本文介绍了 STEGNN:一种用于路网预测的新型时空嵌入图神…

Java控制结构解析

在 Java 编程语言中&#xff0c;控制结构用于控制程序的执行流程。以下是几种常见的控制结构及其解析&#xff1a; 条件语句&#xff08;If-else 语句&#xff09;&#xff1a;根据条件的真假来执行不同的操作。Switch 语句&#xff1a;根据一个表达式的值&#xff0c;选择不同…

P4学习(一) 环境搭建

系列文章目录 第一章 P4学习入门之虚拟机环境搭建 文章目录 系列文章目录前言一、P4是什么&#xff1f;二、搭建步骤1.下载虚拟机镜像2.虚拟机管理软件载入镜像2.1 找到你镜像的所在位置2.2 打开VMware Workstation2.3 载入镜像 3.检验环境是否配置成功 P4 的真机环境搭建 前言…

10.9.2 std::function 代替函数指针

std::function是一个模板类&#xff0c;基本可作为函数指针的代替品&#xff0c;具备更多功能&#xff0c;特别是与函数对象及bind配合使用。使用std::function时&#xff0c;需要添加头文件 #include <functional> 1.定义函数指针 18行&#xff0c;定义了一个函数指针类…

在win11中安装“mingw-w64-gcc-13.2-stable-r40”

在windows系统中&#xff0c;安装完VSCode后&#xff0c;还需要安装mingw&#xff0c;才可以使用C和C编译。 1、从MinGW-w64镜像站点&#xff1a;http://files.1f0.de/mingw&#xff0c;下载“mingw-w64-gcc-13.2-stable-r40”&#xff0c;见下图&#xff1a; 2、将“mingw-w6…

docker 安装redis (亲测有效)

目录 1 安装 1 安装 1 将redis 的 tar 包 上传到服务器 上传之后tar 包&#xff0c;将他变成镜像 输入docker images,发现目前是没有镜像的&#xff0c;现在将tar 包变成镜像 docker load -i redis.tar以上就将tar 包变成镜像了 现在在宿主机找一个地方&#xff0c;存放数据…

《GreenPlum系列》GreenPlum初级教程-02GreenPlum单节点安装

文章目录 第二章 GreenPlum安装1.Docker创建centos容器1.1 拉取centos7镜像1.2 创建容器1.3 进入容器1.4 容器和服务器免密操作1.4.1 生成密钥1.4.2 拷贝密钥 1.5 安装ssh服务和网络必须应用1.6 容器设置root密码1.6.1 安装passwd应用1.6.2 容器本机root设置密码 1.7 容器本机免…

【深度学习:Micro-Models】用于标记图像和视频的微模型简介

【深度学习&#xff1a;Micro-Models】用于标记图像和视频的微模型简介 微模型&#xff1a;起源故事微模型到底是什么&#xff1f;更详细地解释微观模型&#xff1a;一维标签蝙蝠侠效率 在计算机视觉项目中使用微模型的额外好处面向数据的编程 在本文中&#xff0c;我们将介绍 …

移动硬盘无法识别处理办法

今天这里做一下总结&#xff0c;我现在手上有一个移动硬盘&#xff0c;插入win10电脑是有盘号的&#xff0c;但是 但是点击就出问题 解决办法 安装DiskGenius 下载网址在https://www.diskgenius.cn/download.php 下载之后解压安装就行&#xff0c;非常简单&#xff0c;然后…