Linux网络编程-TCP并发服务器

【Linux网络编程】TCP并发服务器的实现(IO多路复用select) TCP的服务器默认的就是一个循环服务器,原因是有两个阻塞 accept函数 和 recv函数之间会相互影响。本文是TCP并发服务器、客户端的实现以及实例的详细解释。使用了IO多路复用select函数进行TCP并发服务器的构建。希望博客对您有所帮助。 ......... 阅读详情

单循环服务器:只能处理一个客户端任务的服务器。
并发服务器:可以同时处理多个客户端任务的服务器(一对多)。
UDP服务端:具备并发性能
TCP服务端:建立连接,单循环服务器。
TCP并发服务器构建方式:

  • 多进程

进程资源开销大,在有限平台下,并发量比较小。

  • 多线程

资源开销小,在相同平台下,并发量比多进程大。

  • 线程池

多线程模型在客户端建立连接时,创建线程和销毁线程有时间消耗。
生产者-消费者设计模式
主线程:生产任务
线程池:执行任务
任务队列

  • IO多路复用

在不创建新进程/线程的前提下,使用一个进程同时检测多路IO。
IO:对文件读写
sockfd

1.多进程

//socket();
//bind();
//listen();
int init_http_server()//TCP连接初始化
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket");
        return -1;
    }
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = inet_addr(IP); 
    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("bind");
        return -1;
    }
    if (listen(sockfd, MAX_CLIENT) < 0)
    {
        perror("listen");
        return -1;
    }
    return sockfd;
}
//接收建立连接的客户端,并接收信息(回应)
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
while(1)
{
int connfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);
if(connfd < 0)
{
perror("accept");
continue;
}
printf("client ip: %s, port: %d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
pid_t pid = fork();
if (pid > 0)
{
}
else if (0 == pid)
{
char buf[1024] = {0};
while (1)
{
recv();
send();
}
}

2.多线程

void* thread_func(void* arg)
{
    char buf[1024];
    int connfd = *(int*)arg;
    free(arg);
    while(1)
    {
        memset(buf, 0, sizeof(buf));
        ssize_t size = recv(connfd, buf, sizeof(buf), 0);
        if(size < 0)
        {
            perror("recv error");
            break;
        }
        else if(size == 0)
        {
            printf("client close\n");
            break;
        }
        printf("recv: %s\n", buf);
        strcat(buf,"--->ok");
        size = send(connfd, buf, strlen(buf), 0);
        if(size < 0)
        {
            perror("send error");
            close(connfd);
            break;
        }
    }
    return NULL;
}
//while里
int *pconnfd = malloc(sizeof(int));
*pconnfd = connfd;
pthread_create(&tid,NULL,thread_func,pconnfd);
pthread_detach(tid);

3.IO多路复用

IO多路复用实现方式:
1. 创建文件描述符集合
2. 将关注的文件描述符添加到集合
3. 将文件描述符传递给内核,内核开始检测IO事件
4. 内核返回到达事件的结果

1.select

select 是 IO 多路复用中最早出现的实现方式,虽然它解决了单进程同时监测多路 IO 的问题,但在实际使用中仍存在以下明显的性能瓶颈和功能限制:

缺点:

1. 使用数组(位图)保存文件描述符集合,最多允许监测1024个文件描述符;
2. 将集合表创建在应用层,存在应用层和内核层数据的反复拷贝;
3. 事件到达时,内核返回整个集合表,应用层需要遍历;
4. select只能工作在水平触发模式(低速模式),不能工作在边沿触发模式(高速模式);

1. 创建文件描述符集合(位图(数组)--》1024(文件描述符1024个,0-1023)
fd_set fds;
FD_ZERO(&fds);
2. 将要监测的文件描述符加入集合
FD_SET(fd, &fds);
3. 将集合传递给内核开始监测IO事件,并且返回监测的结果
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
功能:将文件描述符传递给内核开始监测IO事件,并返回监测到的结果
参数:
nfds:监测的文件描述符最大值+1
readfds:要监测的读事件的文件描述符集合
writefds:要监测的写事件的文件描述符集合
exceptfds:要监测的出错事件的文件描述符集合
timeout:超时时间
NULL :不设置超时时间:阻塞等到
返回值:
成功:实际到达的IO事件的个数
失败:-1
0 :设置超时事件,超时时间到没有事件到达
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);

    fd_set set;
    fd_set tmp;
    FD_ZERO(&set);
    FD_SET(fd,&set);
    FD_SET(0,&set);
    int maxfd = fd > 0 ? fd : 0;
while(1)
{
    tmp = set;
    int cnt = select(maxfd+1, &amp;tmp, NULL, NULL, NULL);
    if(cnt &lt; 0)
    {
        perror("select error");
        return -1;
    }
    if(FD_ISSET(fd,&amp;tmp))
    {
        memset(buf,0,sizeof(buf));
        ssize_t size = read(fd,buf,sizeof(buf));
        if(size &lt; 0)
        {
            perror("read error");
            FD_CLR(fd,&amp;set);
            close(fd);
        }
        else if(size == 0)//已经进入了if循环里面说明管道有数据,但是size返回是0,说明管道写端被关闭
        {
            printf("pipe closed\n");
            FD_CLR(fd,&amp;set);
            close(fd);
        }
        printf("FIFO: %s\n",buf);
    }
    if(FD_ISSET(0,&amp;tmp))
    {
        fgets(buf,sizeof(buf),stdin);
        printf("read from stdin: %s\n",buf);
    }
}
//1.如果写端进程执行了 close(fd),哪怕此时缓冲区是空的,内核也会把该 fd 标记为“可读”,目的是让你去“收尸”。此时 select 会立即返回,触发 FD_ISSET,你执行 read,读到 0,得知对方已断开
//2.select 检查管道 fd 发现:缓冲区为空,但写端还在。内核会把这个 fd 标记为“不可读”,于是 select 会直接阻塞(睡觉),并不会触发 FD_ISSET(fd, &tmp)。

当在终端输入数据结束后按下回车键,此时内核会将位图0号位置1,再继续向后遍历(一共遍历maxfd+1次),若管道有数据则将管道对应的文件描述符置1,遍历结束,内核将位图返回给应用层,通过FD_ISSET进行业务处理。

2.poll

特点:

1. 使用链表保存文件描述符集合,允许监测的文件描述符没有上限限制;
2. 创建的文件描述符集合在应用层,需要应用层和内核层的反复数据拷贝;
3. 应用层对于返回的事件结果需要遍历查找;
4. poll只能工作在水平触发模式(低速模式,高电平时),无法工作在边沿触发模式(高速模式,电平变化时)。

3.epoll

特点:
1. 使用树形结构(红黑树)保存文件描述符集合,没有文件描述符上限限制,并且查找效率高;
2. 文件描述符集合创建在内核层,避免了应用层和内核层的反复数据拷贝;
3. 直接返回到达事件的文件描述符集合;
4. epoll可以工作在水平触发模式(低速模式),也可以工作在边沿触发模式(高速模式);

1000并发量以内select与epoll性能差不多,epoll机制比select更复杂一些

1. 创建文件描述符集合

int epoll_create(int size);
功能:创建epoll的文件描述符集合
参数:
size :允许监测的文件描述符的个数
返回值:
成功:返回文件描述符句柄。
失败:-1

    int epfds = epoll_create(MAX_FD_CNT);
    if(epfds < 0)
    {
        perror("epoll_create error");
        return -1;
    }

2. 添加文件描述符到集合(内核创建的红黑树里)

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:对文件描述符集合中的文件描述符做操作
参数:
epfd:epoll创建的文件描述符集合
op:操作方法:
        EPOLL_CTL_ADD :添加操作
        EPOLL_CTL_MOD :修改操作
        EPOLL_CTL_DEL :删除操作
fd :要操作的文件描述符
event:epoll事件结构体
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 :写事件
返回值:
成功:0
失败:-1

void add_epoll_fd(int epfd, int fd, int events)
{
    struct epoll_event ev;
    ev.data.fd = fd;
    ev.events = events;
    int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
    if(ret < 0)
    {
        perror("epoll_ctl error");
        return;
    }
}
void del_epoll(int epfd,int fd)
{
    int ret = epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);
    if(ret < 0)
    {
        perror("epoll_ctl error");
        return;
    }
    return;
}

