并发性服务器

news2024/9/20 7:57:07

同一时刻能处理多个客户端

多进程:

int init_tcp_ser(const char *ip,unsigned short port)
{
    int sockfd= socket(AF_INET,SOCK_STREAM,0);
    if(-1== sockfd)
    {
        perror("fail socket");
        return -1;
    }
    struct sockaddr_in ser;
    ser.sin_family = AF_INET;
    ser.sin_port = htons(port);
    ser.sin_addr.s_addr = inet_addr(ip);

    int ret = bind(sockfd,(struct sockaddr *)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("bind fail");
        return -1;
    }

    ret = listen(sockfd,128);
    if(-1 == ret)
    {
        perror("listen fail");
        return -1;
    }
    return sockfd;
}

void handler(int signo)
{
    wait(NULL);
}
int main(int argc, char *argv[])
{
    pid_t pid = 0;
    int connfd = 0;
    char buf[1024] = {0};

    signal(SIGCHLD,handler);
    int sockfd = init_tcp_ser("192.168.42.128",50000);
    if(-1 == sockfd)
    {
        return -1;
    }
    while(1)
    {
        connfd = accept(sockfd,NULL,NULL);

        if(-1==connfd)
        {
            perror("fail accept");
            return -1;
        }
        pid = fork();
        if (pid > 0)
        {
        }
        else if(0==pid)
        {
            while(1)
            {
                memset(buf,0,sizeof(buf));
                ssize_t size = recv(connfd,buf,sizeof(buf),0);
                if(size <= 0)
                {
                    break;
                }
                printf("cli----->%s\n",buf);
                strcat(buf,"---->ok!\n");
                send(connfd,buf,strlen(buf),0);
            }
            close(connfd);
        }
    }
    return 0;
}

多线程:

int init_tcp_ser(const char *ip,unsigned short port)
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        perror("fail socket");
        return -1;
    }
    struct sockaddr_in ser;
    ser.sin_family = AF_INET;
    ser.sin_port =htons(port);
    ser.sin_addr.s_addr = inet_addr(ip);
    int ret = bind(sockfd,(struct sockaddr *)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("bind fail");
        return -1;
    }
    ret = listen(sockfd,128);
    if(-1 == ret)
    {
        perror("listen fail");
        return -1;
    }
    return sockfd;
}

void *do_Something(void *arg)
{
    char buf[1024]= {0};
    int connfd = *(int *)arg;
    while(1)
    {
        memset(buf,0,sizeof(buf));
        ssize_t size = recv(connfd,buf,sizeof(buf),0);
        if(size <= 0)
        {
            break;
        }
        printf("----->%s\n",buf);
        strcat(buf,"------>ok!\n");
        send(connfd,buf,strlen(buf),0);
    }
    close(connfd);
    return NULL;
}
int main(int argc, char *argv[])
{
    int connfd = 0;
    int sockfd = init_tcp_ser("192.168.42.128",50000);
    if(sockfd == -1)
    {
        printf("init_tcp_ser fail");
        return -1;
    }
    while(1)
    {
        connfd = accept(sockfd,NULL,NULL);
        if(-1 == sockfd)
        {
            perror("accept fail");
            return -1;
        }
        pthread_t tid;
        int ret1 = pthread_create(&tid,NULL,do_Something,&connfd);
        if(ret1 != 0)
        {
            perror("pthread_create fail");
            return -1;
        }
        pthread_detach(tid);
        void *retval;
        if(pthread_join(tid,&retval) == 0)
        {
            perror("pthread_join fail");
            return -1;
        }
   }
}

IO多路复用:

select:

select模型通过调用select函数来检查一个或多个文件描述符(在socket编程中通常指套接字)的状态,包括可读、可写以及异常。select函数的原型如下:

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

  功能:
          监听文件描述符集合
  参数:
          nfds:监测的文件描述符上限值(最大文件描述符的值+1)
          readfds:读文件描述符集合
          writefds:写文件描述符集合
          exceptfds:异常条件的描述符集合
          timeout:设置超时时间
                      NULL:一直等待
返回值:
         成功返回产生事件文件描述符个数
         失败返回-1 
         定时时间到达仍没有事件产生返回0  

void FD_CLR(int fd, fd_set *set);
                   将fd从文件描述符集合中清除
int  FD_ISSET(int fd, fd_set *set);
                   判断文件描述符fd是否仍在文件描述符集合中
void FD_SET(int fd, fd_set *set);
                   将fd加入文件描述符集合中
