Linux应用软件编程---网络编程(TCP并发服务器构建:[ 多进程、多线程、select ])

TCP并发服务器构建

一、服务器

    单循环服务器:服务端同一时刻只能处理一个客户端的任务(TCP)
并发服务器:服务端同一时刻可以处理多个客户端的任务(UDP)

二、TCP服务端并发模型

1、多进程

     进程资源开销大,安全性高。

     以下是一个实现多进程TCP服务端代码:

#define SER_PORT 62300
#define SER_IP "192.168.0.165"int init_tcp_ser()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket error");return 0;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(SER_PORT);seraddr.sin_addr.s_addr = inet_addr(SER_IP);int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if(ret < 0){printf("bind error");return -1;}int cnt = listen(sockfd, 100);if(cnt < 0){perror("listen error");return -1;}return sockfd;
}void wait_handler(int signo)
{wait(NULL);
}int main(int argc, char *argv[])
{signal(SIGCHLD, wait_handler);struct sockaddr_in cliaddr;socklen_t clilen = sizeof(cliaddr);int sockfd = init_tcp_ser();if(sockfd < 0){perror("init_tcp_ser error");return -1;}while(1){int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen); if(connfd < 0){perror("accept error");return -1;}pid_t pid = fork();if(pid > 0){}else if(pid == 0){char buff[1024] = {0};while(1){memset(buff, 0, sizeof(buff));ssize_t ret = recv(connfd, buff, sizeof(buff), 0);if(ret < 0){perror("send error");return -1;}else if(ret == 0){printf("[%s : %d]: offline!\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));break;}printf("[%s : %d]: %s\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port), buff);strcat(buff, "----OK");ssize_t cnt = send(connfd, buff, strlen(buff), 0);if(cnt < 0){perror("send error");break;}}   close(connfd);}}close(sockfd);return 0;
}

2、多线程

     线程相对与进程资源开销小,相同资源环境下,并发量比进程大。

     以下是一个实现多线程TCP服务端代码:

#include "head.h"#define SER_PORT 62300
#define SER_IP "192.168.0.165"int init_tcp_ser()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket error");return 0;}//允许绑定处于TIME_WAIT状态的地址,避免端口占用问题:int optval = 1;setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(SER_PORT);seraddr.sin_addr.s_addr = inet_addr(SER_IP);int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if(ret < 0){printf("bind error");return -1;}int cnt = listen(sockfd, 100);if(cnt < 0){perror("listen error");return -1;}return sockfd;
}void *task(void *sug)
{int connfd = *(int *)sug;char buff[1024] = {0};while(1){memset(buff, 0, sizeof(buff));ssize_t ret = recv(connfd, buff, sizeof(buff), 0);if(ret < 0){perror("send error");break;}else if(ret == 0){printf("[%s : %d]: offline!\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));break;}printf("[%s : %d]: %s\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port), buff);strcat(buff, "----OK");ssize_t cnt = send(connfd, buff, strlen(buff), 0);if(cnt < 0){perror("send error");break;}}   close(connfd);
}int main(int argc, char *argv[])
{struct sockaddr_in cliaddr;socklen_t clilen = sizeof(cliaddr);int sockfd = init_tcp_ser();if(sockfd < 0){perror("init_tcp_ser error");return -1;}while(1){int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen); if(connfd < 0){perror("accept error");return -1;}pthread_t tid;int fd = pthread_create(&tid, NULL, task, &connfd);if(fd < 0){perror("thread create error");return -1;}  pthread_detach(tid);}close(sockfd);return 0;
}

3、线程池

     为了解决多线程或者多进程模型,在服务器运行过程,频繁创建和销毁线程(进程)带来的时间消耗问题。
基于生产者和消费者编程模型,以及任务队列等,实现的一套多线程框架。

4.  IO多路复用

    1)概念

     对多个文件描述符的读写可以复用一个进程。
在不创建新的进程和线程的前提下,使用一个进程实现对多个文件读写的同时监测。
阻塞IO模式:

    2)方式

        实现方式有 select、poll、epoll 三种。

5、select 实现IO多路复用

    1)实现步骤

    (1)创建文件描述符集合     fd_set
