创建一个多进程服务器和多线程服务器

多进程服务器

cpp 复制代码
#include<myhead.h>
#define PORT 8888                  //端口号
#define IP "192.168.10.10"        //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);
    }
    close(newfd);

    return 0;
}



int main(int argc, const char *argv[])
{

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

    int sfd = -1;
    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;
    }

    struct sockaddr_in sin;
    sin.sin_family =     AF_INET;   //地址族为IPv4
    sin.sin_port =         htons(PORT);    //端口号,需要转换网络字节序
    sin.sin_addr.s_addr = inet_addr(IP);  //IP地址

    if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
    {
        perror("bind error");
        return -1;
    }


    if(listen(sfd, 128) == -1)
    {
        perror("listen error");
        return -1;
    }

    struct sockaddr_in cin;
    socklen_t socklen = sizeof(cin);                //接收长度

    int newfd = -1;         //用于跟客户端通信的套接字文件描述符
    pid_t pid = -1;          //接收子进程pid号



    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);            

        //创建子进程用于跟新的客户端进行通信工作
        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;
        }

    }

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


    return 0;
}

多线程服务器

cpp 复制代码
#include<myhead.h>
#define PORT 8888                  //端口号
#define IP "192.168.10.10"        //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;
        }
    }
    close(newfd);
    //退出线程
    pthread_exit(NULL);

}


int main(int argc, const char *argv[])
{
    //1、创建套接字
    int sfd = -1;
    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;
    }


    //3、将套接字设置成被动监听状态
    if(listen(sfd, 128) == -1)
    {
        perror("listen error");
        return -1;
    }

    //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;
}
相关推荐
ENZTNO11 小时前
迈向安全未来:零信任模型落地中的三大技术挑战与应对
网络·安全·web安全
heartbeat..1 小时前
JavaWeb 入门 - HttpServletResponse 响应对象 详解
java·网络·http·web·response
阿巴~阿巴~1 小时前
TCP可靠传输的底层密码:序号、窗口与六大标志位全解析
运维·服务器·网络·tcp·序列号·六大标志位·确认序号
航Hang*2 小时前
第五章:综合布线技术 —— 管理间(电信间)设计与施工
网络·笔记·学习·设计·光纤
梁辰兴3 小时前
计算机网络基础:地址解析协议 ARP
网络·计算机网络·计算机·arp·计算机网络基础·地址解析协议·梁辰兴
会员源码网3 小时前
手工代付系统开发 | 专业代付支付系统定制 | 源码交付支持二次开发
网络·源代码管理
JosieBook4 小时前
【心理】心理咨询实战技术框架(zengfuyun)
网络·数据库·人工智能
勇气要爆发4 小时前
单播、广播、组播:网络里的“私聊”、“大喇叭”和“群聊”
网络
檀越剑指大厂4 小时前
【网络系列】防盗链(Referer Check)
网络
乾元4 小时前
网络切片的自动化配置与 SLA 保证——5G / 专网场景中,从“逻辑隔离”到“可验证承诺”的工程实现
运维·开发语言·网络·人工智能·网络协议·重构