Linux C/C++ 多线程TCP/UDP服务器 (监控系统状态)

news2024/9/23 1:36:26

Linux环境中实现并发TCP/IP服务器。多线程在解决方案中提供了并发性。由于并发性,它允许多个客户端同时连接到服务器并与服务器交互。

Linux多线程编程概述

许多应用程序同时处理多项杂务。服务器应用程序处理并发客户端;交互式应用程序通常在处理后台计算时处理用户输入;计算密集型应用程序利用多个处理器的功能。共同的主题是使用多个控制线程来提供处理并发活动的上下文,无论是在一个处理器上多路复用、在多个处理器上并行执行,还是利用具有“超线程技术”的处理器以及AMD和Intel的新双核处理器的设施。

协调这些线程的执行涉及同步对共享数据结构的访问,确保程序行为良好且具有确定性,而不管其组件线程的相对执行速度如何。多线程程序和单线程程序一样,必须处理异常和与外界的交互。尽管在这样的程序中可能有许多并发活动,但程序作为一个整体应该对这样的外部输入做出清晰的响应。

线程的实现方式有很多种,包括用户级库、内核和各种组合。大多数Linux实现目前将每个线程视为使用克隆系统调用创建的单独进程(尽管每个线程都与其队列共享其地址空间)。

C/C++ 多线程并发服务器知识点

  • 多线程并发服务器思路
1. socket(),创建监听套接字
2. bind(),绑定监听套接字
3. setsockopt(),设置端口复用
4. listen(),监听状态,用来被动接受来自其他主动套接字的连接请求,并设置监听上限
5. pthread_attr_init()pthread_attr_setdetachstate()pthread_create(),在创建时指定属性
6. pthread_rwlock_wrlock()pthread_rwlock_unlock(),并发程序引起的共享内存问题
...

Linux C/C++ 多线程TCP/UDP服务器 (监控系统状态)

目的:使用TCP/IP实现多线程客户端服务器。它允许多个客户端同时连接到服务器并与服务器交互。处理多线程TCP/UDP服务器监控系统状态:监控CPU负载、RAM使用情况、磁盘空间使用情况和可用网络接口。

服务器:

启动服务器并接受来自客户端的连接。在接受客户机连接后,它分派一个线程与客户机交互。

