常用的进程间通信方式
• 传统的进程间通信方式
无名管道(pipe)、有名管道(fifo)和信号(signal)
• System V IPC对象
共享内存(share memory)、消息队列(message queue)和信号量(semaphore)
• BSD
套接字(socket)
当前目录下路径指定要加上“.”
ftok (“./app”, ‘i’)才可以
“./”才是当前路径,“/“根目录路径
IPC
IPC对象
IPC(Inter-Process Communication)进程间通信,提供了各种进程间通信的方法
ipcs、 ipcrm
- ipcs命令用于查看系统中的IPC对象
ipcs –m 共享内存
ipcs –s 信号量
ipcs –q 消息队列
- ipcrm命令用于删除系统中的IPC对象
ipcrm –m id
创建的IPC对象如果不删除的话会一直保留在系统中
共享内存
“./”才是当前路径,“/“根目录路径
共享内存(share memory)
- 共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝
- 为了在多个进程间交换信息, 内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间
- 进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高的效率。
- 由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等
从串口读取的zigbee网络环境数据要发送给web页面或者APP,必须满足:
- 所有的其他进程都可以定时从”某块内存” 读取数据
- 有新的数据更新时,可以很方便的将数据写入到” 某块内存”
- 读取的数据不需要清除原有数据,写入的数据要更新到这块内存
共享内存实现
共享内存的使用包括如下步骤:
- 创建/打开共享内存
- 映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
- 撤销共享内存映射
- 删除共享内存对象
共享内存函数调用流程
共享内存函数
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); }