进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现(上)

简介: 进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现

常用的进程间通信方式

• 传统的进程间通信方式

无名管道(pipe)、有名管道(fifo)和信号(signal)

• System V IPC对象

共享内存(share memory)、消息队列(message queue)和信号量(semaphore)

• BSD

套接字(socket)

当前目录下路径指定要加上“.”

ftok (“./app”, ‘i’)才可以

“./”才是当前路径,“/“根目录路径

IPC

IPC对象

IPC(Inter-Process Communication)进程间通信,提供了各种进程间通信的方法

ipcs、 ipcrm

  1. ipcs命令用于查看系统中的IPC对象

ipcs –m 共享内存

ipcs –s 信号量

ipcs –q 消息队列

  1. ipcrm命令用于删除系统中的IPC对象
    ipcrm –m id
    创建的IPC对象如果不删除的话会一直保留在系统中

共享内存

“./”才是当前路径,“/“根目录路径

共享内存(share memory)

  1. 共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝
  2. 为了在多个进程间交换信息, 内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间
  3. 进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高的效率。
  4. 由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等
    从串口读取的zigbee网络环境数据要发送给web页面或者APP,必须满足:
  • 所有的其他进程都可以定时从”某块内存” 读取数据
  • 有新的数据更新时,可以很方便的将数据写入到” 某块内存”
  • 读取的数据不需要清除原有数据,写入的数据要更新到这块内存

共享内存实现

共享内存的使用包括如下步骤:

  1. 创建/打开共享内存
  2. 映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
  3. 撤销共享内存映射
  4. 删除共享内存对象

共享内存函数调用流程

共享内存函数

shmget

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, int size, int shmflg);

key:

IPC_PRIVATE 或 ftok的返回值

size:

共享内存区大小

shmflg:

同open函数的权限位,也可以用8进制表示法

返回值

成功:共享内存段标识符

出错: -1

shmat

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);

shmid:要映射的共享内存区标识符

shmaddr:将共享内存映射到指定地址(若为NULL,则表示由系统自动完成映射)

shmflg :

SHM_RDONLY:共享内存只读

默认0:共享内存可读写

返回值:

成功:映射后的地址

出错: -1

shmdt

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>

shmaddr

:共享内存映射后的地址

返回值

成功: 0

出错:-1

shmctl

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmid:要操作的共享内存标识符

cmd : IPC_STAT (获取对象属性)

IPC_SET (设置对象属性)

IPC_RMID (删除对象)

buf : 指定IPC_STAT/IPC_SET时用以保存/设置属性

返回值

成功: 0

出错:-1

举例

Linux终端放大缩小:

放大:

ctrl+shift+=

缩小:

ctrl±

shm-server.c

/* shm_server.c : the time server using shared memory, a bizarre application  */
#include    <stdio.h>
#include    <sys/shm.h>
#include    <time.h>
#include        <stdlib.h>
#include        <unistd.h>
#include        <string.h>
#define    TIME_MEM_KEY    99    /* like a filename      */
#define    SEG_SIZE    ((size_t)100)    /* size of segment      */
main()
{
    long now;
    int n;
    key_t key_info;
    if ((key_info = ftok ("/app", 'i')) < 0)
    {
        perror ("ftok info");
        exit (-1);
    }
    /* create a shared memory segment */
    int seg_id = shmget(key_info, SEG_SIZE, IPC_CREAT | 0777);
    /* attach to it and get a pointer to where it attaches */
    char *mem_ptr = shmat(seg_id, NULL, 0);
    /* run for a minute */
    for (n = 0; n < 60; n++) 
    {
        time(&now);            /* get the time */
        strcpy(mem_ptr, ctime(&now));    /* write to mem */
        sleep(1);            /* wait a sec   */
    }
    shmctl(seg_id, IPC_RMID, NULL);
}

shm-client.c

/* shm_client.c : the time client using shared memory, a bizarre application  */
#include        <stdlib.h>
#include        <unistd.h>
#include    <stdio.h>
#include    <sys/shm.h>
#include    <time.h>
#define    TIME_MEM_KEY    99
#define    SEG_SIZE    ((size_t)100)
main()
{
    key_t key_info;
    if ((key_info = ftok ("/app", 'i')) < 0)
    {
        perror ("ftok info");
        exit (-1);
    }
    int seg_id = shmget(key_info, SEG_SIZE, 0777);
    char *mem_ptr = shmat(seg_id, NULL, 0);
    printf("The time, direct from memory: ..%s", mem_ptr);
    shmdt(mem_ptr);
}