...
int main(int argc, char *argv[])
{
    if (argc != 4)
    {
        printf ("Usage: %s <TCP/UDP> <port> <max_connections>\n", argv[0]);
        return 0;
    }

    if (strncmp ("TCP", argv[1], 3) == 0)
    {
        printf ("Using TCP");
        protocol = TCP;
    }
    else if (strncmp ("UDP", argv[1], 3) == 0)
    {
        printf ("Using UDP");
        protocol = UDP;
    }
    else
    {
        printf ("Unknown protocol: %s\n", argv[1]);
        printf ("Usage: %s <TCP/UDP> <port> <max_connections>\n", argv[0]);
        return 0;
    }

    const int port = atoi (argv[2]);

    if (!port)
    {
        printf ("Wrong port number: %s\n", argv[2]);
        printf ("Usage: %s <TCP/UDP> <port> <max_connections>\n", argv[0]);
        return 0;
    }

    const int max_connections = atoi (argv[3]);

    if (!max_connections)
    {
        printf ("Wrong max_connections number: %s\n", argv[3]);
        printf ("Usage: %s <TCP/UDP> <port> <max_connections>\n", argv[0]);
        return 0;
    }

    printf (" on port %i with no more than %i clients\n", port, max_connections);

    /* Assign signal handlers to signals. */

    if (signal (SIGPIPE, SIG_IGN) == SIG_ERR)
    {
        perror ("signal");
        exit (EXIT_FAILURE);
    }
    if (signal (SIGTERM, signal_handler) == SIG_ERR)
    {
        perror ("signal");
        exit (EXIT_FAILURE);
    }
    if (signal (SIGINT, signal_handler) == SIG_ERR)
    {
        perror ("signal");
        exit (EXIT_FAILURE);
    }

    pthread_attr_t pthread_attr;
    pthread_arg_t *pthread_arg;
    pthread_t pthread;

	//为属性对象分配了动态内存空间
    if (pthread_attr_init (&pthread_attr) != 0)
    {
        perror("pthread_attr_init");
        exit (EXIT_FAILURE);
    }
	//设置线程分离状态
    if (pthread_attr_setdetachstate (&pthread_attr, PTHREAD_CREATE_DETACHED) != 0)
    {
        perror("pthread_attr_setdetachstate");
        exit (EXIT_FAILURE);
    }

    // 开始观测
	//指定已初始化的读写锁
    pthread_rwlock_init (&rwlock, NULL);
    if (pthread_create (&pthread, &pthread_attr, pthread_sysinfo, NULL) != 0)
    {
        perror("pthread_create");
        exit (EXIT_FAILURE);
    }

    struct addrinfo hints;
    struct addrinfo *result, *rp;
    int socket_fd;

    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = (protocol == TCP) ? SOCK_STREAM : SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE;
    hints.ai_protocol = 0;
    hints.ai_canonname = NULL;
    hints.ai_addr = NULL;
    hints.ai_next = NULL;

    int s = getaddrinfo(NULL, argv[2], &hints, &result);
    if (s != 0)
    {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
        exit(EXIT_FAILURE);
    }

    for (rp = result; rp != NULL; rp = rp->ai_next)
    {
        socket_fd = socket(rp->ai_family, rp->ai_socktype,
                           rp->ai_protocol);
        if (socket_fd == -1)
            continue;

        if (bind(socket_fd, rp->ai_addr, rp->ai_addrlen) == 0)
            break;                  /* Success */

        close (socket_fd);
    }

    if (rp == NULL)                 /* No address succeeded */
    {
        fprintf(stderr, "Could not bind\n");
        exit (EXIT_FAILURE);
    }

    freeaddrinfo (result);

    if (protocol == UDP)
    {
        struct timeval timeout = {5, 0};
		//设置端口复用
        setsockopt (socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(struct timeval));

        for (;; udp_reply (socket_fd));
    }

    if (listen (socket_fd, BACKLOG) == -1)
    {
        perror ("listen");
        exit (EXIT_FAILURE);
    }

    while (protocol == TCP)
    {
        pthread_arg = (pthread_arg_t *) malloc (sizeof *pthread_arg);
        if (!pthread_arg)
        {
            perror ("malloc");
            exit (EXIT_FAILURE);
        }

        socklen_t client_address_len = sizeof pthread_arg->client_address;
        int tcp_socket_fd = accept (socket_fd, (struct sockaddr *)&pthread_arg->client_address,
                                    &client_address_len);

        connections++;

        if (tcp_socket_fd == -1)
        {
            perror ("accept");
            free (pthread_arg);
            exit (EXIT_FAILURE);
        }
        else if (connections > max_connections)
        {
            close (tcp_socket_fd);
            connections--;
            free (pthread_arg);
            continue;
        }

        printf ("New TCP connection accepted: now there are %i clients\n", connections);
        pthread_arg->new_socket_fd = tcp_socket_fd;
        if (pthread_create (&pthread, &pthread_attr, pthread_routine_tcp, (void *)pthread_arg) != 0)
        {
            perror("pthread_create");
            free (pthread_arg);
            exit (EXIT_FAILURE);
        }
    }
    return 0;
}
...
void *pthread_sysinfo ()
{
    char *s = system_state_report ();
    strcpy (system_state, s);
    free (s);

    for (;;)
    {
        if (connections > 0 || protocol == UDP)
        {
            s = system_state_report ();
            pthread_rwlock_wrlock (&rwlock);
            strcpy (system_state, s);
            pthread_rwlock_unlock (&rwlock);
            free (s);
        }
    }
    return NULL;
}

void signal_handler (int signal_number)
{
    /* Exit cleanup code here. */
    // close (socket_fd);
    exit (EXIT_SUCCESS);
}
...
char *system_state_report ()
{
    json_t *root = json_loads (BLANC_JSON_REPORT, 0, NULL);

    cpu_usage (json_object_get(root, "CPU, %"));
    ram_usage (json_object_get(root, "RAM"));
    storage_usage (json_object_get(root, "Storage"));
    net_usage (json_object_get(root, "Network"));

    time_stamp (root);

    char *s = json_dumps (root, 0);

    json_decref (root);
    return s;
}

