Linux网络编程(高并发服务器)

news2024/12/24 2:37:17

文章目录

  • 前言
  • 一、什么是高并发服务器
  • 二、使用多线程和多进程实现高并发服务器的思路
  • 三、多进程服务器代码编写
  • 四、多线程服务器代码编写
  • 总结


前言

本篇文章带大家学习Linux网络编程中的高并发服务器。首先我们需要了解什么是高并发服务器,然后是学习如何来编写高并发服务器。

一、什么是高并发服务器

高并发服务器是指能够同时处理大量并发请求的服务器系统。在网络应用中,当多个用户或客户端同时请求服务器时,服务器需要能够高效地处理这些请求,并且保持良好的性能和稳定性。

高并发服务器的设计和实现需要考虑以下几个关键因素:

1.多线程或多进程处理:采用多线程或多进程的方式可以使服务器能够同时处理多个请求。每个线程或进程负责处理一个请求,从而提高服务器的并发处理能力。

2.异步非阻塞I/O:使用异步非阻塞I/O编程模型可以避免在请求处理过程中阻塞线程或进程,充分利用系统资源,提高服务器的并发处理性能。常见的方式是使用事件驱动的编程框架或库,例如Node.js的Event-driven I/O、Nginx的事件驱动模型等。

3.负载均衡:通过在服务器集群中引入负载均衡器,将请求分发到多个服务器节点上,可以进一步提高整个系统的并发处理能力。负载均衡器可以根据一定的策略(如轮询、权重等)将请求分发到不同的服务器,使得每个服务器都能够处理适量的请求。

4.缓存和分布式存储:合理地使用缓存和分布式存储可以降低服务器的负载并提高响应速度。将频繁访问的数据存储在缓存中,减轻对后端存储系统的压力。

5.水平扩展:通过增加服务器的数量来扩展系统的处理能力,例如增加服务器节点或使用云计算服务提供商的弹性伸缩功能。水平扩展可以使系统能够处理更多的并发请求。

二、使用多线程和多进程实现高并发服务器的思路

TCP通信中其实客户端连接上服务器后,服务器会新创建一个客户端出来与连接的客户端进行通信,而不是直接进行通信。这样的话我们就有思路了,我们需要让服务器一直处于accpet等待连接的状态,等待新的客户端连接上来,当有客户端连接上来后会创建一个新的客户端与之进行通信,那么我们就需要为这个客户端去创建一个线程或者是进程,这样的话就不会影响到服务器的接收新客户端的连接请求了。

在这里插入图片描述

三、多进程服务器代码编写

客户端连接服务器成功后就使用fork函数创建出子进程和客户端进行通信,父进程使用信号来对子进程进行回收。

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>

/*回收子进程*/
void catch_child(int sig) 
{
    pid_t pid;
    int status;
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) 
    {
        // 处理子进程的退出状态
    }
}

int main()
{
    int server = 0;
    struct sockaddr_in saddr = {0};
    int client = 0;
    struct sockaddr_in caddr = {0};
    socklen_t asize = 0;
    int len = 0;
    char buf[32] = {0};
    int r = 0;

    pid_t pid;

    server = socket(PF_INET, SOCK_STREAM, 0);

    if( server == -1 )
    {
        printf("server socket error\n");
        return -1;
    }

    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);
    saddr.sin_port = htons(8888);

    if( bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1 )
    {
        printf("server bind error\n");
        return -1;
    }

    if( listen(server, 128) == -1 )
    {
        printf("server listen error\n");
        return -1;
    }

    printf("server start success\n");

    while( 1 )
    {
        asize = sizeof(caddr);      
        client = accept(server, (struct sockaddr*)&caddr, &asize);

        if( client == -1 )
        {
            if (errno == EINTR)
            {
                // 信号中断,重新调用accept
                client = accept(server, (struct sockaddr*)&caddr, &asize);
            }
            else
            {
                perror("accept");
                printf("client accept error\n");
                return -1;
            }
        }   

        pid = fork();//创建子进程与客户端进行通信

        if(pid == 0)
        {
            close(server);
            while (1)
            {
                /*子进程*/
                len = read(client, buf, 1024);
                if(len == 0)
                {
                    printf("child exit\n");
                    close(client);
                    exit(1);//退出子进程
                }
                write(client, buf, len);
                printf("recv_buf : %s len : %d\n", buf, len);
                printf("child pid : %d\n", getpid());
            }                       
        }
        else if(pid > 0)
        {
            /*父进程*/
            struct sigaction act;
            sigemptyset(&act.sa_mask);
            act.sa_handler = catch_child;            
            act.sa_flags = 0;

            sigaction(SIGCHLD, &act, NULL);

            close(client);                    
        }
    }
    
    close(server);

    return 0;
}