(2)添加关注的文件描述符到集合     FD_SET
(3)使用 select 传递集合表给内核,内核开始监测事件    select()
(4)当内核监测到事件时,应用层select将解除阻塞,并获得相关的事件结果
(5)根据 select 返回的结果做不同的任务处理

    2)select 的宏

        将集合清0:void FD_ZERO(fd_set *set);
向集合中添加文件描述符:void FD_SET(int fd, fd_set *set);
从集合中移除文件描述符:void FD_CLR(int fd, fd_set *set);
检查文件描述符是否在集合中:int  FD_ISSET(int fd, fd_set *set);

    3)select() 函数接口

 int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);

功能:传递文件描述符结合表给内核并等待获取事件结果
参数:
nfds : 关注的最大文件描述符+1
readfds:读事件的文件描述符集合
writefds:写事件的文件描述符集合
exceptfds:其他事件的文件描述符集合
timeout:设置select监测时的超时时间
若为NULL : 不设置超时时间(select一直阻塞等待)

返回值:
成功:返回内核监测的到达事件的个数
失败:-1
0 : 超时时间到达,但没有事件发生,则返回0

    4)应用示例

        (1)通过select函数构建多路复用,实现管道和终端的读

        管道向服务端写的代码:

int main(void)
{mkfifo("./myfifo", 0664);int fd = open("./myfifo", O_WRONLY);if(fd < 0){perror("open error");return -1;}while(1){write(fd, "hello world", 11);sleep(1);}close(fd);return 0;
}

        读的代码:

int main(void)
{char buff[1024] = {0};mkfifo("./myfifo", 0664);int fifofd = open("./myfifo", O_RDONLY);if(fifofd < 0){perror("open error");return -1;}//1、创建文件描述符集合fd_set rdfds;fd_set rdfdstmp;//2、清空文件描述符集合表FD_ZERO(&rdfds);//初始化...集//3、添加关注的文件描述符到集合中FD_SET(0, &rdfds);//添加int maxfd = 0;FD_SET(fifofd, &rdfds);maxfd = maxfd > fifofd ? maxfd : fifofd;while(1){rdfdstmp = rdfds;//4、传递集合表给内核并等待返回到达事件的结果int cnt = select(maxfd+1, &rdfdstmp, NULL, NULL, NULL);if(cnt < 0){perror("select error");return -1;}if(FD_ISSET(0, &rdfdstmp))//检查文件描述符0是否在集合中{fgets(buff, sizeof(buff), stdin);//0printf("STDIN: %s\n", buff);}if(FD_ISSET(fifofd, &rdfdstmp)){memset(buff, 0, sizeof(buff));read(fifofd, buff, sizeof(buff));printf("FIFO: %s\n", buff);}}close(fifofd);return 0;
}

        (2)使用select实现TCP服务端IO多路复用代码

#define SER_PORT  50000
#define SER_IP    "192.168.0.165"int init_tcp_ser()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socket error");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(SER_PORT);seraddr.sin_addr.s_addr = inet_addr(SER_IP);int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (ret < 0){perror("bind error");return -1;}ret = listen(sockfd, 100);if (ret < 0){perror("listen error");return -1;}return sockfd;
}int main(int argc, const char *argv[])
{char buff[1024] = {0};struct sockaddr_in cliaddr;socklen_t clilen = sizeof(cliaddr);int sockfd = init_tcp_ser();if (sockfd < 0){return -1;}//1. 创建文件描述符集合fd_set rdfds;fd_set rdfdstmp;FD_ZERO(&rdfds);//2. 添加关注的文件描述符到集合FD_SET(sockfd, &rdfds);int maxfd = sockfd;while (1){rdfdstmp = rdfds;//3. 传递集合到内核,并等待返回监测结果int cnt = select(maxfd+1, &rdfdstmp, NULL, NULL, NULL);if (cnt < 0){perror("select error");return -1;}//4. 是否有监听套接字事件到达 ----》三次握手已完成,可以acceptif (FD_ISSET(sockfd, &rdfdstmp)){int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen);if (connfd < 0){perror("accept error");return -1;}FD_SET(connfd, &rdfds);maxfd = maxfd > connfd ? maxfd : connfd;}//5. 是否有通讯套接字事件到达for (int i = sockfd+1; i <= maxfd; i++){if (FD_ISSET(i, &rdfdstmp)){memset(buff, 0, sizeof(buff));ssize_t cnt = recv(i, buff, sizeof(buff), 0);if (cnt < 0){perror("recv error");FD_CLR(i, &rdfds);close(i);continue;}else if (0 == cnt){FD_CLR(i, &rdfds);close(i);continue;}printf("%s\n", buff);strcat(buff, "--->ok");cnt = send(i, buff, strlen(buff), 0);if (cnt < 0){perror("send error");FD_CLR(i, &rdfds);close(i);continue;}}}	}close(sockfd);return 0;
}

