温度实时监控上报(服务器端--多进程、select、epoll)

温度实时监控上报

温度实时监控上报服务器端,分别采用多进程、多线程、多路复用来实现多个客户端并发访问。
多线程的实现在另一篇博客里,链接:(https://blog.csdn.net/cknfighting/article/details/106423698)

服务器端功能

1 ,通过命令行指定监听的端口;
2,程序放到后台运行,并通过syslog记录程序的运行出错、调试日志;
3, 程序能够捕捉kill信号正常退出;
4, 服务器要支持多个客户端并发访问,可以选择多路复用、多进程或多线程任意一种实现;
5, 服务器收到每个客户端的数据都解析后保存到数据库中,接收到的数据格式为: “ID/时间/温度”,如RPI0001/2019-0105 11:40:30/30.0C”;

多进程实现

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "sqlite3.h"

#define BACKLOG 13

//函数声明,打印帮助信息;捕捉信号并结束程序
void print_usage(char *progname);
void sig_stop(int signum);

//定义一个全局变量g_stop ,与sig_stop()函数配合,达到结束程序的目的
int g_stop = 0;

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;
    pid_t                   pid = -1;
    struct sockaddr_in      ser_addr;
    struct sockaddr_in      cli_addr;
    socklen_t               cliaddr_len = 20;
	/*命令行参数解析
		deamon:程序后台运行
		port:指定服务器开设端口
		help:打印帮助信息
	*/	
    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("receive_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;
        }
    }

	//安装SIGUSR1信号
    signal(SIGUSR1, sig_stop);

	//创建socket_fd,以供后续使用
	//第一个参数为协议域,这里使用AF_INET(32位ipv4地址、16位端口)
	//第二个参数为type,指定socket类型,这里使用SOCK_STREAM
	//第三个参数为指定协议,当其为0时,自动选择与type类型相对应的默认协议
    ser_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (ser_fd < 0)
    {
        printf("Creat socket failure:%s\n", strerror(errno));
        return 0;
    }
    printf("Creat the ser_fd[%d]!\n",ser_fd);

	//设置服务器地址信息
    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;		
    ser_addr.sin_port = htons(port);		//调用htons(),将端口号由主机字节序转变成网络字节序
     //设置服务器IP地址(INADDR_ANY,代表监听所有IP),并调用htonl(0,将其由主机字节序转变成网络字节序
    ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	//解决服务器程序停止后立刻运行,出现(端口)被占用的问题
    setsockopt(ser_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&ch, sizeof(ch));

	//绑定服务器地址(IP+端口),用于提供服务
    rv = bind(ser_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
    if (rv < 0)
    {
        printf("Bind server's port failure:%s\n", strerror(errno));
        return 0;
    }
    printf("The port[%d] has been bind by this server!\n",port);

	//调用listen(),将主动类型的socket套接字变为被动类型(等待客户端连接)
	//第一个参数为sockfd,指定所要监听的socket套接字,用于接收外部请求
	//第二个参数为backlog, TCP连接是一个过程,内核会在进程空间中维护一个连接队列以跟踪与服务器建立连接但还未着手处理的连接
    listen(ser_fd, BACKLOG);

    while (!g_stop)
    {
    	//接受来自客户端的请求,并创建一个cli_fd与客户端进行连接
        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;
        }

        pid = fork();		//调用fork(),实现多进程
        if (pid < 0)
        {
            printf("Creat child process failure:%s.\n", strerror(errno));
            continue;
        }
        else if (pid > 0)
        {
            close(cli_fd);	//父进程关闭cli_fd,保留ser_fd,等待与其他客户端连接
            continue;
        }
        else if (pid == 0)
        {
        	close(ser_fd);		//子进程关闭ser_fd,保留cli_fd,保持与客户端连接
        	
            int         a;
            int         len;
            char        *sn;
            char        *cut;
            char        *temp; 
            char        buf[512];
            char        *datetime;
            char        *zErrMsg = NULL;
            char        sql1[128];
            //描述创建数据库中表的信息
            char        *sql = "create table if not exists temperature(sn char(10), datetime char(50), temperature  char(10))";		
            sqlite3     *db = NULL;

			//调用sqlite3_open(),打开.db数据库文件。若没有,则创建
            len = sqlite3_open("temper.db",&db); 
            if (len)
            {
                fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
                sqlite3_close(db);
                exit(1);
            } 
            else
            {
               printf("You have opened a sqlite3 database named temper.db successfully!\n");
            }

			//创建temperature表,用来存放来自客户端的数据
            ret = sqlite3_exec(db, sql, 0, 0, &zErrMsg);
            if (ret != SQLITE_OK)
            {
                sqlite3_close(db);
                printf("Creat table failure \n");
                return 0;
            }
            printf("Create table successfully!\n");
            printf("Child process start to communicate with client by cli_fd[%d]...\n", cli_fd);
            printf("Now ready to connect the client and recive message from client...\n");
            printf("\n");
                     
            while (1)		//设置while循环,持续接收来自客户端的信息
            {
                memset(buf, 0, sizeof(buf));
                
                a = read(cli_fd, buf, sizeof(buf));		//从buf中读数据(客户端写入)
                if (a < 0)		//返回值小于零,则表示接收数据出错
                {
                    printf("Read information from client failure:%s\n", strerror(errno));
                    close(cli_fd);
                    exit(0);
                }
                else if (a == 0)		//返回值等于0,则表示客户端主动断开连接
                {
                    printf("The connection with client has broken!\n");
                    close(cli_fd);
                    exit(0);
                }
                else		//返回值大于零,则表示接收数据成功
                {
                    printf("The message recived from client[%s,%d] is \"%s\"\n",
                           inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), buf);
                    //对接收到的数据进行分割操作,便于存储至数据库
                    cut = strtok(buf, "/");
                    if (cut != NULL)
                    {
                        sn = cut;
                        //printf("%s\n", sn);
                        if ((cut = strtok(NULL, "/")) != NULL)
                        {
                            datetime = cut;
                            //printf("%s\n", datetime);
                            if ((cut = strtok(NULL, "/")) != NULL)
                            {
                                temp = cut;
                                //printf("%s\n", temp);
                            }
                        }
                    }
                                 
                    snprintf(sql1, 128, "insert into temperature values('%s', '%s', '%s');", 
                             sn, datetime, temp);
                    sql1[127] = '\0';
                    printf("%s\n", sql1);
                    //将数据存储至temperature表中
                    ret = sqlite3_exec(db, sql1, 0 , 0, &zErrMsg);
                    if (ret != SQLITE_OK)
                    {
                        sqlite3_close(db);
                        printf("insert data failure ; %s!\n", zErrMsg);
                        return 0;
                    }
                    printf("insert data successfully!\n");
                    printf("\n");
                }
            }
        }
    }
    close(ser_fd);

    return 0;
}

