多进程服务器和多线程服务器

多进程服务器

cs 复制代码
#include<myhead.h>
#define PORT 9999                  //端口号
#define IP "192.168.10.116"        //IP地址

//定义信号处理函数,用于回收僵尸进程
void handler(int signo)
{
    if(signo == SIGCHLD)
    {
        while(waitpid(-1, NULL, WNOHANG) > 0 );
    }
}

//定义处理客户端操作的函数
int deal_cli_msg(int newfd, struct sockaddr_in cin)
{
    //5、收发数据
    char rbuf[128] = "";    //读取消息的容器
    while(1)
    {
        //清空内容
        bzero(rbuf, sizeof(rbuf));


        int res = recv(newfd, rbuf, sizeof(rbuf), 0);
        if(res == 0)
        {
            printf("客户端下线\n");
            break;
        }
        printf("[%s:%d] : %s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), rbuf);

        //链接一个字符串后发回去
        strcat(rbuf, "*_*");
        send(newfd, rbuf, sizeof(rbuf), 0);
        //功能:向newfd文件描述符中以阻塞形式写入数据
    }
    close(newfd);

    return 0;
}



/**********************************主程序***************************************/
int main(int argc, const char *argv[])
{

    //将SIGCHLD信号与信号处理函数进行绑定
    if(signal(SIGCHLD, handler) == SIG_ERR)
    {
        perror("signal error");
        return -1;
    }



    //1、创建套接字
    int sfd = -1;
    //功能创建一个支持TCP通信的套接字
    //AF_INET:表示跨主机的IPv4的通信
    //SOCK_STREAM:表示支持TCP通信
    if((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket error");
        return -1;
    }

    printf("sfd = %d\n", sfd);           //?

    //设置端口号快速重用
    int reuse = 1;
    if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))==-1)
    {
        perror("setsockopt error");
        return -1;
    }

    //2、绑定地址信息结构体(必须)
    //2.1 填充地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family =     AF_INET;   //地址族为IPv4
    sin.sin_port =         htons(PORT);    //端口号,需要转换网络字节序
    sin.sin_addr.s_addr = inet_addr(IP);  //IP地址

    //2.2绑定工作
    if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
    {
        perror("bind error");
        return -1;
    }

    printf("bind success _%d_%s_%s\n", __LINE__, __FILE__, __func__);

    //3、将套接字设置成被动监听状态
    if(listen(sfd, 128) == -1)
    {
        perror("listen error");
        return -1;
    }
    printf("listen success _%d_%s_%s\n", __LINE__, __FILE__, __func__);

    //4、接收链接请求

    //4.1 定义用于接收客户端地址信息的结构体变量
    struct sockaddr_in cin;
    socklen_t socklen = sizeof(cin);                //接收长度
    //4.2 接收客户端链接请求
    int newfd = -1;         //用于跟客户端通信的套接字文件描述符
    pid_t pid = -1;          //接收子进程pid号



    while(1)
    {
        //fork()
        接收客户端链接请求
        //当执行到accept时,系统会给该函数预分配一个文件描述符(按最小未使用原则)
        //所以,在该函数阻塞时,即使有旧的客户端退,释放了文件描述符,也不会再使用新释放的文件描述符
        //下一次阻塞时,会预选上一次释放的文件描述符
        if( (newfd=accept(sfd, (struct sockaddr*)&cin, &socklen)) == -1)
        {
            perror("accept error");
            return -1;
        }
        printf("[%s:%d] 连接成功, newfd = %d\n", inet_ntoa(cin.sin_addr),\
                ntohs(cin.sin_port), newfd);             //?

        //创建子进程用于跟新的客户端进行通信工作
        pid = fork();
        if(pid > 0)
        {
            //父进程用于接收客户端连接请求
            //父进程中关闭newfd
            close(newfd);

        }else if(pid == 0)
        {
            //关闭sfd
            close(sfd);

            //调用处理客户端信息的函数
            deal_cli_msg(newfd, cin);

            //退出子进程
            exit(EXIT_SUCCESS);

        }else 
        {
            perror("fork error");
            return -1;
        }

        //wait(NULL);           //不能使用阻塞方式回收

    }

    //关闭套接字
    close(sfd);



    return 0;
}