3. 通知内核开始监测事件

int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
功能:通知内核开始监测事件
参数:
epfd:监测的文件描述符句柄(集合)
events :保存epoll返回的到达事件的集合
maxevents:最多监测的事件个数
timeout:设置超时时间
-1 :不设置超时,一直阻塞等待
返回值:
成功:实际到达的事件的个数
失败:-1
0 :超时时间到达,却没有事件返回时

        int epfds = epoll_create(MAX_FD_CNT);
        struct epoll_event events[MAX_FD_CNT];
        int cnt = epoll_wait(epfds, events, MAX_FD_CNT, -1);
        if(cnt < 0)
        {
            perror("epoll_wait error");
            return -1;
        }

  • select 每次都要重新传参:每次调用 select,内核都必须把用户态传进来的 fd 集合全部遍历一遍(线性扫描),还要重新构建内部数据结构。

  • epoll 一次注册,永久有效:epoll_ctl 把 fd 的红黑树建在内核里,epoll_wait 只需要直接去查看就绪链表(rdllist)是否为空就行了。如果没有事件,进程阻塞;如果有,内核直接把就绪链表里的数据拷贝到用户态数组里。

sockfd (监听) → 注册 EPOLLIN → 客户端连接到达 → 全连接队列非空 → epoll 触发 sockfd 可读
→ 循环检测到 evs[i].data.fd == sockfd → 调用 accept → 得到 connfd → 注册 connfd 的 EPOLLIN
→ 后续客户端消息会触发 connfd 的可读事件,由其他分支处理 recv