//打印帮助信息函数
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 ;
}

//回调函数sig_stop()
void sig_stop(int signum)
{
    if (SIGUSR1 == signum)		/判断捕捉到信号是否为SIGUSR1 
    {
        g_stop = 1;		//g_stop为1,while(!g_stop)循环结束,程序关闭
    }

    return ;
}

select实现

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <time.h>
#include "sqlite3.h"

#define BACKLOG 13
#define ARRAY_SIZE(x)          (sizeof(x)/sizeof(s[0]))

//函数声明,打印帮助信息;捕捉信号并结束程序
void print_usage(char* progname);
void sig_stop(int signum);

//定义一个全局变量g_stop ,与sig_stop()函数配合,达到结束程序的目的
int g_stop = 0;

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;
    pid_t                   pid = -1;
    struct sockaddr_in      ser_addr;
    struct sockaddr_in      cli_addr;
    socklen_t               cliaddr_len = 20;
    int                     maxfd = 0;
    int                     fds_array[1024];
    fd_set                  rdset;
    int                     i;
    int                     a;
    int                     len;
    char*                   sn;
    char*                   cut;
    char*                   temp;
    char                    buf[512];
    char*                   datetime;
    char*                   zErrMsg = NULL;
    char                    sql1[128];
    //描述创建数据库中表的信息
    char* sql = "create table if not exists temperature(sn char(10), datetime char(50), temperature  char(10))";
    sqlite3* db = NULL;
    /*命令行参数解析
        deamon:程序后台运行
        port:指定服务器开设端口
        help:打印帮助信息
    */
    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("receive_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;
        }
    }

    //安装SIGUSR1信号
    signal(SIGUSR1, sig_stop);

    //创建socket_fd,以供后续使用
    //第一个参数为协议域,这里使用AF_INET(32位ipv4地址、16位端口)
    //第二个参数为type,指定socket类型,这里使用SOCK_STREAM
    //第三个参数为指定协议,当其为0时,自动选择与type类型相对应的默认协议
    ser_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (ser_fd < 0)
    {
        printf("Creat socket failure:%s\n", strerror(errno));
        return 0;
    }
    printf("Creat the ser_fd[%d]!\n", ser_fd);

    //设置服务器地址信息
    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_port = htons(port);		//调用htons(),将端口号由主机字节序转变成网络字节序
     //设置服务器IP地址(INADDR_ANY,代表监听所有IP),并调用htonl(0,将其由主机字节序转变成网络字节序
    ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    //解决服务器程序停止后立刻运行,出现(端口)被占用的问题
    setsockopt(ser_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&ch, sizeof(ch));

    //绑定服务器地址(IP+端口),用于提供服务
    rv = bind(ser_fd, (struct sockaddr*) & ser_addr, sizeof(ser_addr));
    if (rv < 0)
    {
        printf("Bind server's port failure:%s\n", strerror(errno));
        return 0;
    }
    printf("The port[%d] has been bind by this server!\n", port);

    //调用listen(),将主动类型的socket套接字变为被动类型(等待客户端连接)
    //第一个参数为sockfd,指定所要监听的socket套接字,用于接收外部请求
    //第二个参数为backlog, TCP连接是一个过程,内核会在进程空间中维护一个连接队列以跟踪与服务器建立连接但还未着手处理的连接
    listen(ser_fd, BACKLOG);


    for (i = 0;i < ARRAY_SIZE(fds_array);i++)//将数组都置为-1
    {
        fds_array[i] = -1;
    }
    fds_array[0] = ser_fd;


    //调用sqlite3_open(),打开.db数据库文件。若没有,则创建
    len = sqlite3_open("temper.db", &db);
    if (len)
    {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        exit(1);
    }
    else
    {
        printf("You have opened a sqlite3 database named temper.db successfully!\n");
    }

    //创建temperature表,用来存放来自客户端的数据
    ret = sqlite3_exec(db, sql, 0, 0, &zErrMsg);
    if (ret != SQLITE_OK)
    {
        sqlite3_close(db);
        printf("Creat table failure \n");
        return 0;
    }
    printf("Create table successfully!\n");
    printf("Child process start to communicate with client by cli_fd[%d]...\n", cli_fd);
    printf("Now ready to connect the client and recive message from client...\n");
    printf("\n");
    sqlite3_close(db);

    while (!g_stop)//通过信号中断程序
    {
        FD_ZERO(&rdset);//清空集合
        for (i = 0;i < ARRAY_SIZE(fds_array);i++)
        {
            if (fds_array[i] < 0)
                continue;
            maxfd = fds_array[i] > maxfd ? fds_array[i] : maxfd;
            FD_SET(fds_array[i], &rdset);//将给定的描述符加入集合
        }

        rv = select(maxfd + 1, &rdset, NULL, NULL, NULL);//监视文件描述符
        if (rv < 0)
        {
            printf("select failure :%s\n", strerror(errno));
            break;
        }
        else
        {
            if (rv == 0)
            {
                printf("select gettime out\n");
                continue;
            }
        }
        if (FD_ISSET(ser_fd, &rdset))//判断是否有新的客户端来连接
        {
            if ((cli_fd = accept(ser_fd, (struct sockaddr*) & cli_addr, &cliaddr_len)) < 0)
            {
                printf("accept new client failure:%s\n", strerror(errno));
                continue;
            }
            found = 0;
            for (i = 0;i < ARRAY_SIZE(fds_array);i++)
            {
                if (fds_array[i] < 0)
                {
                    printf("accrpt new client[%d] and add it into array\n", cli_fd);
                    fds_array[i] = cli_fd;
                    found = 1;
                    break;
                }
            }
            if (!found)
            {
                printf("accept new client[%d] but full, so refuse it\n", cli_fd);
                close(cli_fd);
            }
        }
        else
        {
            for (i = 0;i < ARRAY_SIZE(fds_array);i++)
            {
                if (fds_array[i] < 0 || !FD_ISSET(fds_array[i], &rdset))
                    continue;
                else
                {
                    
                    //调用sqlite3_open(),打开.db数据库文件。若没有,则创建
                    len = sqlite3_open("temper.db", &db);
                    if (len)
                    {
                        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
                        sqlite3_close(db);
                        exit(1);
                    }
                    else
                    {
                        printf("You have opened a sqlite3 database named temper.db successfully!\n");
                    }

                    memset(buf, 0, sizeof(buf));

                    a = read(cli_fd, buf, sizeof(buf));		//从buf中读数据(客户端写入)
                    if (a < 0)		//返回值小于零,则表示接收数据出错
                    {
                        printf("Read information from client failure:%s\n", strerror(errno));
                        close(cli_fd);
                        exit(0);
                    }
                    else if (a == 0)		//返回值等于0,则表示客户端主动断开连接
                    {
                        printf("The connection with client has broken!\n");
                        close(cli_fd);
                        exit(0);
                    }
                    else		//返回值大于零,则表示接收数据成功
                    {
                        printf("The message recived from client[%s,%d] is \"%s\"\n",
                            inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), buf);
                        //对接收到的数据进行分割操作,便于存储至数据库
                        cut = strtok(buf, "/");
                        if (cut != NULL)
                        {
                            sn = cut;
                            //printf("%s\n", sn);
                            if ((cut = strtok(NULL, "/")) != NULL)
                            {
                                datetime = cut;
                                //printf("%s\n", datetime);
                                if ((cut = strtok(NULL, "/")) != NULL)
                                {
                                    temp = cut;
                                    //printf("%s\n", temp);
                                }
                            }
                        }

                        snprintf(sql1, 128, "insert into temperature values('%s', '%s', '%s');",
                            sn, datetime, temp);
                        sql1[127] = '\0';
                        printf("%s\n", sql1);
                        //将数据存储至temperature表中
                        ret = sqlite3_exec(db, sql1, 0, 0, &zErrMsg);
                        if (ret != SQLITE_OK)
                        {
                            sqlite3_close(db);
                            printf("insert data failure ; %s!\n", zErrMsg);
                            return 0;
                        }
                        printf("insert data successfully!\n");
                        printf("\n");

                    }
                    sqlite3_close(db);
                }
            }
        }
    }
    close(ser_fd);

    return 0;
}

