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

这篇具有很好参考价值的文章主要介绍了多进程服务器和多线程服务器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

多进程服务器

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

文章来源地址https://www.toymoban.com/news/detail-827039.html

到了这里,关于多进程服务器和多线程服务器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Linux网络编程二(TCP图解三次握手及四次挥手、TCP滑动窗口、MSS、TCP状态转换、多进程/多线程服务器实现)

    Linux网络编程二(TCP图解三次握手及四次挥手、TCP滑动窗口、MSS、TCP状态转换、多进程/多线程服务器实现)

    1、TCP三次握手 TCP 三次握手 (TCP three-way handshake)是 TCP协议建立可靠连接 的过程,确保客户端和服务器之间可以进行可靠的通信。下面是TCP三次握手的 详细过程 : 假设客户端为A,服务器为B。 (1) 第一次握手 第一次握手(SYN=1,seq=500) A向B发送一个带有 SYN 标志位的数据包,

    2024年04月22日
    浏览(13)
  • TCP服务器实现—多进程版,多线程版,线程池版

    TCP服务器实现—多进程版,多线程版,线程池版

    目录 前言 1.存在的问题 2.多进程版 3.多线程版 4.线程池版 总结         在上一篇文章中使用TCP协议实现了一个简单的服务器,可以用来服务端和客户端通信,但是之前的服务器存在一个问题,就是当有多个客户端连接服务器的时候,服务器只能和一个客户端通信,其它的客

    2024年02月12日
    浏览(20)
  • 分别通过select、多进程、多线程实现一个并发服务器

    多进程 多线程 select

    2024年02月20日
    浏览(12)
  • 计算机网络编程 | 并发服务器代码实现(多进程/多线程)

    计算机网络编程 | 并发服务器代码实现(多进程/多线程)

    欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。 专栏:《网络编程》 当涉及到构建高性能的服务

    2024年02月08日
    浏览(17)
  • 运维 | 查看 Linux 服务器 IP 地址

    大多数在操作 Linux 系统时,我们经常需要知道服务器的 IP 比便于后续的一系列操作,这时候有快速查看主机 IP 的命令行操作,能够有效的帮助我们 本章节主要记录一些常用查看服务器 IP 的命令,希望对大家有所帮助。 查看 Linux 服务器的 IP 地址的命令大体上有以下几种。

    2024年04月27日
    浏览(50)
  • C#知识点-13(进程、多线程、使用Socket实现服务器与客户端通信)

    C#知识点-13(进程、多线程、使用Socket实现服务器与客户端通信)

    进程 定义:每一个正在运行的应用程序,都是一个进程  进程不等于正在运行的应用程序。而是为应用程序的运行构建一个运行环境 多线程 这段代码在执行完成之前,程序会被卡死(不能操作程序,包括关闭窗口)。因为我们程序在做一些耗时操作的时候,如果主线程去执

    2024年02月22日
    浏览(111)
  • 【运维】Linux 跨服务器复制文件文件夹

    如果是云服务 建议用内网ip scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的。可能会稍微影响一下速度。当你服务器硬盘变为只读 read only system时,用scp可以帮你把文件移出来

    2024年02月08日
    浏览(52)
  • linux并发服务器 —— 多进程并发(四)

    linux并发服务器 —— 多进程并发(四)

    程序是包含一系列信息的文件,描述了如何在运行时创建一个进程; 进程是正在运行的程序的实例,可以用一个程序来创建多个进程; 用户内存空间包含程序代码以及代码所使用的变量,内核数据结构用于维护进程状态信息; 进程控制块(PCB):维护进程相关的信息,tas

    2024年02月11日
    浏览(12)
  • 【Linux 服务器运维】定时任务 crontab 详解 | 文末送书

    【Linux 服务器运维】定时任务 crontab 详解 | 文末送书

    本文思维导图概述的主要内容: 1.1 什么是 crontab Crontab 是一个在 Unix 和 Linux 操作系统上 用于定时执行任务 的工具。它允许用户创建和管理计划任务,以便在特定的时间间隔或时间点自动运行命令或脚本。Crontab 是 cron table 的缩写, cron 指的是 Unix 系统中的一个后台进程,它

    2024年02月08日
    浏览(68)
  • Linux服务器上查询进程 ps aux

    在Linux服务器上查询进程,有以下几种方法: 使用ps命令。这个命令用于报告当前系统的进程状态。可以用以下方式使用ps命令来查看进程信息: ps aux:显示系统中所有进程的信息。 ps -e:显示所有进程的信息。 ps -f:显示进程的所有信息。 ps -l:以长格式显示进程信息。

    2024年02月05日
    浏览(14)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包