void FD_ZERO(fd_set *set);
                   文件描述符集合清0 

优点

  • 跨平台性:select模型是跨平台的,几乎所有的操作系统都支持。
  • 简单易用:select模型的API相对简单,使用起来比较方便。
  • 灵活性:支持监视多个文件描述符,并且可以通过设置超时参数来实现超时等待。

缺点

  • 效率低:在大规模并发的场景下效率较低,因为需要遍历所有的文件描述符。
  • 文件描述符数量限制:对监视的文件描述符数量有限制,通常最多支持1024个(可修改,但受系统限制)。
  • IO效率不高:每次调用select都需要将监视的所有文件描述符传递给内核,效率较低。

poll:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);


 功能:
        监听文件描述符集合中的事件
 参数:
        fds:文件描述符集合事件数组首地址
        nfds:事件个数
        timeout:超时时间
返回值:
        成功返回产生事件的文件描述符个数
        失败返回-1 
        超时时间到达仍没有产生事件返回0 

struct pollfd {
   int   fd;         /* file descriptor */
   short events;     /* requested events */
   short revents;    /* returned events */
};

epoll:

epoll模型:
1)epoll_create 创建epoll文件描述符集合
2)epoll_ctl   添加关注的文件描述符
3)epoll_wait 监控io事件
4)epoll_ctl  从事件集合中删除完成的文件描述符

int epoll_create(int size);
  功能:
                 创建一个监听事件表(内核中)
  参数:
                size:监听事件最大个数
  返回值:
                成功返回非负值:表示epoll事件表对象(句柄)
                失败返回-1 
5.epoll_ctl
  int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  功能:
                在监听事件表中新增一个事件
  参数:
                epfd:事件表文件描述符 
                op:EPOLL_CTL_ADD 新增事件
                   EPOLL_CTL_MOD 修改事件 
                   EPOLL_CTL_DEL 删除事件
                fd:文件描述符 
                events:事件相关结构体
  返回值:
                成功返回0 
                失败返回-1 

typedef union epoll_data {
   void        *ptr;
   int          fd;
   uint32_t     u32;
   uint64_t     u64;
} epoll_data_t;

struct epoll_event {
   uint32_t     events;      /* Epoll events */
   epoll_data_t data;        /* User data variable */
};

 events:
                EPOLLIN 读事件
                EPOLLOUT 写事件
                EPOLLET 边沿触发
                LT 水平触发

6.epoll_wait
  int epoll_wait(int epfd, struct epoll_event *events,
                      int maxevents, int timeout);
      功能:

                监听事件表中的事件,并将产生的事件存放到结构体数组中
  参数:
                epfd:事件表文件描述符
                events:存放结果事件结构体数组空间首地址 
                maxevents:最多存放事件个数
                timeout:超时时间
                -1:阻塞等待直到有事件发生 
  返回值:
                成功返回产生事件个数
                失败返回-1 
                超时时间到达没有事件发生返回0 

select,poll,epoll优缺点对比: 

select

优点

  1. 可移植性好:select是较早出现的I/O多路复用技术,具有较好的跨平台性,可以在多种操作系统上运行,包括Windows、Linux和Unix等。
  2. 超时控制:select支持超时设置,允许程序在等待I/O事件时指定一个超时时间,增加了程序的灵活性。

缺点

  1. 效率较低:select在处理大量文件描述符(FD)时效率较低。每次调用select时,都需要将用户空间的FD集合复制到内核空间,并且内核需要遍历所有的FD来检查是否有I/O事件发生,这个过程的时间复杂度为O(n),其中n为FD的数量。当FD数量很大时,这个开销会非常大。
  2. FD数量限制:select对单个进程可监视的FD数量有限制,这个限制通常与系统的文件描述符限制相关,但select通常有一个较小的硬限制,比如1024。
  3. 信号干扰:如果select在等待期间收到了信号,并且该信号的处理函数修改了select监控的文件描述符集合,那么select的行为将是不确定的。
poll

优点

  1. 无连接数限制:poll与select相比,一个显著的优势是它没有最大连接数的限制,因为它基于链表来存储文件描述符。
  2. 简化编程:poll的接口相对于select来说更简洁一些,它不需要开发者计算最大文件描述符加一的大小。

缺点

  1. 效率问题:poll同样存在效率问题,每次调用poll时,也需要将用户空间的FD集合复制到内核空间,并且内核需要遍历所有的FD来检查是否有I/O事件发生,时间复杂度同样为O(n)。
  2. 数据拷贝:大量的FD数组在每次调用poll时都会被整体复制到用户态和内核地址空间之间,这会导致不必要的性能开销。
