当前位置: 首页 > article >正文

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

多进程服务器

#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;
}

多线程服务器

#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;
}


http://www.kler.cn/a/234779.html

相关文章:

  • Android修行手册 - 移动端几种常用动画方案对比
  • Redis 持久化机制详解
  • 维克日记:私密写作新选择,轻松记录生活点滴
  • 用python ollama qwen2.5 开发一个AI修仙游戏
  • 梳理你的思路(从OOP到架构设计)_简介设计模式
  • 数学竞赛网站:构建互动学习的网络平台
  • Vue - 快速入门(一)
  • 腾讯云4核8G12M轻量应用服务器性能够用吗?支持多少人?
  • sheng的学习笔记-部署-目录
  • 嵌入式电子产品开发感悟!
  • 深入学习Pandas:数据连接、合并、加入、添加、重构函数的全面指南【第72篇—python:数据连接】
  • C++局部变量与全局变量
  • ChatGPT高效提问—prompt实践
  • 修改SpringBoot中默认依赖版本
  • 快速手动完成 VS 编写脚本自动化:如何选取最高效的工作方式?
  • MySQL(基础)
  • 集群及LVS简介、LVSNAT模式原理、LVSNAT模式配置、LVSDR模式原理、LVSDR模式配置、LVS错误排查
  • HiveSQL——条件判断语句嵌套windows子句的应用
  • UR10+gazebo+moveit吸盘抓取搬运demo
  • 数据分析基础之《pandas(8)—综合案例》
  • 解决Spring Boot Configuration Annotation Processor not configured的问题
  • KY139 毕业bg
  • 协议-TCP协议-基础概念04-可能发生丢包的位置-linux配置项梳理(TCP连接的建立和断开、收发包过程)
  • 更换商品图片日期JSON格式报错 - 序列化与反序列化日期格式设置
  • springcloud分布式架构网上商城源码和论文
  • Linux笔记之Docker进行镜像备份与迁移