四、多线程服务器代码编写

使用多线程的方法比多进程的方法简单一些,这里使用pthread_detach函数将线程进行分离,这样的话就不需要我们手动的去回收线程了,我们要做的就是在线程函数里面和连接上来的客户端进行通信就可以了。

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>

void* client_work(void* arg)
{
    int client = (int)arg;
    int len = 0;
    char buf[1024];

    while (1)
    {
        len = read(client, buf, 1024);
        if(len == 0)
        {
            printf("client is close\n");
            return NULL;
        }
        printf("read buf : %s\n", buf);
        write(client, buf, len);
    }    

    close(client);
    return NULL;
}

int main()
{
    int server = 0;
    struct sockaddr_in saddr = {0};
    int client = 0;
    struct sockaddr_in caddr = {0};
    socklen_t asize = 0;
    int len = 0;
    char buf[32] = {0};
    int r = 0;

    pid_t pid;

    server = socket(PF_INET, SOCK_STREAM, 0);

    if( server == -1 )
    {
        printf("server socket error\n");
        return -1;
    }

    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);
    saddr.sin_port = htons(8888);

    if( bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1 )
    {
        printf("server bind error\n");
        return -1;
    }

    if( listen(server, 128) == -1 )
    {
        printf("server listen error\n");
        return -1;
    }

    printf("server start success\n");

    while( 1 )
    {
        pthread_t tid;
        asize = sizeof(caddr);      
        client = accept(server, (struct sockaddr*)&caddr, &asize);

        if( client == -1 )
        {
            if (errno == EINTR)
            {
                // 信号中断,重新调用accept
                client = accept(server, (struct sockaddr*)&caddr, &asize);
            }
            else
            {
                perror("accept");
                printf("client accept error\n");
                return -1;
            }
        }

        pthread_create(&tid, NULL, client_work, (void*)client);   
        pthread_detach(tid);
    }
    
    close(server);

    return 0;
}

总结

本篇文章就讲解到这里。

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

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

相关文章

python——案例24:输出日历

案例24&#xff1a;输出日历import calendar #导入日历 yearint(2023) #设定年 moonint(8) #设定月print(calendar.month(year,moon))

黑客入侵:福特汽车Sync3车机存在漏洞,黑客入侵可抹除系统数据

据福特汽车公告&#xff0c;他们发现部分2021年至2022年车型的Sync3车机存在Wi-Fi漏洞&#xff0c;该漏洞可能被黑客利用来入侵并抹除车机内的系统数据。这一漏洞源于福特车系中采用的WL18xx MCP驱动程序的内存缓冲区溢位漏洞&#xff0c;其漏洞编号为CVE-2023-29468。 这一发现…

产品经理:实现一个微信输入框

近期在开发AI对话产品的时候为了提升用户体验增强了对话输入框的相关能力&#xff0c;产品初期阶段对话框只是一个单行输入框&#xff0c;导致在文本内容很多的时候体验很不好&#xff0c;所以进行体验升级&#xff0c;类似还原了微信输入框的功能&#xff08;只是其中的一点点…

matlab保存图片

仅作为记录&#xff0c;大佬请跳过。 即可。 参考 感谢大佬博主文章&#xff1a;传送门

Java算法_ 检查对称树(LeetCode_Hot100)

题目描述&#xff1a;给你一个二叉树的根节点 &#xff0c; 检查它是否轴对称。root 获得更多&#xff1f;算法思路:代码文档&#xff0c;算法解析的私得。 运行效果 完整代码 /*** 2 * Author: LJJ* 3 * Date: 2023/8/17 8:47* 4*/ public class SymmetricTree {static class…

Journal of Cheminformatics投稿经验分享

期刊名: Journal of Cheminformatics期刊名缩写:J CHEMINFORMATICS期刊ISSN:1758-2946E-ISSN:1758-29462023年影响因子/JCR分区:8.6/Q1SCI分区: CHEMISTRY, MULTIDISCIPLINARY 化学综合3区COMPUTER SCIENCE, INFORMATION SYSTEMS 计算机:信息系统2区COMPUTER SCIENCE, I…

AgentBench:AI智能体的应用前景——生产端的应用

