暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

进程通信c++

智慧大数据 2020-03-06
491

进程通信

一、使用fork方法系统调用创建进程

  • fork说明

    • fork系统调用是用于创建进程的;

    • fork创建的进程初始化状态和父进程一样;

    • 系统会为fork的进程分配新的资源;

  • fork调用和返回

    • fork系统调用无参数;

    • 会返回两次,分别返回子进程ID和零;

    • 返回子进程ID的是父进程,返回0的是子进程;

  • 进程使用example:

    #include <iostream>
    #include <cstring>
    #include <stdio.h>
    #include <unistd.h>


    using namespace std;


    int main(){
    int num = 888;
    pid_t pid;
    pid = fork();
    //一次执行,fork会返回两次
    if(pid == 0){
    //表示输出一个回车,并刷新输出流,和printf("\n")显示一样
    cout << "这是一个子进程." << endl;
    cout << "num is son process:" << num << endl;
    while(true){
    num += 1;
    cout << "num is son process:" << num << endl;
    sleep(1);
    }
    }else if(pid > 0){
    cout << "这是一个父进程." << endl;
    cout << "子进程id:" << pid << endl;
    cout << "num is father process:" << num << endl;
    while(true){
    num -= 1;
    cout << "num is father process:" << num << endl;
    sleep(1);
    }
    }else if(pid < 0){
    //进程没有创建成功
    cout << "创建进程失败." << endl;
    }
    return 0;
    }
    // g++ fork_demo.cpp -o fork_demo -g

    二、进程同步之共享内存

    • (1)、进程和线程

      • 进程的线程共享进程资源

      • 进程之间共享计算机资源

    • 在某种程度上,多进程是共同使用物理内存的;

    • 由于操作系统的进程管理,进程间的内存空间是独立的,是段页式存储管理;
      进程默认是不能访问进程空间之外的内存空间的;
      -(2)、共享内存

      • 共享内存允许不相关的进程访问同一片物理内存;

      • 共享内存是两个进程之间共享和传递数据最快的方式;

      • 共享内存未提供同步机制,需要借助其他机制管理访问;

    • (3)原理:

      申请共享内存
      —>连接到进程空间
      —>使用共享内存
      —>脱离进程空间 &删除

    • example:使用一个带有客户端和服务端的例子通过共享内存来实现通信

      • server :

        #include "common.h"


        #include <sys/shm.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <stdio.h>
        #include <string.h>


        #include <iostream>


        int main(){

        //定义共享内存结构体
        struct ShmEntry *entry;


        //1、申请共享内容,参数为key,size和shmfig[IPC_CREAT|(IPC_CREAT|IPC_EXCL)],返回一个共享内存的id
        int shmid = shmget((key_t)1111,sizeof(struct ShmEntry),0666|IPC_CREAT);
        if(shmid == -1){
        std::cout << "创建共享内存失败" << std::endl;
        return -1;
        }


        //2、连接到当前进程空间,使用共享内存
        //参数共享内存标识符、shmid指定共享内存出现在进程内存地址的什么位置,shmaddr直接指定为NULL让内核自己决定一个合适的地址位置,shmflg读写模式
        entry = (ShmEntry*)shmat(shmid,0,0);
        entry->can_read = 0;
        while(true){
        if(entry->can_read == 1){
        std::cout << "收到信息:" << entry->msg << std::endl;
        entry->can_read = 0;
        }else{
        std::cout << "内存块不可读,休息中1s.." << std::endl;
        sleep(1);
        }
        }


        //3、脱离进程空间
        //是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存
        shmdt(entry);


        //4、删除共享内存
        shmctl(shmid,IPC_RMID,0);


        return 0;
        }
        //g++ server.cpp common.h -o server -g -lpthread
        • client:

          #include "common.h"


          #include <sys/shm.h>
          #include <stdlib.h>
          #include <unistd.h>
          #include <stdio.h>
          #include <string.h>


          #include <iostream>


          int main(){
          //定义共享内存结构体
          struct ShmEntry *entry;


          //1、申请共享内容,参数为key,size和shmfig[IPC_CREAT|(IPC_CREAT|IPC_EXCL)],返回一个共享内存的id
          int shmid = shmget((key_t)1111,sizeof(struct ShmEntry),0666|IPC_CREAT);
          if(shmid == -1){
          std::cout << "创建共享内存失败" << std::endl;
          return -1;
          }


          //2、连接到当前进程空间使用共享内存
          //参数共享内存标识符、shmid指定共享内存出现在进程内存地址的什么位置,shmaddr直接指定为NULL让内核自己决定一个合适的地址位置,shmflg读写模式
          entry = (ShmEntry*)shmat(shmid,0,0);
          entry->can_read = 0;
          char buffer[TEXT_LEN];
          while(true){
          if(entry->can_read == 0){
          std::cout << "输入信息:>>>";
          fgets(buffer, TEXT_LEN, stdin);
          /*trncpy函数用于将指定长度的字符串复制到字符数组中,
          dest -- 指向用于存储复制内容的目标数组。
          src -- 要复制的字符串。
          n -- 要从源中复制的字符数*/
          strncpy(entry->msg,buffer,TEXT_LEN);
          std::cout << "发送信息: " << entry->msg << std::endl;
          entry->can_read = 1;
          }
          }


          //3、脱离进程空间
          //是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存
          shmdt(entry);


          //4、删除共享内存
          shmctl(shmid,IPC_RMID,0);


          return 0;
          }
          //g++ client.cpp common.h -o client -g -lpthread
          • common:

            #ifndef __COMMON_H__
            //if not define的简写
            #define __COMMON_H__


            #define TEXT_LEN 2048


            //共享内存的数据结构
            struct ShmEntry{
            //是否可以读取共享内存,用于进程间通信
            bool can_read;
            //共享内存信息
            char msg[2048];
            };
            #endif


          三、进程同步之unix域套接字

          • (1)、域套接字是一种高级的进程间通信的方法;

            • Unix域套接字可以用于同一机器进程间通信;

            • 提供了简单可靠的单机进程通信同步服务,但是只能在单机使用,不能跨机器使用;

          • (2)、套接字(socket)原是网络通信中使用的术语;

            • Unix系统提供的域套接字提供了网络套接字类似的功能;

            • 使用有如nginx,uWSGI,,mysql…

          • (3)、使用:

            • server:创建套接字
              —>绑定(bind)套接字
              —>监听(listen)套接字
              —>接受&处理信息
              —>关闭

            • client: 创建套接字
              —>连接套接字
              —>发送消息
              —>关闭

          • example:(域套接字的例子)

            • server:

              #include <stdio.h>
              #include <sys/types.h>
              #include <sys/socket.h>
              #include <sys/un.h>
              #include <strings.h>
              #include <string.h>
              #include <netinet/in.h>
              #include <stdlib.h>
              #include <unistd.h>


              #include <iostream>


              //域套接字定义
              #define SOCKET_PATH "./domainsocket"
              #define MSG_SIZE 2048


              int main(){
              int socket_fd,accept_fd;
              int ret = 0;
              socklen_t addr_len;
              char msg[MSG_SIZE];
              struct sockaddr_un server_addr;


              //1、创建域套接字
              socket_fd = socket(PF_UNIX,SOCK_STREAM,0);
              if(-1 == socket_fd){
              std::cout << "套接字创建失败" << std::endl;
              return -1;
              }


              //移除已有套接字路径
              remove(SOCKET_PATH);
              //内存区域置零
              bzero(&server_addr,sizeof(server_addr));
              server_addr.sun_family = PF_UNIX;
              strcpy(server_addr.sun_path,SOCKET_PATH);


              //2、绑定域套接字
              std::cout << "绑定套接字..." << std::endl;
              ret = bind(socket_fd,(sockaddr *)&server_addr,sizeof(server_addr));


              if(0 > ret){
              std::cout << "绑定套接字失败" << std::endl;
              return -1;
              }


              //3、监听套接字
              std::cout << "监听套接字..." << std::endl;
              ret = listen(socket_fd,10);
              if(-1 == ret){
              std::cout << "监听套接字失败" << std::endl;
              return ret;
              }
              std::cout << "等待新的请求." << std::endl;
              accept_fd = accept(socket_fd,NULL,NULL);


              bzero(msg,MSG_SIZE);


              //true必须小写
              while(true){
              //4、接受&处理信息
              recv(accept_fd,msg,MSG_SIZE,0);
              std::cout << "接受信息:" << msg << std::endl;
              }


              close(accept_fd);
              close(socket_fd);
              return 0;
              }
              //g++ server.cpp -o server -g -lpthread
              • client:

                #include <stdio.h>
                #include <sys/types.h>
                #include <sys/socket.h>
                #include <sys/un.h>
                #include <strings.h>
                #include <string.h>
                #include <netinet/in.h>
                #include <stdlib.h>
                #include <unistd.h>


                #include <iostream>


                //域套接字定义
                #define SOCKET_PATH "./domainsocket"
                #define MSG_SIZE 2048


                int main(){
                int socket_fd,accept_fd;
                int ret = 0;
                socklen_t addr_len;
                char msg[MSG_SIZE];
                struct sockaddr_un server_addr;


                //1、创建域套接字
                socket_fd = socket(PF_UNIX,SOCK_STREAM,0);
                if(-1 == socket_fd){
                std::cout << "套接字创建失败" << std::endl;
                return -1;
                }


                //内存区域置零
                bzero(&server_addr,sizeof(server_addr));
                server_addr.sun_family = PF_UNIX;
                strcpy(server_addr.sun_path,SOCKET_PATH);


                //2、连接域套接字
                std::cout << "2、连接套接字..." << std::endl;
                ret = connect(socket_fd,(sockaddr *)&server_addr,sizeof(server_addr));


                if(0 > ret){
                std::cout << "连接套接字失败" << std::endl;
                return -1;
                }


                while(true){
                //键入信息
                std::cout << "键入信息>>>";
                fgets(msg,MSG_SIZE,stdin);
                //3、发送消息
                ret = send(socket_fd,msg,MSG_SIZE,0);
                }


                close(socket_fd);
                return 0;
                }
                //g++ client.cpp -o client -g -lpthread




              文章转载自智慧大数据,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论