zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    python导入requests库一直报错原因总结 (文件名与库名冲突)
    Windows下,python pip安装时ReadTimeoutError解决办法
    win10家庭版怎么开启Administrator超级管理员帐户
    关于Centos7 firewalld防火墙开放端口后仍不能访问ftp和nginx的问题解决
    Nginx下配置ThinkPhp多入口访问
    phpStudy配置站点 解决You don't have permission to access / on this server
    非微信内置浏览器中的网页调起微信支付的方案研究
    两种解决方法 PHP Warning: File upload error
    chrome浏览器的跨域设置——包括版本49前后两种设置
    ESA2GJK1DH1K基础篇: 阿里云物联网平台: 阿里云物联网平台加入规则引擎(云产品流转),让两个MQTT设备之间实现通信
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/6181675.html
Copyright © 2011-2022 走看看