share.c
#include <sys/ipc.h>
 #include <sys/shm.h>
#include <stdio.h>
#include <sys/stat.h>
 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
int main()
{
    int  segment_id,segment_size;
    char *shared_memory;
    struct shmid_ds shmbuffer;
    const int shared_segment_size = 0x6400;
/*分配*/
    segment_id = shmget (IPC_PRIVATE, shared_segment_size, 
                      IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR ); 
    shared_memory = (char*) shmat (segment_id, 0, 0); 
    printf ("shared memory attached at address %p\n", shared_memory); 
    shmctl (segment_id, IPC_STAT, &shmbuffer); 
    segment_size = shmbuffer.shm_segsz; 
    printf ("segment size: %d\n", segment_size); 
    sprintf (shared_memory, "Hello, world."); 
    shmdt (shared_memory); 
/*绑定到共享内存块*/
    shared_memory = (char*) shmat (segment_id, (void*) 0x500000, 0); 
    printf ("shared memory reattached at address %p\n",shared_memory); 
    printf ("%s\n", shared_memory);
    /*tuo li*/
    shmdt (shared_memory); 
    /*释放内存*/
    shmctl (segment_id, IPC_RMID, 0); 
    return;
}

消息队列(message queue)

  • 消息队列是IPC对象的一种
  • 消息队列由消息队列ID来唯一标识
  • 消息队列就是一个消息的列表。 用户可以在消息队列中添加消息、 读取消息等。
  • 消息队列可以按照类型来发送/接收消息

消息队列函数调用流程

消息队列函数

msgget

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int flag);

key:和消息队列关联的key值

flag:消息队列的访问权限

返回值:

成功:消息队列ID

出错: -1

msgsnd

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t size,int flag);

msqid:消息队列的ID

msgp:指向消息的指针。常用消息结构msgbuf如下:

struct msgbuf
{
long mtype; //消息类型
char mtext[N];//消息正文
};

size:发送的消息正文的字节数

flag:

IPC_NOWAIT 消息没有发送完成函数也会立即返回。

0:直到发送完成函数才返回

返回值:

成功:0

出错: -1

msgrcv

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
 int msgrcv(int msgid,  void* msgp,  size_t  size,  long msgtype,  int  flag);

函数参数

msqid:消息队列的ID

msgp:接收消息的缓冲区

size:要接收的消息的字节数

msgtype:

0:接收消息队列中第一个消息。

大于0:接收消息队列中第一个类型为msgtyp的消息.

小于0:接收消息队列中类型值不小于msgtyp的绝对值且类型值又最小的消息。

flag:

0:若无消息函数会一直阻塞

IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG。

函数返回值

成功:接收到的消息的长度

出错:-1

msgctl

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );

函数参数

msqid:消息队列的队列ID

cmd:

IPC_STAT:读取消息队列的属性,并将其保存在buf指向的缓冲区中。

IPC_SET:设置消息队列的属性。这个值取自buf

IPC_RMID:从系统中删除消息队列。

buf:消息队列缓冲区函数

返回值 成功:0

出错:-1

举例

server

#include<stdio.h>
#include<fcntl.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/stat.h>
#define QUEUE_MSG_LEN    256
#define PROJ_ID        'g'
#define PATH_NAME    "/app"
#define SERVER_MSG    1
#define CLIENT_MSG    2
/*message data structure */
struct msg 
{
    long type;
    long msgtype;
    unsigned char text[QUEUE_MSG_LEN];
};
int main(void)
{
    /*message data structure */
    struct msg msg_buf;
    int qid;
    int msglen;
    int i=0;
    /*get message queue */
    key_t msgkey;
    if ((msgkey = ftok(PATH_NAME, PROJ_ID)) == -1) 
    {
        perror("ftok error!\n");
        exit(1);
    }
    if ((qid = msgget(msgkey, IPC_CREAT | 0666)) == -1) 
    {
        perror("msgget error!\n");
        exit(1);
    }
    while (1) 
    {
        printf("server send: ");
        /*get string from terminal & fill up message data structure */
        fgets(msg_buf.text, QUEUE_MSG_LEN, stdin);
        if (strncmp("exit", msg_buf.text, 4) == 0) 
        {
            msgctl(qid, IPC_RMID, NULL);
            break;
        }
        msg_buf.text[strlen(msg_buf.text) - 1] = '\0';
        msg_buf.type = SERVER_MSG;
        msg_buf.msgtype = i++;
        /*send message to message queue with SERVER_MSG type */
        if (msgsnd(qid, &msg_buf, sizeof(struct msg) - sizeof(long), 0) == -1) 
        {
            perror("Server msgsnd error!\n");
            exit(1);
        }
#if 1
        /*receive message from message queue with CLIENT_MSG type */
        if (msgrcv(qid, &msg_buf, sizeof(struct msg) - sizeof(long), CLIENT_MSG, 0) == -1) 
        {
            perror("Server msgrcv error!\n");
            exit(1);
        }
        printf("server rcv: %d: %s\n",msg_buf.msgtype,msg_buf.text);
#endif        
    }
    exit(0);
}