//打印帮助信息函数
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;
}

//回调函数sig_stop()
void sig_stop(int signum)
{
    if (SIGUSR1 == signum) / 判断捕捉到信号是否为SIGUSR1
    {
        g_stop = 1;		//g_stop为1,while(!g_stop)循环结束,程序关闭
    }

    return;
}

epoll实现

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include "sqlite3.h"

#define BACKLOG 13
#define MAX_EVENTS  512

//函数声明,打印帮助信息;捕捉信号并结束程序
void print_usage(char* progname);
void sig_stop(int signum);

//定义一个全局变量g_stop ,与sig_stop()函数配合,达到结束程序的目的
int g_stop = 0;

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;
    pid_t                   pid = -1;
    struct sockaddr_in      ser_addr;
    struct sockaddr_in      cli_addr;
    socklen_t               cliaddr_len = 20;
    int                     epollfd;
    struct epoll_event      event;
    struct epoll_event      event_array[MAX_EVENTS];
    int                     events;
    int                     found;
    int                     len;
    char*                   zErrMsg = NULL;
    char                    sql1[128];
    int                     a;
    char*                   sn;
    char*                   cut;
    char*                   temp;
    char                    buf[512];
    char*                   datetime;
    //描述创建数据库中表的信息
    char* sql = "create table if not exists temperature(sn char(10), datetime char(50), temperature  char(10))";
    sqlite3* db = NULL;
    /*命令行参数解析
        deamon:程序后台运行
        port:指定服务器开设端口
        help:打印帮助信息
    */
    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("receive_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;
        }
    }

    //安装SIGUSR1信号
    signal(SIGUSR1, sig_stop);

    //创建socket_fd,以供后续使用
    //第一个参数为协议域,这里使用AF_INET(32位ipv4地址、16位端口)
    //第二个参数为type,指定socket类型,这里使用SOCK_STREAM
    //第三个参数为指定协议,当其为0时,自动选择与type类型相对应的默认协议
    ser_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (ser_fd < 0)
    {
        printf("Creat socket failure:%s\n", strerror(errno));
        return 0;
    }
    printf("Creat the ser_fd[%d]!\n", ser_fd);

    //设置服务器地址信息
    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_port = htons(port);		//调用htons(),将端口号由主机字节序转变成网络字节序
     //设置服务器IP地址(INADDR_ANY,代表监听所有IP),并调用htonl(0,将其由主机字节序转变成网络字节序
    ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    //解决服务器程序停止后立刻运行,出现(端口)被占用的问题
    setsockopt(ser_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&ch, sizeof(ch));

    //绑定服务器地址(IP+端口),用于提供服务
    rv = bind(ser_fd, (struct sockaddr*) & ser_addr, sizeof(ser_addr));
    if (rv < 0)
    {
        printf("Bind server's port failure:%s\n", strerror(errno));
        return 0;
    }
    printf("The port[%d] has been bind by this server!\n", port);

    //调用listen(),将主动类型的socket套接字变为被动类型(等待客户端连接)
    //第一个参数为sockfd,指定所要监听的socket套接字,用于接收外部请求
    //第二个参数为backlog, TCP连接是一个过程,内核会在进程空间中维护一个连接队列以跟踪与服务器建立连接但还未着手处理的连接
    listen(ser_fd, BACKLOG);

    if ((epollfd = epoll_create(MAX_EVENTS)) < 0)
    {
        printf("epoll_create failure:%s\n", strerror(errno));
        return 0;
    }

    event.events = EPOLLIN;
    event.data.fd = ser_fd;

    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ser_fd, &event) < 0)
    {
        printf("epoll add ser_fd failure:%s\n", strerror(errno));
        return 0;
    }

    //调用sqlite3_open(),打开.db数据库文件。若没有,则创建
    len = sqlite3_open("temper.db", &db);
    if (len)
    {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        exit(1);
    }
    else
    {
        printf("You have opened a sqlite3 database named temper.db successfully!\n");
    }

    //创建temperature表,用来存放来自客户端的数据
    ret = sqlite3_exec(db, sql, 0, 0, &zErrMsg);
    if (ret != SQLITE_OK)
    {
        sqlite3_close(db);
        printf("Creat table failure \n");
        return 0;
    }
    printf("Create table successfully!\n");
    printf("Child process start to communicate with client by cli_fd[%d]...\n", cli_fd);
    printf("Now ready to connect the client and recive message from client...\n");
    printf("\n");
    sqlite3_close(db);
    while (!g_stop)
    {
        events = epoll_wait(epollfd, event_array, MAX_EVENTS, -1);
        if (events < 0)
        {
            printf("epoll failure:%s\n", strerror(errno));
            break;
        }
        else if (events == 0)
        {
            printf("epoll get timeout\n");
            continue;
        }

        for (i = 0;i < events;i++)
        {
            if ((event_array[i].events & EPOLLERR) || (event_array[i].events & EPOLLHUP))
            {
                printf("epoll_wait get error on fd[%d]:%s\n", event_array[i].data.fd, strerror(errno));
                epoll_ctl(epollfd, EPOLL_CTL_DEL, event_array[i].data.fd, NULL);
                close(event_array[i].data.fd);
            }

            if (event_array[i].data.fd == ser_fd)
            {
                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;
                }
                event.data.fd = cli_fd;
                event.events = EPOLLIN;
                if (epoll_ctl(epollfd, EPOLL_ATL_ADD, cli_fd, &event) < 0)
                {
                    printf("epoll add client socket failure:%s\n", strerror(errno));
                    close(cli_fd);
                    continue;
                }
            }
            else
            {

                //调用sqlite3_open(),打开.db数据库文件。若没有,则创建
                len = sqlite3_open("temper.db", &db);
                if (len)
                {
                    fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
                    sqlite3_close(db);
                    exit(1);
                }
                else
                {
                    printf("You have opened a sqlite3 database named temper.db successfully!\n");
                }

                memset(buf, 0, sizeof(buf));

                a = read(cli_fd, buf, sizeof(buf));		//从buf中读数据(客户端写入)
                if (a < 0)		//返回值小于零,则表示接收数据出错
                {
                    printf("Read information from client failure:%s\n", strerror(errno));
                    close(cli_fd);
                    exit(0);
                }
                else if (a == 0)		//返回值等于0,则表示客户端主动断开连接
                {
                    printf("The connection with client has broken!\n");
                    close(cli_fd);
                    exit(0);
                }
                else		//返回值大于零,则表示接收数据成功
                {
                    printf("The message recived from client[%s,%d] is \"%s\"\n",
                        inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), buf);
                    //对接收到的数据进行分割操作,便于存储至数据库
                    cut = strtok(buf, "/");
                    if (cut != NULL)
                    {
                        sn = cut;
                        //printf("%s\n", sn);
                        if ((cut = strtok(NULL, "/")) != NULL)
                        {
                            datetime = cut;
                            //printf("%s\n", datetime);
                            if ((cut = strtok(NULL, "/")) != NULL)
                            {
                                temp = cut;
                                //printf("%s\n", temp);
                            }
                        }
                    }

                    snprintf(sql1, 128, "insert into temperature values('%s', '%s', '%s');",
                        sn, datetime, temp);
                    sql1[127] = '\0';
                    printf("%s\n", sql1);
                    //将数据存储至temperature表中
                    ret = sqlite3_exec(db, sql1, 0, 0, &zErrMsg);
                    if (ret != SQLITE_OK)
                    {
                        sqlite3_close(db);
                        printf("insert data failure ; %s!\n", zErrMsg);
                        return 0;
                    }
                    printf("insert data successfully!\n");
                    printf("\n");
                }
                sqlite3_close(db);
            }
        }
    }
    close(ser_fd);

    return 0;
}

//打印帮助信息函数
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;
}

//回调函数sig_stop()
void sig_stop(int signum)
{
    if (SIGUSR1 == signum) / 判断捕捉到信号是否为SIGUSR1
    {
        g_stop = 1;		//g_stop为1,while(!g_stop)循环结束,程序关闭
    }

    return;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值