17、扩展景深成像的瞳孔函数工程技术解析 本文详细解析了扩展景深成像的关键技术,包括基于焦距堆栈的数字处理方法、立方相位掩模的光学设计、对数非球面透镜的应用以及旋转点扩散函数的深度编码功能。通过实验验证和实际应用分析,展示了这些技术在显微镜成像、工业检测和医疗影像中的广泛用途及优势。同时探讨了未来发展方向,如智能算法优化、新型光学材料和多模态成像技术,为相关领域的技术创新提供了参考。 阅读详情

相关推荐

用R搞定生态溯源:MixSIAR贝叶斯混合模型从安装到出图的保姆级教程

本文提供了一份详细的MixSIAR贝叶斯混合模型教程,涵盖从R环境配置、数据预处理到模型参数设置和可视化分析的完整流程。通过实战案例和常见问题解决方案,帮助生态学研究者快速掌握混合模型在生态溯源中的应用,提升数据分析效率。

weixin_42531516的博客 467

linux tcp服务器并发,Linux网络编程——tcp并发服务器(epoll实现)

Linux网络编程——tcp并发服务器(epoll实现)2018-09-22通过epoll实现tcp并发回执服务器(客户端给服务器发啥,服务器就给客户端回啥)代码如下:[csharp]view plaincopy#include#include#include#include#include#include#include#include#include#include#i...

weixin_31542739的博客 336

ISCC-Amy‘s Code CTF-Reverse

ISCC-Amy's Code CTF-Reverse

m0_72904009的博客 682

Linux网络编程:TCP多进程/多线程并发服务器详解

Linux网络编程:TCP多进程/多线程并发服务器详解在Linux网络编程中,TCP服务器主要有三种并发模型:本文将重点讲解多进程和多线程实现方式,并分析关键技术和常见问题。2.1 核心代码解析 2.2 关键技术点 • 允许服务器快速重启而不需要等待TIME_WAIT状态结束• 避免"Address already in use"错误 • 子进程退出后会变成僵尸进程• 通过信号处理或显式wait/waitpid回收资源重要原则:只有当所有进程都关闭了文件描述符,内核才会真正释放资源。• 父进程需要关闭客户端

2301_80067496的博客 1177

C#中使用OpenCV的常用函数

c# opencv 常见操作

大黄鸭在发光的专栏 1080

AI中台系统设计方案探讨

集成JupyterLab、低代码建模工具(如H2O.ai)、预训练模型库(Hugging Face、PaddleHub)。:通过REST/gRPC接口封装AI能力(如OCR、语音识别),支持流量控制与鉴权(如Kong、Apigee)。:服务注册发现(Consul)、熔断降级(Hystrix)、监控告警(Prometheus+Grafana)。:分布式存储(如HDFS、Ceph)与对象存储(如S3、OSS),支持海量数据高速读写。加密传输(TLS)、动态脱敏(如数据掩码)、访问控制(RBAC)。

reset2021的博客 1033

Linux网络编程核心实践:TCP/UDP socket与epoll高并发服务器构建

