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

多进程服务器

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

多线程服务器

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

你可能感兴趣的:(网络)