【socket】基于socket通信-线程上报温度

线程是一条执行路径,是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。线程由CPU独立调度执行,在多CPU环境下就允许 多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理。

一个正在运行的软件(如迅雷)就是一个进程,一个进程可以同时运行多个任务( 迅雷软件可以同时下载多个文件,每个下载任务就是一个线程), 可以简单的认为进程是线程的集合。

线程是一条可以执行的路径。

对于单核CPU而言:多线程就是一个CPU在来回的切换,在交替执行。
对于多核CPU而言:多线程就是同时有多条执行路径在同时(并行)执行,每个核执行一个线程,多个核就有可能是一块同时执行的。

为什么要使用多线程
多线程可以提高程序的效率。

实际生活案例:村长要求喜洋洋在一个小时内打100桶水,可以喜洋洋一个小时只能打25桶水,如果这样就需要4个小时才能完成任务,为了在一个小时能够完成,喜洋洋就请美洋洋、懒洋洋、沸洋洋,来帮忙,这样4只羊同时干活,在一小时内完成了任务。原本用4个小时完成的任务现在只需要1个小时就完成了,如果把每只羊看做一个线程,多只羊即多线程可以提高程序的效率。

常用线程函数

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
功能:
用来创建一个线程
参数:
thread是一个pthread_t类型的指针,他用来返回该线程的线程ID。
pthread_attr_t *attr是结构体,定义如下
start_routine是一个函数指针,它指向的函数原型void *func(void*),这是创建的子线程要执行的任务(函数)
arg是传给了所调用的函数的参数,如果有多个参数需要传递给子线程则需要封装到一个结构体里传进去

typedef struct
{
    int     detachstate; 线程的分离状态
    int     schedpolicy; 线程调度策略
    struct sched_param schedparam; 线程的调度参数
    int     inheritsched; 线程的继承性
    int     scope; 线程的作用域
    size_t  guardsize; 线程栈末尾的警戒缓冲区大小
    int     stackaddr_set;
    void *  stackaddr; 线程栈的位置
    size_t  stacksize; 线程栈的大小
}pthread_attr_t;
int pthread_join (pthread_t tid, void ** status);
功能:
主线程等待子线程的终止。也就是在子线程调用了pthread_join()方法后面的代码,只有等到子线程结束了才能执行
参数:
thread: 线程标识符,即线程ID,标识唯一线程。retval: 用户定义的指针,用来存储被等待线程的返回值。

当调用 pthread_join() 时,当前线程会处于 阻塞状态,直到被调用的线程 结束后,当前线程才会 重新开始 执行。当 pthread_join() 函数返回后,被调用线程才算真正意义上的结束,它的 内存空间也会被释放(如果被调用线程是非分离的)

  • 被释放的内存空间仅仅是系统空间,你必须手动清除程序分配的空间,比如 malloc() 分配的空间。
  • 一个线程只能被一个线程所连接。
  • 被连接的线程必须是 非分离的,否则连接会 出错

作用:

  • 用于 等待其他线程结束:当调用 pthread_join() 时,当前线程会处于阻塞状态,直到被调用的线程结束后,当前线程才会重新开始执行。
  • 对线程的 资源进行回收:如果一个线程是非分离的(默认情况下创建的线程都是非分离)并且没有对该线程使用 pthread_join() 的话,该线程结束后并不会释放其内存空间,这会导致该线程变成了”僵尸线程”。
pthread_t pthread_self (void);
功能
获得线程自身的ID。
例如:
void* thread_func(void *arg)
{
    printf("thread id=%lu\n", pthread_self());
    return arg;
}
int main(void)
{
    pthread_t tid;
    pthread_create(&tid, NULL, thread_func, NULL);
    pthread_join(tid,NULL);
    return 0;
}
int pthread_detach (pthread_t tid);
功能:
pthread_detach用于是指定线程变为**分离**状态,就像进程脱离终端而变为后台进程类似
void pthread_exit (void *status);
功能:
终止线程

return 语句和 pthread_exit() 函数的含义不同,return 的含义是 返回,它不仅可以用于线程执行的函数,普通函数也可以使用;pthread_exit() 函数的含义是 线程退出,它专门用于结束某个线程的执行。

int pthread_attr_init(pthread_attr_t *attr);

功能:初始化一个线程属性对象
参数:*attr 线程属性结构体指针变量
返回值:0 - 成功,非0 - 失败
int pthread_attr_destroy(pthread_attr_t *attr);

功能:销毁一个线程属性对象
参数:*attr 线程属性结构体指针变量
返回值:0 - 成功,非0 - 失败
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);