【END】

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

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

相关文章

重构审计体验!批量生成报表项目底稿的凭证检查表

在审计工作中&#xff0c;我们通过序时账或其他审计软件筛选导出的凭证列表&#xff0c;要如何快速分发给各个报表项目底稿的凭证检查表呢&#xff1f; “TB工具箱2025”正式上线“批量生成凭证表”的功能&#xff0c;通过一些巧妙的设计&#xff0c;使其具备高度的通用性&…

【c++进阶系列】:万字详解二叉搜索树(附源码实现)

&#x1f525; 本文专栏&#xff1a;c &#x1f338;作者主页&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客励志语录&#xff1a; 你可以走得慢&#xff0c;但别回头 1.概念 二叉搜索树&#xff0c;从其名字我们就能知道该数据结构是一个特殊的二叉树&#xff0c;而二…

通过web服务做横向移动

环境配置边缘主机(win10)&#xff1a;192.168.237.140 10.10.90.128内网主机(win7)&#xff1a;10.10.90.129 web服务 -- upload-labs攻击机&#xff1a;vps&#xff08;120.26.114.196&#xff09;windows10windows7假设已经拿下边缘主机win10&#xff0c;vshell上线ipconfig查…

把CentOS 7默认yum源改成腾讯云镜像

步骤计划&#xff1a; 备份原有CentOS-Base.repo文件&#xff0c;防止配置出错可恢复 下载腾讯云提供的CentOS 7镜像源配置文件&#xff08;对应CentOS-Base.repo&#xff09; 清理并生成yum缓存&#xff0c;使新源生效 具体命令 # 备份原有源 sudo mv /etc/yum.repos.d/C…

欧盟《人工智能法案》生效一年主要实施进展概览(二)

文章目录前言三、《关于禁止的人工智能实践指南》1. 整体适用2. 禁止的人工智能系统具体介绍&#xff08;1&#xff09;有害操纵和欺骗类及对脆弱性的有害利用类&#xff08;2&#xff09;社会评分类&#xff08;3&#xff09;个人刑事犯罪风险评估和预测类&#xff08;4&#…

私域电商新范式:开源AI智能名片链动2+1模式S2B2C商城小程序赋能传统行业流量转化

摘要&#xff1a;本文聚焦私域电商领域&#xff0c;指出其并非仅局限于快消品等传统电商行业&#xff0c;多数传统行业同样面临私域流量利用难题。传统行业手握私域流量或优质流量入口&#xff0c;却不知如何有效转化&#xff0c;陷入流量焦虑。在此背景下&#xff0c;开源AI智…

Axios 整理常用形式及涉及的参数

一、axios get请求 //形如 axios.get(url[, config]).then(response > {// 处理响应}).catch(error > {// 处理错误}); //无 config 的情况下&#xff0c; axios.get(https://api.example.com/data).then(response > {// 处理响应}) .catch(error > {// 处理错误})…

深度学习---卷积神经网络CNN

卷积神经网络CNN&#xff08;Convolutional Neural Networks&#xff09;一、图像原理图像在计算机中是一堆按顺序排列的数字&#xff0c;数值为0到255。0表示最暗&#xff0c;255表示最亮。上图是只有黑白颜色的灰度图&#xff0c;而更普遍的图片表达方式是RGB颜色模型&#x…

日志输出触发的死锁问题排查记录

现象描述 错误日志&#xff1a; Found one Java-level deadlock:"http-nio-8083-exec-106":waiting for ownable synchronizer 0x00000005cbfa6b90, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),which is held by "http-nio-8083-exec-10" …

UNIX网络编程笔记:高级套接字编程20-25

广播通信&#xff1a;局域网内的高效信息传播 在局域网通信场景中&#xff0c;广播是一种高效的一对多信息传播方式 。它无需为每个接收者单独建立连接&#xff0c;能一次性将消息送达网段内所有目标&#xff0c;广泛应用于服务发现、网络通知等场景。以下从基础原理到实践应用…