本篇博文是Linux网络编程的全面深度指南,带领读者从零开始构建一个完整、坚实的知识体系。文章分为三大板块:首先,基础理论篇系统地梳理了TCP/IP五层模型,通过命令行工具验证了从数据链路层到应用层的核心协议(ARP, IP, TCP/UDP)与数据封装过程;其次,实战编程篇详细讲解了socket编程的核心API,通过编写TCP和UDP的回射服务器,让读者亲手实践连接建立、数据交换和地址管理的完整流程,并最终通过一个epoll版的TCP服务器实战,展示了如何构建高并发网络应用。本文是理论与实践紧密结合的典范

weixin_52342399的博客 1099

Windows 2012 SYSVOL复制失败的处理

题外话:晓原理、知架构、查日志是排错的三件法宝今天在DC1上新建并链接了一个组策略对像,在客户端刷新时,却报下面的错误:“处理组策略失败。Windows无法应用组策略对象LDAP….”如下图所示:于是在客户端用\\domain.com访问,发现\\domain.com\SYSVOL\domain.com\policies下面没有上面报错的组策略对象。这是怎么一回事呢,pin...

weixin_33989780的博客 1669

Linux网络编程04-TCP并发服务器

本文围绕并发服务器展开,重点梳理Linux常用I/O模型体系。先介绍并发服务器基础概念,再系统讲解阻塞I/O、非阻塞I/O、信号驱动I/O三类基础模型,核心聚焦I/O多路复用技术,深入剖析select与epoll的实现机制、核心差异,并结合实际场景说明其适用范围,为高并发网络编程提供清晰的技术选型依据。

weixin_53143624的博客 813

ElectrolyteGPT:首个电池电解液逆向设计的生成式 AI 系统 —— 算法原理与复现解析

数据驱动的重要性:1100 万→100 万的精心筛选,比单纯增大模型更有效领域适配:fLine 表示法、正则分词、化学感知的数据增强(SMILES randomization)都是关键小模型的力量:6M 参数在特定化学空间的表现,远超通用大模型在相同任务上的零样本能力条件生成的极限:10 维条件导致模型崩溃,提示我们需要更好的条件编码策略(如 diffusion guidance、RLHF-style 偏好优化)未来方向配方实验验证。

ASKCOS博客 123

Python 爬虫实战:豆瓣电影海报批量获取(Top250 榜单 + 可视化展示)

在信息爆炸的时代,数据已成为决策的核心,而数据的获取是数据分析的第一步。本文将详细介绍如何利用 Python 爬虫获取豆瓣电影 Top250 榜单的海报,并对数据进行可视化展示,助你更好地了解电影市场的趋势和用户的喜好。

yansideyucsdn的博客 718

Linux网络编程——tcp并发服务器(多进程)

http://blog.youkuaiyun.com/lianghe_work/article/details/46503895 一、tcp并发服务器概述 一个好的服务器,一般都是并发服务器(同一时刻可以响应多个客户端的请求)。并发服务器设计技术一般有:多进程服务器、多线程服务器、I/O复用服务器等。 二、多进程并发服务器 在 Linux 环境下多进程的应用

sinat_35297665的博客 988

Claude Code 100个真实案例 - 用AI绘制CAD机械图纸(工程师看了直呼内行)

本案例展示如何使用 Claude Code 配合 Python 的 `ezdxf` 库,从零开始生成专业级 CAD 机械图纸。我们将绘制一个完整的法兰盘零件图,包含主视图、俯视图、标注尺寸、粗糙度标记和标题栏,最终生成标准 DXF 文件,可直接在 AutoCAD 或 FreeCAD 中打开编辑。

yueyeguzhuo的专栏 895

C/C++ Linux网络编程4 - 解决TCP服务器并发的方式

本文介绍了两种实现TCP服务器并发处理的方法:多进程和多线程。通过fork()创建子进程管理客户端连接,并采用"孙子进程"策略避免僵尸进程问题;同时演示了使用C++11线程库实现多线程服务器的方式。文章提供了完整的代码实现,包括socket初始化、HTTP响应处理等核心功能,并通过网络调试工具和wrk性能测试对比了两种方案的效率。测试结果表明多线程方式在并发性能和资源消耗方面表现更优,同时文章也指出了高并发场景下服务器可能面临的稳定性问题。

yzc的博客 1420

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Linux网络编程:TCP并发服务器实现

本文通过多进程和多线程技术进行的TCP并发服务器的实现,在多进程方式下,解决了僵尸进程的问题。最后通过完成代码的编写并测试,成功实现了TCP并发服务器。

weixin_42937740的博客 1276

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

linux网络编程-----TCP的并发服务器构建