功能:设置一个线程属性栈大小
参数:*attr 线程属性结构体指针变量 guardsize设置一个保护区大小
返回值:0 - 成功,非0 - 失败
int pthread_attr_setdetachstate(pthread_attr_t *attr,intdetachstate);

功能:修改线程的分离状态属性
参数:*attr 线程属性结构体指针变量 , intdetachstate 线程的分离状态属性(PTHREAD_CREATE_DETACHED)
返回值:0 - 成功,非0 - 失败

代码实现

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include "sqlite3.h"

#define BACKLOG 13
typedef void *(THREAD_BODY) (void *thread_arg);

void print_usage(char *progname);
void sig_stop(int signum);
int socket_listen(char *listen_ip, int port);
void sqlite_tem(char *buf);
int thread_start(pthread_t *thread_id ,THREAD_BODY* thread_workbody, void *thread_arg);
void* thread_worker(void *args);

static int g_stop = 0;

typedef struct worker_ctx_s
{
    pthread_mutex_t     lock;

}worker_ctx_t;

int main(int argc, char **argv)
{
    int                     rv;
    int                     ret;
    int                     opt;
    int                     idx;
    int                     port;
    int                     log_fd;
    int                     ch = 1;
    int                     daemon_run = 0;
    int                     ser_fd = -1;
    int                     cli_fd = -1;

    struct sockaddr_in      ser_addr;
    struct sockaddr_in      cli_addr;
    socklen_t               cliaddr_len = 20;
    worker_ctx_t            worker_ctx;
    pthread_t               tid;
    pthread_attr_t          thread_attr;

    struct option            opts[] = {
        {"daemon", no_argument, NULL, 'd'},
        {"port", required_argument, NULL, 'p'},
        {"help", no_argument, NULL, 'h'},
        {NULL, 0, NULL, 0}
    };

    while ((opt = getopt_long(argc, argv, "dp:h", opts, &idx)) != -1)
    {
        switch (opt)
        {
            case 'd':
                daemon_run = 1;
                break;
            case 'p':
                port = atoi(optarg);
                break;
            case 'h':
                print_usage(argv[0]);
                return 0;
        }
    }

    if (!port)
    {
        print_usage(argv[0]);
        return 0;
    }

    if (daemon_run)
    {
        printf("Program %s is running at the background now\n", argv[0]);

        log_fd = open("temper.log", O_CREAT | O_RDWR, 0666);
        if (log_fd < 0)
        {
            printf("Open the logfile failure : %s\n", strerror(errno));
            return 0;
        }

        dup2(log_fd, STDOUT_FILENO);
        dup2(log_fd, STDERR_FILENO);

        if ((daemon(1, 1)) < 0)
        {
            printf("Deamon failure : %s\n", strerror(errno));
            return 0;
        }
    }

    signal(SIGUSR1, sig_stop);

    pthread_mutex_init(&worker_ctx.lock,NULL);

    if( (ser_fd = socket_listen(NULL, port)) < 0 )
    {
        printf("ERROR: %s server listen on serv_port %d failure\n", argv[0], port);
        return -2;
    }
    printf("server start to listen on serv_port %d\n",  port);

    while (!g_stop)
    {

        cli_fd = accept(ser_fd, (struct sockaddr*) & cli_addr, &cliaddr_len);
        if (cli_fd < 0)
        {
            printf("Accept the request from client failure:%s\n", strerror(errno));
            continue;
        }
        thread_start(&tid ,thread_worker,(void*)cli_fd);
    }

    pthread_mutex_destroy(&worker_ctx.lock);
    close(ser_fd);
    return 0;
}

void *thread_worker(void *ctx)
{
    int                 rv;
    char                buf[1024];
    int                 cli_fd;
    worker_ctx_t        s;

    if( !ctx)
    {
        printf("Invalid input arguments in %s\n");
        pthread_exit(NULL);
    }

    cli_fd = (int)ctx;

    printf("Child thread start to commuicate with socket client...\n");
    while(1)
    {
        pthread_mutex_lock(&s.lock);

        memset(buf, 0, sizeof(buf));
        rv = read(cli_fd, buf, sizeof(buf));
        if( rv < 0)
        {
            printf("Read data from client sockfd[%d] failure: %s and thread will exit\n", cli_fd,strerror(errno));
            close(cli_fd);
            pthread_exit(NULL);
        }
        else if( rv == 0)
        {
            printf("Socket[%d] get disconnected and thread will exit.\n", cli_fd);
            close(cli_fd);
            pthread_exit(NULL);
        }
        else
        {
            printf("\n");
            printf("%s\n",buf);
            sqlite_tem(buf);
            printf("Database inserted successfully!\n");
            pthread_mutex_unlock(&s.lock);
        }
    }
    close(cli_fd);
    return 0;
}