React Native核心技术深度解析_Trip Footprints

React Native 框架详细技术解析 作为前端开发者&#xff0c;理解React Native需要从Web开发的角度出发&#xff0c;了解其独特之处和技术实现。 &#x1f3af; React Native 核心概念 什么是React Native&#xff1f; React Native是Facebook开发的跨平台移动应用开发框架&…

预算管理的“数字围栏“:如何用实时预警终结行政费用超支

作为公司行政主管&#xff0c;每年最让我忐忑的时刻不是年终总结&#xff0c;而是季度财务分析会。当CFO皱着眉头指出行政费用又超支时&#xff0c;那种如坐针毡的感觉至今难忘。行政预算就像一匹难以驯服的野马&#xff0c;明明已经严加管控&#xff0c;却总在年底给我们"…

NTLM哈希深度解析:从原理到安全实践

NTLM哈希深度解析&#xff1a;从原理到安全实践作为一名白帽子黑客&#xff0c;深入理解NTLM哈希机制对保障企业网络安全至关重要。1. NTLM哈希概述 NTLM&#xff08;New Technology LAN Manager&#xff09;是微软推出的一套身份验证协议套件&#xff0c;用于在Windows网络中验…

4-3.Python 数据容器 - 集合 set(集合 set 概述、集合的定义、集合的遍历、集合的常用方法)

集合 set 概述集合用于存储一系列元素集合存储的元素是无序的&#xff0c;不支持索引集合存储的元素是不可以重复的集合存储的元素可以是不同类型的&#xff0c;例如、数字、字符串、甚至是其他集合集合是可变的&#xff0c;在程序运行时可以添加、删除其中的元素一、集合的定义…

验证码请求与缓存问题解决方案

验证码请求与缓存问题解决方案 1.问题描述 请求验证码图片未变化&#xff0c;且未监听到新请求的问题。 2.问题分析 这个问题的根本原因通常是浏览器缓存机制导致的 - 浏览器会缓存相同URL的图片&#xff0c;导致第二次请求时直接从缓存读取而不发送新请求。 3.解决方案思路 在…

安卓接入通义千问AI的实现记录

官网&#xff1a;https://help.aliyun.com/zh/model-studio/use-qwen-by-calling-api#b1320a1664b9a 创建网络请求 创建一个BaseNetworkApi基类用于实现各种拦截器等。 abstract class BaseNetworkApi {fun <T> getApi(serviceClass: Class<T>, baseUrl: String…

Linux 命令浏览文件内容

Linux 命令浏览文件内容 1. cat 查看文件的所有内容1.1 -n 显示行号1.2 -b 显示没有空行的行号2. head 前10行标准输出2.1 -c 输出每行第一个字符2.2 -n 指定行数3. tail 显示文件的最后 10 行数据3.1 -c 显示指定字符3.2 -n 指定行数3.3 显示追加内容4. more 分页显示文件内容…

UVa11607 Cutting Cakes

UVa11607 Cutting Cakes题目链接题意分析AC 代码题目链接 UVa11607 Cutting Cakes 题意 平面上有n&#xff08;n≤1 500&#xff09;个点&#xff0c;其中没有3 点共线。另外有m&#xff08;m≤700 000&#xff09;条直线&#xff0c;你的任务是对于每条直线&#xff0c;输出3…

[e3nn] 等变神经网络 | 线性层o3.Linear | 非线性nn.Gate

第4章&#xff1a;等变神经网络模块 欢迎回来&#xff5e; 在我们探索e3nn的旅程中&#xff0c;我们已经揭示了一些基本概念&#xff1a; 在第1章&#xff1a;不可约表示&#xff08;Irreps&#xff09;中&#xff0c;我们学习了Irreps作为等变数据的标签&#xff0c;告诉我们数…

共享云服务器替代传统电脑做三维设计会卡顿吗

与传统本地工作站相比&#xff0c;云服务器在硬件配置、协作效率和成本控制方面具有明显优势&#xff0c;但设计师们比较关心的主要问题始终是&#xff1a;使用共享云服务器进行三维设计会出现卡顿吗&#xff1f;这取决于硬件配置、网络环境、软件优化及使用场景等多方面因素。…