为了解决多线程(多进程)模型,在服务器运行过程中,频繁创建和销毁线程(进程)带来的时间消耗问题(基于生产者和消费者编程模型,以及任务队列等,实现的一套多线程框架)。对多个文件描述符的读写可以复用一个进程(在不创建新的进程和线程的前提下,使用一个进程实现对多个文件读写的同时监测)。④当内核检测到事件时,应用层select将解除阻塞,并获得相关的事件结果。检查指定的文件描述符是否在集合中,是则返回非零值。从文件描述符集合中移除指定的文件描述符。清空文件描述符集合,移除所有文件描述符。

2403_88096060的博客 598

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Linux 网络编程:TCP 通信基础、并发服务器与 IO 多路复用详解

监控超时阻塞时间可以精确到微秒:select 使用结构体,可以精确设置秒和微秒级别的超时时间。跨平台兼容性好:select 不仅仅在 Linux 下可以使用,在 Windows、macOS 以及其他 Unix-like 系统上也得到广泛支持。相较于 select 在操作上有所简化,不需要定义多个事件集合,也不需要每次重置集合所能监控的描述符数量,是没有限制的特性selectpollepollfd 上限默认 1024无限制无限制内核机制每次全量拷贝 fd 集合、轮询遍历。

yz040724的博客 327

Linux C语言TCP网络编程实战:从Socket到epoll并发服务器

网络编程是现代软件开发的基石,其核心在于实现不同主机间进程的可靠通信。TCP协议通过三次握手建立连接、四次挥手断开连接,并利用序列号、确认应答和重传机制,确保了数据传输的可靠性与顺序性。这一技术价值在于为上层应用提供了稳定的字节流传输服务,是构建Web服务器、即时通讯、分布式系统等高性能网络应用的基础。在实际工程中,开发者通过操作系统提供的Socket API进行编程,需要处理地址绑定、端口监听、连接建立、数据收发以及资源释放等关键步骤。针对高并发场景,I/O多路复用技术如epoll模型成为提升服务器性能的

weixin_30325487的博客 945

Linux网络编程——服务器类型与TCP并发服务器构建(SELECT)

本文介绍了TCP并发服务器的四种实现方案:1)多进程模型通过fork()创建子进程处理请求,资源开销大但安全性高;2)多线程模型采用pthread_create创建线程,开销低于进程;3)线程池模型预先创建线程处理任务队列,避免频繁线程创建销毁;4)IO多路复用通过select/poll/epoll监控多个文件描述符,单进程即可处理多客户端。重点解析了select实现流程:定义fd集合、添加关注fd、内核监控事件、处理触发事件,并提供了详细代码示例,比较了各方案的资源开销和并发能力差异。

weixin_69590097的博客 1160

Linux网络编程——tcp并发服务器(poll实现)

想详细彻底地了解poll或看懂下面的代码请参考《Linux网络编程——I/O复用之poll函数》 代码: [csharp] view plain copy #include    #include    #include    #include    #include    #include    #include    #i

u010871058的专栏 959

Linux网络编程--TCP并发服务器

一.并发服务器模型 常用的TCP服务器模型,我们上节写的是TCP循环服务器模型,这种模型很大的弊端就是没办法实现并发,在此基础上进行优化,就出现了多线程和多进程的服务器。 他们的解决思路都是相同的,他们的数据处理都是单独在开一个线程或者进程进行处理。 多线程和多进程的服务器模型是比较常见的,他们之间各具优势,需要根据不同应用场景进行选择。 二.多线程并发实例 客户端的实现和之前的代码相同,不做重点关注。 server.c #include <pthread.h> #include

EmbeddedCoder 的优快云博客 664

Linux网络编程 TCP---并发服务器:多进程架构与端口复用技术实战指南

并发服务器、多进程、端口复用 本文深入解析基于多进程的并发服务器实现原理,涵盖监听套接字创建、父子进程职责分工(父进程管理连接请求,子进程处理客户端通信)、信号回收子进程等核心流程,并提供完整代码示例。同时,针对服务器重启后端口占用问题,详述端口复用技术(setsockopt与SO_REUSEADDR)的作用与实现方法,确保服务快速重启。通过理论与实践结合,帮助开发者优化网络程序稳定性和响应效率

2401_87244387的博客 1073
上一篇: Liunx网络编程-应用层
下一篇: Linux网络编程-sqlite数据库
剑指offer.
博客等级 码龄3年 15粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值