int thread_start(pthread_t *thread_id ,THREAD_BODY* thread_workbody, void *thread_arg)
{
    int             rv = -1;
    pthread_attr_t  thread_attr;

    if(pthread_attr_init(&thread_attr))
    {
        printf("pthread_attr_init() failure :%s\n", strerror(errno));
        goto cleanup;
    }

    if(pthread_attr_setstacksize(&thread_attr,120*1024))
    {
        printf("pthread_attr_setstacksize() failure:%s\n",strerror(errno));
        goto cleanup;
    }

    if(pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED))
    {
        printf("pthread_attr_setdetachstate() failure :%s\n", strerror(errno));
        goto cleanup;
    }

    if(pthread_create(thread_id,&thread_attr, thread_workbody, thread_arg))
    {
        printf("create thread failure:%s\n",strerror(errno));
        goto cleanup;
    }
    rv = 0;

cleanup:
    pthread_attr_destroy(&thread_attr);
    return rv ;
}

void print_usage(char* progname)
{
    printf("-d(--daemon):let program run in the background.\n");
    printf("-p(--port):enter server port.\n");
    printf("-h(--help):print this help information.\n");

    return;
}

void sig_stop(int signum)
{
    if (SIGUSR1 == signum)
    {
        g_stop = 1;
    }

    return;
}