int cpu_usage (json_t *cpu_state)
{
    char buff[TXT_BUFFER_SIZE][TXT_BUFFER_SIZE];
    int ncpu = get_nprocs ();

    FILE* fp = fopen(STAT_PATH,"r");
    for (int i = 0; i < ncpu + 1; i++)
    {
        fgets(buff[i], TXT_BUFFER_SIZE, fp);
    }
    fclose(fp);

    sleep(TIME_LAG);

    fp = fopen(STAT_PATH,"r");
    for (int i = 0; i < ncpu + 1; i++)
    {
        fgets(buff[i + ncpu + 1], TXT_BUFFER_SIZE, fp);
    }
    fclose(fp);

    for (int i = 0; i < ncpu + 1; i++)
    {
        long long sum = 0, lastSum = 0;
        long long idle, lastIdle;

        char* token = strtok(buff[i], " ");

        for (int col = 0; token != NULL;)
        {
            token = strtok (NULL, " ");
            if (token != NULL)
            {
                lastSum += atoll (token);
                if (col == 3)
                    lastIdle = atoll (token);
                col++;
            }
        }
...

        int cpu_usage_pct = (1000 *((sum - lastSum) - (idle - lastIdle)) / (sum - lastSum) + 5) / 10;
        json_t *json_cpu_pct;
        json_cpu_pct = json_integer(cpu_usage_pct);
        json_array_append (cpu_state, json_cpu_pct);
        json_decref (json_cpu_pct);
    }
    return 0;
}

...

客户端:
与服务器交互。通常,会使用write将消息中的消息发送到服务器,并使用read从服务器接收消息并将其存储在消息中。