epoll

优点

  1. 高效处理大量并发连接:epoll是专为处理大量并发连接而设计的,它采用了一种基于事件驱动的方式来工作,只处理“活跃”的socket,从而避免了无谓的遍历和等待。
  2. IO效率稳定:epoll的IO效率不会随着FD数量的增加而线性下降,这是因为它只关心那些真正发生I/O事件的socket。
  3. 使用mmap加速数据传递:epoll通过mmap机制实现了内核空间与用户空间之间的消息传递,减少了数据拷贝的次数,进一步提高了效率。

缺点

  1. 跨平台性差:epoll是Linux特有的I/O多路复用技术,无法在其他操作系统上使用。
  2. 学习曲线较陡峭:相对于select和poll来说,epoll的API较为复杂,需要一定的学习成本。
  3. 活动连接多时性能下降:虽然epoll在处理大量并发连接时效率很高,但当活动连接非常多时,频繁的调用epoll_wait可能会导致性能下降。

综上所述,select、poll和epoll各有优缺点,在实际应用中应根据具体需求和环境选择合适的I/O多路复用技术。对于需要处理大量并发连接的场景,epoll是更好的选择;而对于跨平台性要求较高的场景,则可能需要考虑使用select或poll。

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

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

相关文章

【Python 千题 —— 基础篇】简易购物车

Python 千题持续更新中 …… 脑图地址 👉:⭐https://twilight-fanyi.gitee.io/mind-map/Python千题.html⭐ 题目描述 题目描述 设计一个在线购物车系统,该系统能够管理用户的购物行为。用户可以将商品添加到购物车中、移除购物车中的商品、查看购物车中的商品列表,并计算…

nerfstudio半离线配置踩坑记录

安装torch2.1.2 with cuda11.8 由于清华镜像源&#xff08;包括阿里源和豆瓣源&#xff09;都没有torch2.1.2cu118的包&#xff0c;因此只能从pytorch官网下载。 服务器上直接通过下面pip的方式安装会由于网络原因中断&#xff0c;无奈只能在本地先把torch的包下载下来再上传到…

8.Linux_Makefile

Makefile 1、基本知识 语法&#xff1a; 目标:依赖 //依赖可以是0个或多个&#xff0c;依赖之间用空格分隔命令 //命令前面必须有tab键 目标&#xff1a;最终要生成的文件依赖&#xff1a;生成目标所需要的文件命令&#xff1a;怎么样通过依赖来生成目标的 make访问mak…

pve首页查看功耗拓展脚本

作者&#xff1a;TP唉 https://www.bilibili.com/read/cv26924314/?jump_opus1 出处&#xff1a;bilibili 如图所示想要这全方位信息很难吗&#xff1f;不&#xff0c;很简单只需要在shell里粘贴两串代码轻松搞定&#xff01; 命令1&#xff1a;(curl -Lf -o /tmp/temp.sh ht…

CleanClip: macOS 上最干净的剪贴板管理工具

在日常工作中,我们经常需要复制粘贴各种内容。但是 macOS 自带的剪贴板功能非常有限,只能保存最后一次复制的内容。这就是为什么我们需要一个强大的剪贴板管理工具 - CleanClip。 CleanClip 是什么? CleanClip 是一款专为 Mac 用户设计的剪贴板管理工具&#xff0c;它可能是 …

day13JS-MoseEvent事件

1. MouseEvent的类别 mousedown &#xff1a;按下键mouseup &#xff1a;释放键click &#xff1a;左键单击dblclick &#xff1a;左键双击contextmenu &#xff1a;右键菜单mousemove &#xff1a;鼠标移动mouseover : 鼠标经过 。 可以做事件委托&#xff0c;子元素可以冒泡…

FUNCTION_ALV 下拉框的实现

下拉框可以用drdn_field或者使用DRDN_HNDL&#xff0c;这个文章主要是下拉框的基本使用&#xff0c;核心就是在fieldcat内表里面设置好下拉框的字段或者组的编号 文章目录 drdn_field使用DRDN_HNDL复制状态完整代码核心代码运行结果 drdn_field 使用DRDN_HNDL 复制状态 完整代码…

AcWing852.spfa判断负环

cnt数组表示&#xff1a;cnt【j】表示边j #include<iostream> #include<cstring> #include<algorithm> #include<queue> #define N 2010 #define M 10010 using namespace std; int n,m; int h[N],w[M],e[M],ne[M],idx; int dis[N],cnt[N]; bool st[N…