生产端的应用 相比于消费端,AI智能体作为生产力工具的潜力则更为巨大。在现实中,很多工作需要专业化的数据作为支撑,通用化大模型显然不能胜任,这就给专用型的AI智能体留下了空间。在实践中,人们已经用大模型训练了不少专用的AI智能体。比如,不久前北京大学团队发行了一…

linux内核异步内存回收的另一个思路:基于冷热文件的冷热区域精准的回收冷文件页page(内核ko方案)

本文介绍的针对pagecache的异步内存回收方案与现有的思路有很大不同&#xff1a;内存回收的单位是一个个文件&#xff0c;再把文件的pagecache分成一个个小单元(或者叫区域)。提前判断出文件那些区域是频繁访问的(热区域)&#xff0c;哪些区域很少访问(冷区域)。异步内存回收线…

移动通信系统的LMS自适应波束成形技术matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ..................................................................... idxx0; while idxx&…

深入探索Java中的File类与IO操作:从路径到文件的一切

文章目录 1. File类的作用与构造方法2. File类常用方法&#xff1a;获取、判断和创建2.1 获取功能方法2.2 判断功能方法2.3 创建和删除功能方法2.4 目录的遍历方法 3. 递归&#xff1a;探索更深的层次代码示例&#xff1a;递归遍历文件夹 结论 &#x1f389;欢迎来到Java学习路…

AI极客日报0817 - 微软、亚马逊如何借助AI提升用户体验?

&#x1f440;AI 日报合集 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; 曾经&#xff0c;很多企业对ChatGPT的开放性表示担忧。如今&#xff0c;这些顾虑即将成为过去——微软带来了一个答案&#xff0c;推出了名为Azure ChatGPT的私有开源版本。那么&#xff0c;这一新版…

nodejs+vue+elementui多媒体作品信息共享平台开发_s2uq7

武理多媒体信息共享平台主要有管理员和用户两个功能模块。以下将对这两个功能的作用进行详细的剖析。 管理员模块&#xff1a;管理员是系统中的核心用户&#xff0c;管理员登录后&#xff0c;可以对后台系统进行管理。主要功能有个人中心、用户管理、作品分类管理、作品信息管理…

数据分析工具都有哪些?

简单介绍一下&#xff0c;数据分析是指适当的统计分析方法对收集来的大量数据进行分析&#xff0c;将它们汇总和理解消化&#xff0c;以求最大化地开发数据的功能&#xff0c;发挥数据的作用。 那么数据分析有哪些工具呢&#xff0c;是不是都需要掌握&#xff1f;当然不是的&am…

嵌入式设备应用开发(程序、静态库、动态库、配置文件)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 一个程序要想正确地在设备上运行起来,那么基本步骤就是,首先编写好程序代码,接着用交叉编译器编译出来,最后将这个程序拷贝到嵌入式设备上。然后,我们可以通过console控制台的…

【图像分类】基于卷积神经网络和主动学习的高光谱图像分类(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【使用 k 折叠交叉验证的卷积神经网络(CNN)】基于卷积神经网络的无特征EMG模式识别研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

4.Vue

1.什么是Vue Vue是一套前端框架&#xff0c;免除原生JavaScript中的DOM操作&#xff0c;简化书写。 基于**MVVM(Model-View-ViewModel)思想&#xff0c;实现数据双向绑定**&#xff0c;将编程的关注点放在数据上。 官网&#xff1a;https://v2.cn.vuejs.org/ 框架&#xff1…

Linux 5种网络IO模型

Linux IO模型 网络IO的本质是socket的读取&#xff0c;socket在linux系统被抽象为流&#xff0c;IO可以理解为对流的操作。刚才说了&#xff0c;对于一次IO访问&#xff08;以read举例&#xff09;&#xff0c;数据会先被拷贝到操作系统内核的缓冲区中&#xff0c;然后才会从操…

DDD 架构分层,MQ消息要放到那一层处理?

作者&#xff1a;小傅哥 博客&#xff1a;https://bugstack.cn 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01;&#x1f604; 本文的宗旨在于通过简单干净实践的方式教会读者&#xff0c;使用 Docker 配置 RocketMQ 并在基于 DDD 分层结构的 SpringBoot 工…

Nginx反向代理技巧

跨域 作为一个前端开发者来说不可避免的问题就是跨域&#xff0c;那什么是跨域呢&#xff1f; 跨域&#xff1a;指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的&#xff0c;是浏览器对javascript施加的安全限制。浏览器的同源策略是指协议&#xff0c;域名…