int socket_listen(char *listen_ip, int port)
{
    int                     rv = 0;
    int                     on = 1;
    int                     ser_fd;
    struct sockaddr_in      servaddr;

    if ( (ser_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
    {
        printf("Use socket() to create a TCP socket failure: %s\n", strerror(errno));
        return -1;
    }

    setsockopt(ser_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(port);

    if( !listen_ip )
    {
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    }
    else
    {
        if( inet_pton(AF_INET, listen_ip, &servaddr.sin_addr)  0 )
        {
            printf("Inet_pton() set listen IP address failure\n");
            rv = -2;
            goto cleanup;
        }
    }

    if( bind(ser_fd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )
    {
        printf("Use bind() to bind the TCP socket failure: %s\n", strerror(errno));
        rv = -3;
        goto cleanup;
    }

    if( listen(ser_fd, 64) < 0 )
    {
        printf("Use bind() to bind the TCP socket failure: %s\n", strerror(errno));
        rv = -4;
        goto cleanup;
    }

cleanup:
    if( rv < 0 )
        close(ser_fd);
    else
        rv = ser_fd;
    return rv;
}

void sqlite_tem(char *buf)
{
    int             nrow=0;
    int             ncolumn = 0;
    char          **azResult=NULL;
    int             rv;
    sqlite3        *db=NULL;
    char           *zErrMsg = 0;
    char            sql1[100];
    char           *ipaddr=NULL;
    char           *datetime=NULL;
    char           *temper=NULL;
    char           *sql = "create table if not exists temperature(ipaddr char(30), datetime char(50), temper  char(30))";

    ipaddr = strtok(buf,"/");
    datetime = strtok(NULL, "/");
    temper = strtok(NULL, "/");

    rv = sqlite3_open("tempreture.db", &db);
    if(rv)
    {
        printf("Can't open database:%s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return;
    }
    printf("opened a sqlite3 database named tempreture.db successfully!\n");

    int ret = sqlite3_exec(db,sql, NULL, NULL, &zErrMsg);
    if(ret != SQLITE_OK)
    {
        printf("create table fail: %s\n",zErrMsg);
    }

    if(snprintf(sql1,sizeof(sql1), "insert into temper values('%s','%s','%s')", ipaddr, datetime, temper) < 0)
    {
        printf("Failed to write data\n");
    }

    sqlite3_exec(db, sql1, 0, 0, &zErrMsg);
    sqlite3_free(zErrMsg);
    sqlite3_close(db);
    return;
}

使用多线程可以实现服务器和多个客户端得通信,使用多线程的方式,因为可以使用共享的全局变量,所以线程间的通信(数据交换)变得非常高效。
但是在Unix系统中,一个进程包含很多东西,包括可执行程序以及一大堆的诸如文件描述符地址空间等资源。在很多情况下,完成相关任务的不同代码间需要交换数据。
如果采用多进程的方式,进程的创建所花的时间片要比线程大些,另外进程间的通信比较麻烦,需要在 用户空间和内核空间进行频繁的切换,开销很大。所以多线程服务器对于 数据交换变得高效起来。

Original: https://www.cnblogs.com/Ye-Wei/p/16728600.html
Author: 西故黄鹤楼
Title: 【socket】基于socket通信-线程上报温度

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/606346/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • nginx-http响应头安全策略

    从nginx的http头文件的方面,利用参数设置开启浏览器的安全策略,来实现相关的安全机制。 add_header Content-Security-Policy "de…

    Linux 2023年6月6日
    0104
  • Guava 内存缓存的使用

    一、概述 guava⽬前有三种刷新本地缓存的机制: expireAfterAccess:当缓存项在指定的时间段内没有被读或写就会被回收。 expireAfterWrite:当缓存项…

    Linux 2023年6月16日
    0119
  • 在Linux命令行内的大小写转换

    在编辑文本时大小写常常是需要注意的地方,大小写的转换是很枯燥而繁琐的工作,所幸,Linux 提供了很多能让这份工作变得容易的命令。接下来让我们看看都有哪些完成大小写转换的命令。 t…

    Linux 2023年6月14日
    0121
  • 当前硬件版本不支持设备“nvme”。 vmx 未能启动虚拟机 2022-06-30T06:44:04.446Z In(05)+

    由于系统发生了dwm.exe内存泄露问题,为了处理就更新了一下系统,再 我打开VMware的时候运行不了虚拟机 再此记录一下: 发生此问题是硬件兼容性问题,解决办法: 根据VMMw…

    Linux 2023年6月8日
    0269
  • Python2中快速获取本地时区当天0点时间戳的一种方法

    如下所示,看了网上的几种方法,这种方法算是代码量比较小的,同时可以保证求的是本地时区的0点时间戳,返回的是浮点数,需要的话自己转一下int In [1]: import time …

    Linux 2023年6月6日
    0101
  • CentOS 7.x 用shell增加、删除端口

    一、在/usr/local/sbin/下创建port文件,不要扩展名,并给权限 chom 777 port 二、用法 #port add 8080 #port remove 808…

    Linux 2023年5月28日
    0100
  • Debian目录的生成及打包

    故事背景 做linux开发的一般都会涉及到deb包,那么我们如何制作deb包,debian目录中都有哪些文件以及他们的含义是什么呢?那么我们就带着这些疑惑去探索了。 探索之路 首先…

    Linux 2023年5月27日
    0147
  • LeetCode-补充题9. 36进制加法

    题目来源 题目详情 36进制由0-9,a-z,共36个字符表示。 要求按照加法规则计算出任意两个36进制正整数的和,如1b + 2x = 48 (解释:47+105=152) 要求…

    Linux 2023年6月7日
    0105
  • 多个USB转串口设备区分方法

    当计算机或者其他USB主机上使用多个USB转串口设备时,会遇到多个串口无法与具体的串口设备对应起来的问题,包括更换不同USB端口串口序号发生改变,多个设备USB插拔顺序不同导致串口…

    Linux 2023年6月7日
    067
  • 模板层

    过滤器 语法结构 {{ 数据对象|过滤器名称:参数 }} 过滤器最多只能额外传输一个参数 常见过滤器 标签 注意事项 在django模板语法中写标签的时候,只需要写关键字然后tab…

    Linux 2023年6月7日
    098
  • Redis 经验谈

    新浪作为全世界最大的Redis用户,在开发和运维方面有非常多的经验。本文作者来自新浪,希望能为业界提供一些亲身经历,让大家少走弯路。 使用初衷 从2010年上半年起,我们就开始尝试…

    Linux 2023年5月28日
    0100
  • Windows下PowerShell监控Keepalived

    一、 背景 某数据库服务器为CentOS,想要监控Keepalived的VIP是否有问题,通过邮件进行报警,但这台机器不能上外网,现在只能在Windows下通过PowerShell…

    Linux 2023年5月28日
    0101
  • Zabbix 使用心得总结

    zabbix 使用中部分功能总结1、监控采集的值(如磁盘空间、流量数据等)无需脚本进行单位转换,zabbix可自动转换为合适的单位 如采集的字节可自动转换为KB、MB 如果设置了单…

    Linux 2023年6月14日
    0156
  • 蓝桥杯国赛——循环小数

    时间限制: 1.0s 内存限制: 256.0MB 本题总分:20 分 【问题描述】已知 S 是一个小于 1 的循环小数,请计算与 S 相等的最简真分数是多少。例如 0 . 3333…

    Linux 2023年6月6日
    076
  • EKS助力小白实践云原生——通过k8s部署wordpress应用

    目前云原生在大厂已经有了充分的实践,也逐渐向小厂以及非互联网公司推广。适逢12月20日,腾讯云原生【燎原社】精心打造了云原生在线技术工坊,让零基础的同学也能快速入门和实践 Dock…

    Linux 2023年6月13日
    090
  • Docker镜像构建之Dockerfile

    在 Docker 中构建镜像最常用的方式就是使用 Dockerfile。Dockerfile 是一个用来构建镜像的文本文件。 官方文档:https://docs.docker.co…

    Linux 2023年5月27日
    0141
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球