...
int main(int argc, char *argv[])
{
...

    if (argc < 4)
    {
        fprintf (stderr, "Usage: %s <host> <port> <update_time (seconds)>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    const int time_lag = atoi (argv[3]);

    if (!time_lag)
    {
        fprintf( stderr, "Impossible time lag: %s\n", argv[3]);
        exit(EXIT_FAILURE);
    }



    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;     /* Allow IPv4 or IPv6 */
    hints.ai_socktype = 0;           /* Any type: TCP/UDP */
    hints.ai_flags = 0;
    hints.ai_protocol = 0;           /* Any protocol */

    s = getaddrinfo(argv[1], argv[2], &hints, &result);
    if (s != 0)
    {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
        exit(EXIT_FAILURE);
    }

    for (rp = result; rp != NULL; rp = rp->ai_next)
    {
        sfd = socket(rp->ai_family, rp->ai_socktype,
                     rp->ai_protocol);
        if (sfd == -1)
            continue;

        if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
            break;

        close(sfd);
    }

    if (rp == NULL)
    {
        fprintf (stderr, "Could not connect to server %s at port: %s\n", argv[1], argv[2]);
        exit(EXIT_FAILURE);
    }

    freeaddrinfo(result);

    // Server interaction.

    for (;; sleep (time_lag))
    {
        char msg[BUF_SIZE];
        char s[BUF_SIZE];
        bzero (msg, BUF_SIZE);

        write (sfd, "report", 6);
        int server_response = read (sfd, msg, BUF_SIZE);
        if (server_response <= 0)
        {
            printf ("Connection is closed by server\n");
            break;
        }
        status (msg, s);
        printf ("%s\n", s);
    }

...
}

int status (const char *src, char *report)
{
...

    int ncpu = json_array_size (cpu_status);
    int tot_cpu_usage = json_integer_value (tot_cpu_load);

    char buff[BUF_SIZE];

    sprintf (report, "Total usage of %2i CPUs: %3i%%, ", ncpu - 1, tot_cpu_usage);

    int mem_tot  = json_integer_value (json_object_get (ram_status, "Total"  ));
    int mem_free = json_integer_value (json_object_get (ram_status, "Free"   ));
    int mem_buff = json_integer_value (json_object_get (ram_status, "Buffers"));
    int mem_cach = json_integer_value (json_object_get (ram_status, "Cached" ));

    int mem_not_used = mem_free + mem_buff + mem_cach;
    int mem_used = mem_tot - mem_not_used;

    sprintf(buff, "Memory: %.1f MB used, %.1f MB free", mem_used/1024.0, mem_not_used/1024.0);
...
}

If you need the complete source code, please add the WeChat number (c17865354792)

运行结果:
打开两个客户端连接服务器,最后再同时断开连接服务器。


在这里插入图片描述

在客户端的请求消息报告中,作为响应,服务器给出系统当前状态的描述。

总结

多线程在解决方案中提供了并发性。由于并发性,客户端不必等待轮到他们,可以立即得到服务。当服务器有一个线程来处理新连接。接受这样的连接后,将创建一个新线程,负责与给定客户端的所有通信。最后要讲的是,熟悉多线程编程是一项重要的个人技能,只有掌握了多线程编程,才能更合理地选择使用或不使用多线程。

Welcome to follow WeChat official account【程序猿编码

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

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

相关文章

80211无线网络架构

无线网络架构物理组件BSS&#xff08;Basic Service Set&#xff09;基本服务集BSSID&#xff08;BSS Identification&#xff09;ssid&#xff08;Service Set Identification&#xff09;ESS&#xff08;Extended Service Set&#xff09;扩展服务集物理组件 无线网络包含四…

【C++学习】基础语法(三)

众所周知C语言是面向过程的编程语言&#xff0c;关注的是过程&#xff1b;解决问题前&#xff0c;需要分析求解的步骤&#xff0c;然后编辑函数逐步解决问题。C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事拆分成不同的对象&#xff0c;不同对象间交互解决问…

C++:类与对象

文章目录一.面向过程和面向对象的初步认识二.类1.类的初步认识2.类的定义3.类的访问限定符4.类的作用域5.类的实例化6.类对象模型三.this指针1.什么是this指针2.this指针的特性3.this指针的空指针问题四.浅谈封装五.类的默认成员函数1.构造函数1.1构造函数的概念1.2构造函数的用…

jenkins 安装 -适用于在线安装 后续写个离线安装的

jenkins安装1.下载jenkins2.安装启动3.附件卸载jdk的命令4.配置jenkins一、在jenkins配置文件中配置jdk环境变量二、修改jenkins默认的操作用户1.下载jenkins jenkins官网下载 https://www.jenkins.io/ 点击下载 我是centos系统所以选择centos&#xff0c;点击后按着官方提供…

golang简单实现chatgpt网页聊天

效果如图&#xff1a; 安装openai的sdk&#xff1a; go get github.com/sashabaranov/go-gpt3go代码&#xff1a; main.go package mainimport ("fmt""net/http""os"gogpt "github.com/sashabaranov/go-gpt3" )var client gogpt.N…

高可用 - 02 Keepalived_VRRP工作原理

文章目录Keepalived VS HeartbeatKeepalived的用途VRRP与工作原理物理路由器和虚拟路由器Keepalived VS Heartbeat Keepalived是Linux下一个轻量级的高可用解决方案&#xff0c;它与Heartbeat、RoseHA实现的功能类似&#xff0c;都可以实现服务或者网络的高可用&#xff0c;但…

SmS-Activate一款好用的短信验证码接收工具

前言 有些国外应用在使用应用上的功能时需要注册账号&#xff0c;由于某种不可抗因素&#xff0c;我们的手机号一般不支持注册&#xff0c;接收不到信息验证码&#xff0c;于是我们可以使用SmS-Activate提供的服务&#xff0c;使用$实现我们的需求&#xff08;大概一次验证1-5…

Python练习系统

用python给自己做个练习系统刷题吧&#xff01; #免费源码在文末公众号哈# 选择题 def xuanze():global flag2if flag21:def insert():numvar1.get()questionvar2.get()choicevar3.get()answervar4.get()with open(d:\\练习系统\\练习三3.1.pickle,rb) as file:lst1pickle.lo…

golang入门笔记——内存管理和编译器优化

静态分析 静态分析&#xff1a;不执行程序代码&#xff0c;推导程序的行为&#xff0c;分析程序的性质 控制流&#xff08;control flow&#xff09;&#xff1a;程序的执行流程 数据流&#xff08;data flow&#xff09;&#xff1a;数据在控制流上的传递 通过分析控制流和…

网络安全应急响应服务方案怎么写?包含哪些阶段?一文带你了解!

文章目录一、服务范围及流程1.1 服务范围1.2 服务流程及内容二、准备阶段2.1 负责人准备内容2.2 技术人员准备内容&#xff08;一&#xff09;服务需求界定&#xff08;二&#xff09;主机和网络设备安全初始化快照和备份2.3市场人员准备内容&#xff08;1&#xff09;预防和预…

全网最新的软件测试/自动化测试必问的面试题合集

1.你为什么选择软件测试行业因为之前有了解软件测试这个行业&#xff0c;觉得他的发展前景很好。2.根据你以前的工作经验描述一下软件开发、测试过程&#xff0c;由那些角色负责&#xff0c;你做什么要有架构师、开发经理、测试经理、程序员、测试员。我在里面主要是负责所分到…

曙光超算平台 如何使用 Tensorboard (乌镇中心)

在E-Shell中执行 1. salloc -p 队列名 -N 1 -n 32 --gresdcu:4 salloc -p wzhdtest -N 1 -n 32 --gresdcu:4 2. ssh 节点名 ssh g01r3n07 3. conda deactivate 4. 查看当前所有模块 module ava compiler 从上图中加载某个dtk模块 module load compiler/dtk/21.10 注&…

第九章 vue 进阶篇 Element Plus 基本使用

Element Plus 基本使用 element-ui 是基于vue 开发的一套ui组件库&#xff0c;提供丰富的网页开发组件&#xff0c;可用快速开发网站&#xff0c;降低前端开发成本 版本 element目前有两个版本 element-ui&#xff1a;基于vue2 element-plus: 基于vue3官网地址 https://elem…

JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)

文章目录前言一、了解JVM常用命令行参数1、命令行参数概述2、常用命令3、通过案例学命令行参数(Linux)4、区分概念二、GC日志详解1、打印详细日志2、日志描述3、解析案例三、调优前的基础概念四、调优是什么&#xff1f;1、调优1&#xff1a;JVM规划和预调优a、涨知识时刻b、概…

解決 torch 無法使用GPU

1.使用 import torch torch.cuda.is_available() ------> False print(torch.version) --> 查詢 torch 版本 2.命令行&#xff0c;輸入 nvidia-smi 3.直接去網站找出相對應版本 https://download.pytorch.org/whl/torch_stable.html cuda : 11.7 -> cu117 python3.…

分享95个HTML娱乐休闲模板,总有一款适合您

分享95个HTML娱乐休闲模板&#xff0c;总有一款适合您 95个HTML娱乐休闲模板下载链接&#xff1a;https://pan.baidu.com/s/1nBCV2kTy1csY3z8QRqXrsQ?pwd946p 提取码&#xff1a;946p Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 夜店娱乐网站模板 游戏模板…

mybatis条件构造器(二)

mybatis条件构造器(二) 1 准备工作 1.1 建表sql语句(Emp表) SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for emp -- ---------------------------- DROP TABLE IF EXISTS emp; CREATE TABLE emp (EMPNO int NOT NU…

2023年安徽省职业院校“磐云杯”网络安全竞赛任务书

2023年安徽省职业院校“磐云杯”网络安全竞赛 任务书 一、竞赛时间 总计&#xff1a;360分钟 三、竞赛任务书内容 &#xff08;一&#xff09;拓扑图 &#xff08;二&#xff09;A模块基础设施设置/安全加固&#xff08;200分&#xff09; 一、项目和任务描述&#xff1a;…

UML-时序图以及PlantUML绘制

介绍 时序图&#xff08;Sequence Diagram&#xff09;&#xff0c;又名序列图、循序图&#xff0c;是一种UML交互图。它通过描述对象之间发送消息的时间顺序显示多个对象之间的动态协作。它可以表示用例的行为顺序&#xff0c;当执行一个用例行为时&#xff0c;其中的每条消息…

Python基础4——面向对象

目录 1. 认识对象 2. 成员方法 2.1 成员方法的定义语法 3. 构造方法 4. 其他的一些内置方法 4.1 __str__字符串方法 4.2 __lt__小于符号比较方法 4.3 __le__小于等于符号比较方法 4.4 __eq__等号比较方法 5. 封装特性 6. 继承特性 6.1 单继承 6.2 多继承 6.3 pas…