多线程服务器

cs 复制代码
#include<myhead.h>
#define PORT 9999                  //端口号
#define IP "192.168.10.116"        //IP地址

//定义向线程体中传递参数的结构体类型
struct pthread_ds
{
    int newfd;          //处理客户端的套接字文件描述符
    struct sockaddr_in cin;       //客户端套接字地址信息结构体变量
};

//定义线程处理函数
void *deal_cli_msg(void *arg)
{
    //分解传过来的参数
    int newfd = ((struct pthread_ds*)arg)->newfd;     
    struct sockaddr_in cin = ((struct pthread_ds*)arg)->cin;

    //5、收发数据
    char rbuf[128] = "";    //读取消息的容器
    while(1)
    {
        //清空内容
        bzero(rbuf, sizeof(rbuf));


        int res = recv(newfd, rbuf, sizeof(rbuf), 0);
        if(res == 0)
        {
            printf("客户端下线\n");
            break;
        }
        printf("[%s:%d] : %s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), rbuf);

        //链接一个字符串后发回去
        strcat(rbuf, "*_*");
        send(newfd, rbuf, sizeof(rbuf), 0);
        //功能:向newfd文件描述符中以阻塞形式写入数据
    }
    close(newfd);

    //退出线程
    pthread_exit(NULL);


}



/****************************主程序***********************/
int main(int argc, const char *argv[])
{
    //1、创建套接字
    int sfd = -1;
    //功能创建一个支持TCP通信的套接字
    //AF_INET:表示跨主机的IPv4的通信
    //SOCK_STREAM:表示支持TCP通信
    if((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket error");
        return -1;
    }

    printf("sfd = %d\n", sfd);           //?

    //设置端口号快速重用
    int reuse = 1;
    if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))==-1)
    {
        perror("setsockopt error");
        return -1;
    }

    //2、绑定地址信息结构体(必须)
    //2.1 填充地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family =     AF_INET;   //地址族为IPv4
    sin.sin_port =         htons(PORT);    //端口号,需要转换网络字节序
    sin.sin_addr.s_addr = inet_addr(IP);  //IP地址

    //2.2绑定工作
    if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
    {
        perror("bind error");
        return -1;
    }

    printf("bind success _%d_%s_%s\n", __LINE__, __FILE__, __func__);

    //3、将套接字设置成被动监听状态
    if(listen(sfd, 128) == -1)
    {
        perror("listen error");
        return -1;
    }
    printf("listen success _%d_%s_%s\n", __LINE__, __FILE__, __func__);

    //4、接收链接请求

    //4.1 定义用于接收客户端地址信息的结构体变量
    struct sockaddr_in cin;
    socklen_t socklen = sizeof(cin);                //接收长度
    //4.2 接收客户端链接请求
    int newfd = -1;         //用于跟客户端通信的套接字文件描述符
    pthread_t tid = -1;       //接收线程号


    while(1)
    {
        //接收客户端链接请求
        if( (newfd=accept(sfd, (struct sockaddr*)&cin, &socklen)) == -1)
        {
            perror("accept error");
            return -1;
        }
        printf("[%s:%d] 连接成功, newfd = %d\n", inet_ntoa(cin.sin_addr),\
                ntohs(cin.sin_port), newfd);             //?

        //定义一个向线程体传递的结构体变量
        struct pthread_ds info = {newfd, cin};

        //创建一个分支线程,用于跟客户端进行通信
        if(pthread_create(&tid, NULL, deal_cli_msg, &info) != 0)
        {
            printf("tid create error\n");
            return -1;
        }

        //回收线程资源
        //pthread_join(tid);    //不能使用阻塞形式回收线程资源
        pthread_detach(tid);        //将线程设置成分离态

    }

    //关闭套接字
    close(sfd);


    return 0;
}
相关推荐
大树883 小时前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 小时前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质4 小时前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush44 小时前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5204 小时前
Linux 11 动态监控指令top
linux
小宇宙Zz4 小时前
Maven依赖冲突
java·服务器·maven
Inhand陈工5 小时前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智5 小时前
ARP代理--工作原理
运维·网络·arp·arp代理
不会C语言的男孩5 小时前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
shushangyun_5 小时前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化