【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)

大家都在看

  • Centos7 离线安装K3s

    1、安装前准备 github地址:https://github.com/k3s-io/k3s/releases k3s二进制文件:k3s下载地址:github地址 / 百度网盘地址…

    Linux 2023年6月7日
    0136
  • Jenkinsfile Pipeline 使用 SSH 连接

    为了在 Jenkinsfile 的命令中使用 SSH,我们不得不通过一些设置… 前提 首先你需要将用到的 SSH 私钥保存到 Jenkins 的凭据中,这样你会获得一个…

    Linux 2023年6月7日
    0111
  • 关于阿里云ECS Centos 5/6/7 Linux Glibc库严重安全漏洞修复方法

    本文来自转载http://www.shidehui.com/jingyan/about-ali-cloud-ecs-centos-567-linux-glibc-library-s…

    Linux 2023年6月13日
    0125
  • 三系统删除与恢复引导(windows,Ubuntu,deepin)

    三系统的删除与引导修复 一、情况说明: 相信能找到我这篇随笔的朋友估计也是我和一样作死装了三个系统,例如我的(Window10,Ubuntu,deepin) 从左往右为我装系统的顺…

    Linux 2023年6月14日
    092
  • Apache Shiro反序列化漏洞(Shiro550)

    1.漏洞原理: Shiro 是 Java 的一个安全框架,执行身份验证、授权、密码、会话管理 shiro默认使用了CookieRememberMeManager,其处理cookie…

    Linux 2023年6月13日
    070
  • CH343芯片应用—硬件设计

    CH343属于沁恒第三代USB转串口芯片系列的单串口型号,基于经典版CH340芯片完成技术革新,实现USB转高速异步串口,支持最高6Mbps串口波特率。 电源设计 CH343芯片有…

    Linux 2023年6月7日
    0161
  • Shell 脚本是什么?

    一个 Shell 脚本是一个文本文件,包含一个或多个命令。作为系统管理员,我们经常需要使用多个命令来完成一项任务,我们可以添加这些所有命令在一个文本文件(Shell 脚本)来完成这…

    Linux 2023年5月28日
    097
  • webshell 免杀

    https://xz.aliyun.com/t/11391 Original: https://www.cnblogs.com/cute/p/16356651.htmlAuthor…

    Linux 2023年5月28日
    0106
  • 搭建redis集群

    这里总结性给出搭建步骤: 1、 至少6个节点,三主三从 2、 编译redis源码 3、放置集群的配置文件redis.conf 创建工作目录: 每个文件夹下新建redis.conf …

    Linux 2023年5月28日
    085
  • Redis-cli连接

    原文:https://support.huaweicloud.com/usermanual-dcs/dcs-ug-0713004.html 介绍使用同一VPC内弹性云服务器ECS上…

    Linux 2023年5月28日
    0106
  • [云计算]OpenStack这一篇就够了!

    OpenStack简介 OpenStack背景介绍 OpenStack应用场景 OpenStack发展历程 OpenStack架构 架构设计原则 架构全景图 核心服务组件 系统通信…

    Linux 2023年6月13日
    0230
  • Java基础系列–07_String、StringBuffer和StringBuilder

    String类(1)字符串:字符串是 常量;它们的值在 创建之后不能更改,存储在堆中。如果字符串多次赋值,其实是每次重新赋值的时候程序都先在内存中寻找已开辟的空间是否存在该值;如果…

    Linux 2023年6月7日
    073
  • Macbook pro 2015-mid 15寸 安装Debian时所需无线网卡驱动

    https://pan.baidu.com/s/1o1oUZhK17fpgxpwH6bBkRQ?pwd=6kpt 把该文件放到u盘的firmware/目录下即可。 给自己留个备份,…

    Linux 2023年6月6日
    0125
  • 云主机实现校园网使用网络

    下载SoftEther 虚拟专用网络 Server 管理工具和 Open虚拟专用网络 GUI工具 配置云主机 tar -zxvf softether-vpnserver-v4.28…

    Linux 2023年6月8日
    085
  • springboot 工程出现 socket hang up

    出现socket hang up 原因为程序处理时间长,超出了默认请求超时时间,导致socket断开 可以通过设置请求超时时间降低出现的概率以下示例中设置请求超时时间为三分钟 sp…

    Linux 2023年6月8日
    0103
  • mysql字符串拼接

    Mysql数据库中的字符串 CONCAT()CONCAT_WS()GROUP_CONCAT() CONCAT() CONCAT(string1,string2)最常用的字符串拼接方…

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