client

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#define QUEUE_MSG_LEN    256
#define PROJ_ID        'g'
#define PATH_NAME    "/app"
#define SERVER_MSG    1
#define CLIENT_MSG    2
/*message data structure */
struct msg 
{
    long type;
    long msgtype;
    unsigned char text[QUEUE_MSG_LEN];
};
int main(void)
{
    int qid;
    int msglen;
    int i=0;
    struct msg msg_buf;
    /* get a message queue */
    key_t msgkey;
    if ((msgkey = ftok(PATH_NAME, PROJ_ID)) == -1) //得到ID,
    {
        perror("ftok error!\n");
        exit(1);
    }
    if ((qid = msgget(msgkey, IPC_CREAT | 0666)) == -1) 
    {
        perror("msgget error!\n");
        exit(1);
    }
    while (1) 
    {
        /*receive message from message queue with SERVER_MSG type */
        if (msgrcv(qid, &msg_buf, sizeof(struct msg) - sizeof(long), SERVER_MSG, 0) == -1) 
        {
            perror("Server msgrcv error!\n");
            exit(1);
        }
        printf("server rcv : %ld: %s\n",msg_buf.msgtype,msg_buf.text);    
#if 1
        printf("client send: ");
        /*get string from terminal & fill up message data structure */
        fgets(msg_buf.text, QUEUE_MSG_LEN, stdin);
        if (strncmp("exit", msg_buf.text, 4) == 0) 
        {
            break;
        }
        msg_buf.text[strlen(msg_buf.text) - 1] = '\0';
        msg_buf.type = CLIENT_MSG;
        msg_buf.msgtype = i++;
        /*send message to message queue with CLIENT_MSG type */
        if (msgsnd(qid, &msg_buf, strlen(msg_buf.text) + 1+4, 0) == -1) 
        {
            perror("client msgsnd error!\n");
            exit(1);
        }
        #endif
    }
    exit(0);
}

目录
相关文章
|
2月前
|
消息中间件 安全 Linux
线程同步与IPC:单进程多线程环境下的选择与权衡
线程同步与IPC:单进程多线程环境下的选择与权衡
64 0
|
2月前
|
消息中间件 Unix Linux
Linux进程间通信(IPC)介绍:详细解析IPC的执行流程、状态和通信机制
Linux进程间通信(IPC)介绍:详细解析IPC的执行流程、状态和通信机制
60 1
|
3月前
|
编译器 C++ 开发者
QT基础【7-跨进程发送信号】
QT基础【7-跨进程发送信号】
|
2月前
|
消息中间件 Linux API
C/C++ 进程间通信system V IPC对象超详细讲解(系统性学习day9)
C/C++ 进程间通信system V IPC对象超详细讲解(系统性学习day9)
|
5月前
|
消息中间件 NoSQL Linux
Linux进程信号【信号保存】
Linux进程信号【信号保存】
41 0
|
2月前
|
监控 Shell Linux
【Shell 命令集合 系统管理 】⭐⭐⭐Linux 向进程发送信号 kill命令 使用指南
【Shell 命令集合 系统管理 】⭐⭐⭐Linux 向进程发送信号 kill命令 使用指南
31 0
|
5月前
|
存储 Linux 编译器
Linux进程信号【信号处理】
Linux进程信号【信号处理】
44 0
|
8天前
|
NoSQL Linux 程序员
【linux进程信号(一)】信号的概念以及产生信号的方式
【linux进程信号(一)】信号的概念以及产生信号的方式
|
2月前
|
消息中间件 存储 网络协议
Linux IPC 进程间通讯方式的深入对比与分析和权衡
Linux IPC 进程间通讯方式的深入对比与分析和权衡
69 0
|
2月前
|
安全 Shell Linux
【Shell 命令集合 系统管理 】Linux 终止或向进程发送信号 skill命令 使用指南
【Shell 命令集合 系统管理 】Linux 终止或向进程发送信号 skill命令 使用指南
31 0