ps笔刷设置使用介绍

形状动态 建议开启&#xff0c;作用是笔刷会有粗细变换 传递 不透明度抖动 . 选择钢笔压力&#xff0c;作用就是压感&#xff0c;压力值&#xff0c;有粗细深浅轻重变化 调到这画的时候就不会特别浅 流量抖动 选择钢笔压力&#xff0c;开了就有虚边 方便画过渡。 一般画…

JavaWeb实战教程:如何一步步构建房产信息管理系统?MySQL助力数据管理

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

Unable to delete file: .....(路径) signing-config.json无法删除

运行了一个去年很久之前的项目,在打包的时候弹出这个错误,提示要删除这个json文件,尝试了很多次无法删除,最后想到可能是文件权限的问题 Execution failed for task :app:clean. > Unable to delete file: D:\xxxxxx\xxxxxx\app\build\intermediates\signing_config\debug\…

基于Python、Django的企业门户网站设计

一、框架设计 1.1 创建项目和应用 企业门户网站的结构如下图所示。 因此,在文件夹下创建hengDaProject项目。在该项目下添加homeApp、aboutApp、newsApp、productsApp、serviceApp、scienceApp、contactApp应用。该操作参见:https://blog.csdn.net/qq_42148307/article/det…

【归纳总结】常见排序算法及其实现:直接插入排序、希尔排序、选择排序、堆排序、冒泡排序、快排、归并排序

思维导图&#xff1a; 目录 思维导图&#xff1a; 一、插入排序 1.直接插入排序&#xff1a; a:基本思想&#xff1a; b:基本步骤&#xff1a; c:复杂度分析 d:Java代码实现&#xff1a; 2.希尔排序&#xff08;缩小增量排序&#xff09; a:基本思想&#xff1a; c…

python_每天定时向数据库插入数据

每天的零点十分&#xff0c;定时向mysql数据库插入&#xff0c;昨天新增的文件和昨天下载文件的记录。第一次运行的时候&#xff0c;会全量同步昨天之前的数据。 import os import threading from datetime import datetime, timedelta import time import schedule from pymy…

仓颉编程语言亮相全国大学生计算机系统能力大赛

2024年8月18日-22日&#xff0c;由全国高等学校计算机教育研究会、系统能力培养研究专家组、系统能力培养研究项目发起高校主办&#xff0c;杭州电子科技大学承办的2024全国大学生计算机系统能力大赛编译系统设计赛&#xff08;华为毕昇杯&#xff09;及操作系统设计赛在杭电下…

企业防泄密首选!哪款公司防泄密软件更强?看这里,一文解惑!

早在2011年&#xff0c;前苹果员工Paul Devine泄露苹果公司的机密信息&#xff0c;涉及新产品的预测、计划蓝图、价格和产品特征&#xff0c;还为苹果公司的合作伙伴、供应商和代工厂商提供的关于苹果公司的数据&#xff0c;这使得这些供应商和代工厂商拥有了与苹果谈判的筹码&…

Wireless Communications - 模拟调制

AM/DSB/VSB/SSB的调制与解调 AM DSB SSB 滤波法 相移法 VSB 相干解调 线性调制的抗噪声分析 DSB SSB FM/PM 的调制与解调 NBFM WBFM 调频信号的产生和解调 模拟调制对比

SpringBootFFmpeg实现M3U8切片转码播放(本地)

文章目录 参考概述代码pom.xmlffmpegFFmpegUtilsMediaInfoTranscodeConfig application.ymlApplicationUploadControllerindex.html 测试 参考 springboot-ffmpeg-demo gitee代码 SpringBoot FFmpeg实现一个简单的M3U8切片转码系统 FFmpeg音视频核心技术精讲 - 百度网盘 概…

【STM32】红外遥控

红外遥控&#xff0c;掌握了就能装逼了&#xff0c;哈哈哈哈哈哈。 大部分图片来源&#xff1a;正点原子HAL库课程 专栏目录&#xff1a;记录自己的嵌入式学习之路-CSDN博客 1 器件特性 这里载波发射周期的发射与不发射时间实际上是因为载波是38kHz、占空为三分之一的方波&a…

符号译码_网络同步赛

哎……又是 If平推字符 #include <bits/stdc++.h> using namespace std; signed main(){char x;while(cin>>x){if(x==1){cin>>x;if(x==1)cout<<">";else if(x == 0){cin>>x;if(x==1)cout<<"]";else if(x==0)cout&…