• Linux socket多进程服务器框架二


    客户端未解决Bug:子进程或者父进程退出的时候,我无法做到两个进程都调用clt_socket_Destory()方式释放socket句柄,
    但是进程退出后,相应的资源也会释放,有一定影响,但是不大,以后我想到办法再优化。
    重点:客户端connect服务器方法需要单独分离出来,方便用户自己断线重连。
    客户端
    //clthelp.h
    #include <stdio.h>
    #include "commsocket.h"
    
    #ifndef _vxclt
    #define _vxclt
    
    #ifdef __cplusplus
    extern "C"
    {
    #endif
    
    /**
     * clientsock_init - 初始化socket
     * @handle:socket句柄
     * 成功返回0,失败返回错误码
     * */
    int clientsock_init(void **handle);
    
    /**
     * connect_server - 客户端创建连接
     * @handle:socket句柄
     * @port:端口号
     * @ipaddr:请求服务器的IP地址
     * 成功返回0,失败返回错误码
     * */
    int connect_server(void *handle, int port, char *ipaddr,
            unsigned int wait_seconds);
    
    /**
     * clt_Process_business - 客户端业务处理
     * @handle:socket句柄
     * */
    void clt_Process_business(void *handle);
    
    /**
     * clt_socket_Destory - 释放socket句柄
     * @handle:socket句柄
     * */
    void clt_socket_Destory(void **handle);
    
    #ifdef __cplusplus
    extern "C"
    }
    #endif
    #endif
    //clthelp.c    --客户端代码实现
    #include "clthelp.h"
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <sys/wait.h>
    #include <signal.h>
    
    /**
     * clientsock_init - 初始化socket
     * @handle:socket句柄
     * 成功返回0,失败返回错误码
     * */
    int clientsock_init(void **handle)
    {
        int ret = 0;
        //初始化socket环境
        //创建socket套接字
        if (handle == NULL)
        {
            ret = Sck_ParamErr;
            printf("clientsock_init() params not correct !
    ");
            return ret;
        }
        Mysock *mysock = (Mysock *) malloc(sizeof(Mysock));
        if (mysock == NULL)
        {
            ret = Sck_MacErr;
            printf("malloc() failed !");
            return ret;
        }
        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd == -1)
        {
            ret = Sck_BaseErr;
            perror("socket() err");
            return ret;
        }
        mysock->fd = sockfd;
        *handle=mysock;
        return 0;
    }
    
    /**
     * connect_server - 客户端创建连接
     * @handle:socket句柄
     * @port:端口号
     * @ipaddr:请求服务器的IP地址
     * 成功返回0,失败返回错误码
     * */
    int connect_server(void *handle, int port, char *ipaddr,
            unsigned int wait_seconds)
    {
        int ret = 0;
        if (handle == NULL || ipaddr == NULL || port < 0 || port > 65535)
        {
            ret = Sck_ParamErr;
            printf("getconnection() params not correct !
    ");
            return ret;
        }
        Mysock *mysock = (Mysock *) handle;
        //connect
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = inet_addr(ipaddr);
        ret = connect_timeout(mysock->fd, &addr, wait_seconds);
        if (ret == -1)
        {
            if (errno == ETIMEDOUT)
            {
                //超时处理
                ret = Sck_TimeoutErr;
                printf("connect_timeout() time out !
    ");
                return ret;
            }
            ret = Sck_BaseErr;
            perror("connect_timeout() err");
            return ret;
        }
        return ret;
    }
    
    /**
     * clt_send - 客户端发送数据
     * @handle:socket句柄
     * @wait_seconds:等待超时秒数,如果为0表示不检测超时
     * 失败返回错误码
     * */
    void clt_send(void *handle, unsigned int wait_seconds)
    {
        int ret = 0;
        char buf[MAXBUFSIZE] = { 0 };
        Mysock *mysock = (Mysock *) handle;
        //从终端读取数据
        while (fgets(buf, MAXBUFSIZE, stdin) != NULL)
        {
            if (strlen(buf) > MAXBUFSIZE)
            {
                printf("输入字节数过长!
    ");
                break;
            }
            //超时检测
            ret = write_timeout(mysock->fd, wait_seconds);
            if (ret == -1)
            {
                if (errno == ETIMEDOUT)
                {
                    printf("write_timeout() time out !
    ");
                    break;
                }
                perror("write_timeout() err");
                break;
            } else
            {
                ret = socket_send(mysock->fd, buf, strlen(buf));
                if (ret == -1)
                {
                    printf("socket_send() failed !
    ");
                    break;
                }
                memset(buf, 0, MAXBUFSIZE);
            }
        }
    }
    
    /**
     * clt_recv - 客户端接收数据
     * @handle:socket句柄
     * @wait_seconds:等待超时秒数,如果为0表示不检测超时
     * */
    void clt_recv(void *handle, unsigned int wait_seconds)
    {
        int ret = 0;
        char buf[MAXBUFSIZE] = { 0 };
        int len = MAXBUFSIZE;
        Mysock *mysock = (Mysock *) handle;
        while (1)
        {
            //超时检测
            ret = read_timeout(mysock->fd, wait_seconds);
            if (ret == -1)
            {
                if (errno == ETIMEDOUT)
                {
                    printf("read_timeout() time out !
    ");
                    break;
                }
                perror("read_timeout() err");
                break;
            } else
            {
                len = MAXBUFSIZE;
                ret = socket_recv(mysock->fd, buf, &len);
                if (ret == -1)
                {
                    break;
                }
                fputs(buf, stdout);
                memset(buf, 0, sizeof(buf));
            }
        }
    }
    
    /**
     * handler - 信号捕捉函数
     * @sign:信号码
     * */
    void handler(int sign)
    {
        if (sign == SIGCHLD)
        {
            int mypid = 0;
            while ((mypid = waitpid(-1, NULL, WNOHANG)) > 0)
            {
                printf("子进程的pid=%d
    ", mypid);
            }
            //退出父进程
            exit(0);
        } else if (sign == SIGPIPE)
        {
            printf("accept SIGPIPE !
    ");
        } else if (sign == SIGUSR1)
        {
            //父进程退出,子进程也需要退出
            exit(0);
        }
    }
    
    /**
     * clt_Process_business - 客户端业务处理
     * @handle:socket句柄
     * */
    void clt_Process_business(void *handle)
    {
        int ret = 0;
        if (handle == NULL)
        {
            ret = Sck_ParamErr;
            printf("Process_business() params not correct !
    ");
            return;
        }
        //信号安装
        int signoarr[3] = { SIGCHLD, SIGPIPE, SIGUSR1 };
        ret = Install_Signal(signoarr, 3, handler);
        if (ret != 0)
        {
            return;
        }
        pid_t pid = fork();
        if (pid == -1)
        {
            ret = Sck_BaseErr;
            perror("fork() err");
            return;
        }
        if (pid == 0)
        {
            //子进程接收数据
            clt_recv(handle, 100);
            exit(0);
        } else if (pid > 0)
        {
            //父进程写数据
            clt_send(handle, 100);
            //向子进程发信号--就算发送出错,我也毫无办法去关闭子进程了
            kill(pid, SIGUSR1);
            exit(0);
        }
        return;
    }
    
    /**
     * clt_socket_Destory - 释放socket句柄
     * @handle:socket句柄
     * */
    void clt_socket_Destory(void **handle)
    {
        if (handle == NULL)
        {
            printf("clt_socket_Destory() param not correct !
    ");
            return;
        }
        Mysock *mysock = (Mysock *) *handle;
        if (mysock != NULL)
        {
            printf("客户端执行释放函数!
    ");
            free(mysock);
            *handle = NULL;
        }
        mysock = NULL;
    }
    //客户端
    #include "clthelp.h"
    
    int main()
    {
        void *handle = NULL;
        int ret = 0;
        //初始化socket
        ret = clientsock_init(&handle);
        if (ret != 0)
        {
            printf("error message:%s
    ", strsockerr(ret));
            return -1;
        }
        //连接服务器
        ret = connect_server(handle, 8080, "127.0.0.1", 70);
        if (ret != 0)
        {
            printf("error message:%s
    ", strsockerr(ret));
            return -1;
        }
        //多进程发送接收信息
        clt_Process_business(handle);
        //释放内存
        clt_socket_Destory(&handle);
        return 0;
    }
  • 相关阅读:
    HDU 4757 Tree 可持久化字典树 trie
    BZOJ 4198: [Noi2015]荷马史诗 哈夫曼树 k叉哈夫曼树
    BZOJ 3253 Fence Repair 哈夫曼树 水题
    BZOJ 3572: [Hnoi2014]世界树 虚树 树形dp
    2-SAT的一些题目
    二分图相关定理 最小点覆盖 最小路径覆盖 最大独立集 最小覆盖集
    POJ 1469 COURSES 二分图最大匹配 二分图
    快速排序
    排序算法:希尔排序
    霍夫曼编码实现
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/6181675.html
Copyright © 2020-2023  润新知