彩世界平台-彩世界时时app-彩世界开奖app苹果下载

热门关键词: 彩世界平台,彩世界时时app,彩世界开奖app苹果下载

您的位置:彩世界平台 > 彩世界开奖app苹果下载 > Linux网络编程--进程间通信(一),linux网络编程

Linux网络编程--进程间通信(一),linux网络编程

发布时间:2019-08-30 09:37编辑:彩世界开奖app苹果下载浏览(152)

    Linux网络编程--进程间通信(一),linux网络编程

    进程间通信简介(摘自《Linux网络编程》p85)

      AT&T 在 UNIX System V 中引入了几种新的进程通讯方式,即消息队列( MessageQueues),信号量( semaphores)和共享内存( shared memory),统称为 System V IPC。在Linux 系统编程中,它们有着广泛的应用。
      System V IPC 的一个显著的特点,是它的具体实例在内核中是以对象的形式出现的,我们称之为 IPC 对象。每个 IPC 对象在系统内核中都有一个唯一的标识符。通过标识符内核可以正确的引用指定的 IPC 对象.。需要注意的是,标识符的唯一性只在每一类的 IPC 对象内成立。比如说,一个消息队列和一个信号量的标识符可能是相同的,但绝对不会出现两个有相同标识符的消息队列。

      标识符只在内核中使用, IPC 对象在程序中是通过关键字( key)来访问的。和 IPC 对象标识符一样,关键字也必须是唯一的。而且,要访问同一个 IPC 对象, Server 和 Client必须使用同一个关键字。因此,如何构造新的关键字使之不和已有的关键字冲突,并保证Server 和 Client 使用的关键字是相同的,是建立 IPC 对象时首先要解决的一个问题。(具体在后边的msg通信中详解)

    通信方法还有:半双工管道pipe,命名管道fifo,消息队列,信号量,共享内,socket套接字等,下面一一介绍:

    ①半双工管道:

      int pipe(int filedes[2]);

      管道是将两个进程之间的标准输入输出相互对接的机制

      linux命令中使用的管道 |  : ls -l | grep *.c  //显示文件(输入端)-(|)-(输出端)>找到.c结尾文件

    实现:因为半双工缘故,所以只能实现一段输入,一段输出,而不能双向通信。所以:实现为,通过管道连接进程,一端开放读文件描述,一端开放写文件描述

    //管道的性质就是,一个进程的输出作为另一个进程的输入
    //那么我们可以关闭一个进程读端使之作为输入端,
    //另一个进程关闭写端,读取数据,接收数据作为管道输出端
    
    //FIFO命名管道
    //文件系统中,命名管道是特殊文件的方式存在的
    //不同进程可以通过命名管道共享数据
    
    //命名管道一直是阻塞方式的,且必须是显示的通过open建立连接到管道的通道
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<unistd.h>
    
    #include<sys/types.h>
    
    int main()
    {
        int result = 1;
        int fd[2];
        pid_t pid;
        int *write_fd = &fd[1];        //写文件描述
        int *read_fd = &fd[0];        //读文件描述
    
        int nbytes;
        char str[] = "管道,你好n";    
        char readBuffer[80];
        memset(readBuffer,0,sizeof(readBuffer));
    
        result = pipe(fd);        //创建管道
        if(-1==result)
        {
            printf("管道创建失败!n");
            return -1;
        }
    
        pid = fork();            //进程创建分叉程序
        if(-1 == pid)
        {
            printf("fork失败");
            return -1;
        }
    
        if(0==pid)            //子进程关闭读端,写入字符
        {
            close(*read_fd);
            result = write(*write_fd,str,strlen(str));
            printf("写入%d个数据n",result);
        }
        else                //父进程关闭写端,读取数据
        {
            close(*write_fd);
            nbytes = read(*read_fd,readBuffer,sizeof(readBuffer));
            printf("接收到%d个数据,内容为%s",nbytes,readBuffer);
        }
        return 0;
    }
    

    ②命名管道

      int mkfifo(const char* pathname,mode_t mode);

      类似于普通管道,只是

      a.在文件系统中以设备特殊文件的形式存在

      b.不同进程之间可以通过命名管道共享数据

    操作区别于普通管道:FIFO中必须显式通过open建立连接到管道的通道,且总是处于阻塞状态的

    ③消息队列

      消息队列是内核地址空间的内部链表,通过内核在各个进程之间传递内容。每个消息队列通过唯一IPC标识符标识,不同队列相对独立。

      

    //file: msg.h
    /* message buffer for msgsnd and msgrcv calls */
    struct msgbuf {
        __kernel_long_t mtype;          /* type of message */
        char mtext[1];                  /* message text */
    };
    
    /* Obsolete, used only for backwards compatibility and libc5 compiles */
    struct msqid_ds {
        struct ipc_perm msg_perm;
        struct msg *msg_first;        /* first message on queue,unused  */
        struct msg *msg_last;        /* last message in queue,unused */
        __kernel_time_t msg_stime;    /* last msgsnd time */
        __kernel_time_t msg_rtime;    /* last msgrcv time */
        __kernel_time_t msg_ctime;    /* last change time */
        unsigned long  msg_lcbytes;    /* Reuse junk fields for 32 bit */
        unsigned long  msg_lqbytes;    /* ditto */
        unsigned short msg_cbytes;    /* current number of bytes on queue */
        unsigned short msg_qnum;    /* number of messages in queue */
        unsigned short msg_qbytes;    /* max number of bytes on queue */
        __kernel_ipc_pid_t msg_lspid;    /* pid of last msgsnd */
        __kernel_ipc_pid_t msg_lrpid;    /* last receive pid */
    };
    
    //filename
    /* Obsolete, used only for backwards compatibility and libc5 compiles */
    struct ipc_perm
    {
        __kernel_key_t    key;  //函数msgget()使用的键值  
        __kernel_uid_t    uid;  //用户UID
        __kernel_gid_t    gid;  //用户GID
        __kernel_uid_t    cuid;  //创建者UID
        __kernel_gid_t    cgid;  //创建者GID
        __kernel_mode_t    mode;   //权限
        unsigned short    seq;  //序列号
    };
    

      内核中的消息队列

    图片 1

    注:结构list_head 形成一个链表,结构msg_msg之中的m_list使得消息形成链表,查找,插入时,对m_list域进行偏移找到位置

    相关函数:

      键值构建 key_t ftok(const char* pathname,int proj_id);

      获取消息 int msgget(key_t key,int msgflg);

      发送消息 int msgsnd(int msqid, const void * msgp,size_t msgsz,int msgflg);

      接收消息 ssize_t msgrcv(int msqid, void * msgp, size_t msgsz, long msgtype, int msgflg);

      消息控制 int msgctl(int msqid, int cmd, struct msqid_ds *buf);  //向内核发送cmd命令判断进行何种操作

    一个简单例子

    ④信号量

      信号量是一种计数器,用来控制对多个进程共享的资源所进行的访问。常用作锁机制(生产者消费者模型是个典型使用)

      信号量结构

    //filename sys/sem.h
    /* arg for semctl system calls. */
    union semun {
        int val;            /* value for SETVAL */
        struct semid_ds *buf;    /* buffer for IPC_STAT & IPC_SET */
        unsigned short *array;    /* 数组结构 */
        struct seminfo *__buf;    /* 信号量内部结构 */
        void *__pad;
    };
    

      相关函数 

      新建信号量 int semget(key_t key, int nsems, int semflg);

      //key 来自于ftok()

      信号量操作函数 int semop(int semid,struct sembuf* sops, unsigned nsops);

      //信号量的P,V操作通过向已经建立好的信号量发送命令完成

      控制信号量参数

      int semctl(int semid, int semnum ,int cmd,.....);

      //用于在信号量集合上执行控制操作

    #include<stdio.h>
    #include<unistd.h>
    #include<sys/ipc.h>
    #include<sys/sem.h>
    #include<sys/types.h>
    
    typedef int sem_t;
    union semun
    {
        int val;
        struct semid_ds * buf;
        unsigned short *array;
    }arg;
    
    sem_t CreateSem(key_t key, int value)
    {
        union semun sem;
        sem_t semid;
        sem.val = value;
    
        semid = semget(key,0,IPC_CREAT);
        if(-1 == semid)
        {
            printf("create semaphore errorn");
            return -1;
        }
    
        semctl(semid,0,SETVAL,sem);
    
        return semid;
    }
    
    int Sem_P(sem_t semid)
    {
    struct sembuf sops = {0,+1,IPC_NOWAIT};
    return (semop(semid,&sops,1));
    }
    
    int Sem_V(sem_t semid)
    {
        struct sembuf sops = {0,-1,IPC_NOWAIT};
        return (semop(semid,&sops,1));
    }
    
    void SetvalueSem(sem_t semid , int value)
    {
        union semun sem;
        sem.val = value;
        semctl(semid,0,SETVAL,sem);
    }
    
    int GetvalueSem(sem_t semid)
    {
        union semun sem;
        return semctl(semid,0,GETVAL,sem);
    }
    
    void DestroySem(sem_t semid)
    {
        union semun sem;
        sem.val = 0;
        semctl(semid,0,IPC_RMID,sem);
    }
    int main()
    {
        key_t key;
        int semid;
        char i;
        int value = 0;
        key = ftok("/ipc/sem",'a');
    
        semid = CreateSem(key,100);
        for( i = 0;i <= 3;++i)
        {
            Sem_P(semid);
            Sem_V(semid);    
        }
        value = GetvalueSem(semid);    
    
        DestroySem(semid);    
        return 0;
    }
    

    ⑤共享内存(最快捷的方法)没有中间过程,管道等

      在多个进程之间共享内存区域的一种进程间通信方式,在多个进程之间对内存段进行映射的方式实现内存共享。

        相关函数

      创建共享内存函数 int shmget(key_y key, size_t size, int shmflg);

      获得共享内存地址void * shmat(int shmid,const void* shmaddr, int shmflg);

      删除共享内存函数 int shmdt(const void* shmadddr);

      共享内存控制函数 int shmctl(int shmid ,int cmd, struct shmid_ds * buf);

    ⑥信号

      用于在一个或多个进程之间传递异步信号。

      相关函数

      信号截取 sighandler signal(int signum ,sighandler handler);

      发送信号 int kill(pid_t pid, int sig);

           int raise(int sig);

      

      

      

      

    进程间通信简介(摘自《Linux网络编程》p85) ATT 在 UNIX System V 中引入了几种新的进程通讯...

    进程间通信简介(摘自《Linux网络编程》p85)

      AT&T 在 UNIX System V 中引入了几种新的进程通讯方式,即消息队列( MessageQueues),信号量( semaphores)和共享内存( shared memory),统称为 System V IPC。在Linux 系统编程中,它们有着广泛的应用。
      System V IPC 的一个显著的特点,是它的具体实例在内核中是以对象的形式出现的,我们称之为 IPC 对象。每个 IPC 对象在系统内核中都有一个唯一的标识符。通过标识符内核可以正确的引用指定的 IPC 对象.。需要注意的是,标识符的唯一性只在每一类的 IPC 对象内成立。比如说,一个消息队列和一个信号量的标识符可能是相同的,但绝对不会出现两个有相同标识符的消息队列。

      标识符只在内核中使用, IPC 对象在程序中是通过关键字( key)来访问的。和 IPC 对象标识符一样,关键字也必须是唯一的。而且,要访问同一个 IPC 对象, Server 和 Client必须使用同一个关键字。因此,如何构造新的关键字使之不和已有的关键字冲突,并保证Server 和 Client 使用的关键字是相同的,是建立 IPC 对象时首先要解决的一个问题。(具体在后边的msg通信中详解)

    通信方法还有:半双工管道pipe,命名管道fifo,消息队列,信号量,共享内,socket套接字等,下面一一介绍:

    ①半双工管道:

      int pipe(int filedes[2]);

      管道是将两个进程之间的标准输入输出相互对接的机制

      linux命令中使用的管道 |  : ls -l | grep *.c  //显示文件(输入端)-(|)-(输出端)>找到.c结尾文件

    实现:因为半双工缘故,所以只能实现一段输入,一段输出,而不能双向通信。所以:实现为,通过管道连接进程,一端开放读文件描述,一端开放写文件描述

    //管道的性质就是,一个进程的输出作为另一个进程的输入
    //那么我们可以关闭一个进程读端使之作为输入端,
    //另一个进程关闭写端,读取数据,接收数据作为管道输出端
    
    //FIFO命名管道
    //文件系统中,命名管道是特殊文件的方式存在的
    //不同进程可以通过命名管道共享数据
    
    //命名管道一直是阻塞方式的,且必须是显示的通过open建立连接到管道的通道
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<unistd.h>
    
    #include<sys/types.h>
    
    int main()
    {
        int result = 1;
        int fd[2];
        pid_t pid;
        int *write_fd = &fd[1];        //写文件描述
        int *read_fd = &fd[0];        //读文件描述
    
        int nbytes;
        char str[] = "管道,你好n";    
        char readBuffer[80];
        memset(readBuffer,0,sizeof(readBuffer));
    
        result = pipe(fd);        //创建管道
        if(-1==result)
        {
            printf("管道创建失败!n");
            return -1;
        }
    
        pid = fork();            //进程创建分叉程序
        if(-1 == pid)
        {
            printf("fork失败");
            return -1;
        }
    
        if(0==pid)            //子进程关闭读端,写入字符
        {
            close(*read_fd);
            result = write(*write_fd,str,strlen(str));
            printf("写入%d个数据n",result);
        }
        else                //父进程关闭写端,读取数据
        {
            close(*write_fd);
            nbytes = read(*read_fd,readBuffer,sizeof(readBuffer));
            printf("接收到%d个数据,内容为%s",nbytes,readBuffer);
        }
        return 0;
    }
    

    ②命名管道

      int mkfifo(const char* pathname,mode_t mode);

      类似于普通管道,只是

      a.在文件系统中以设备特殊文件的形式存在

      b.不同进程之间可以通过命名管道共享数据

    操作区别于普通管道:FIFO中必须显式通过open建立连接到管道的通道,且总是处于阻塞状态的

    ③消息队列

      消息队列是内核地址空间的内部链表,通过内核在各个进程之间传递内容。每个消息队列通过唯一IPC标识符标识,不同队列相对独立。

      

    //file: msg.h
    /* message buffer for msgsnd and msgrcv calls */
    struct msgbuf {
        __kernel_long_t mtype;          /* type of message */
        char mtext[1];                  /* message text */
    };
    
    /* Obsolete, used only for backwards compatibility and libc5 compiles */
    struct msqid_ds {
        struct ipc_perm msg_perm;
        struct msg *msg_first;        /* first message on queue,unused  */
        struct msg *msg_last;        /* last message in queue,unused */
        __kernel_time_t msg_stime;    /* last msgsnd time */
        __kernel_time_t msg_rtime;    /* last msgrcv time */
        __kernel_time_t msg_ctime;    /* last change time */
        unsigned long  msg_lcbytes;    /* Reuse junk fields for 32 bit */
        unsigned long  msg_lqbytes;    /* ditto */
        unsigned short msg_cbytes;    /* current number of bytes on queue */
        unsigned short msg_qnum;    /* number of messages in queue */
        unsigned short msg_qbytes;    /* max number of bytes on queue */
        __kernel_ipc_pid_t msg_lspid;    /* pid of last msgsnd */
        __kernel_ipc_pid_t msg_lrpid;    /* last receive pid */
    };
    
    //filename
    /* Obsolete, used only for backwards compatibility and libc5 compiles */
    struct ipc_perm
    {
        __kernel_key_t    key;  //函数msgget()使用的键值  
        __kernel_uid_t    uid;  //用户UID
        __kernel_gid_t    gid;  //用户GID
        __kernel_uid_t    cuid;  //创建者UID
        __kernel_gid_t    cgid;  //创建者GID
        __kernel_mode_t    mode;   //权限
        unsigned short    seq;  //序列号
    };
    

      内核中的消息队列

    图片 2

    注:结构list_head 形成一个链表,结构msg_msg之中的m_list使得消息形成链表,查找,插入时,对m_list域进行偏移找到位置

    相关函数:

      键值构建 key_t ftok(const char* pathname,int proj_id);

      获取消息 int msgget(key_t key,int msgflg);

      发送消息 int msgsnd(int msqid, const void * msgp,size_t msgsz,int msgflg);

      接收消息 ssize_t msgrcv(int msqid, void * msgp, size_t msgsz, long msgtype, int msgflg);

      消息控制 int msgctl(int msqid, int cmd, struct msqid_ds *buf);  //向内核发送cmd命令判断进行何种操作

    一个简单例子

    本文由彩世界平台发布于彩世界开奖app苹果下载,转载请注明出处:Linux网络编程--进程间通信(一),linux网络编程

    关键词: