System V的IPC包括System V消息队列,System V信号量和System共享内存。特征是使用key_t来标志,一般是一个32位的整数,正式说法是一个不小于32位的整数。
没有亲缘关系的进程之间需要约定好一个文件或目录名(反正目录也是文件),以及一个整数值,然后调用ftok()函数返回一个key_t。
key_t类型在<sys/types.h>中定义。
函数ftok原型为:
#include <sys/ipc.h> /* Generates key for System V style IPC. */ key_t ftok (const char *pathname, int proj_id);得到key_t类型的IPC键后,就可以调用shmget函数获得共享内存标志符了。这个标志符是一个int,一般进程间通信,总有一个是相当于服务器的,他来创建这个共享内存,其他进程默认假定该共享内存已经存在。
POSIX 共享内存的大小可以用ftruncate随时修改,但System V的共享内存在shmget调用之后就确定了无法修改。
http://blog.csdn.net/zhangzhenghe/article/details/6838019
1.创建
(1)在服务器端,需要进行创建:
key_t kt = ftok("/home/administrator", 0);
int id = shmget(kt, 1024, IPC_CREAT | 0666);
关键的地方:1024为字节数,IPC_CREAT表示不存在则创建,存在则直接用;IPC_CREAT|IPC_EXCL表示不存在则创建,存在则返回-1退出;0666表示权限,注意前面的0,表示八进制,切记!
(2)在客户端,需要创建:
key_t kt = ftok("/home/administrator", 0);
int id = shmget(kt, 0,0666);
由于共享内存区已经存在,所以第二个参数必须为0,第三个参数也跟creat不相干,指定权限位即可。
2.绑定
key_t kt = ftok("/home/administrator", 0);int id = shmget(kt, 0,0666);
p = shmat( id, NULL ,0);p是一个指针,什么指针都行。
然后就可以进行读写了。
3.解除绑定
key_t kt = ftok("/home/administrator", 0);
int id = shmget(kt, 0,0666);
char *p=shmat(id,NULL,0);shmdt(p);
4.删除
key_t kt = ftok("/home/administrator", 0);int id = shmget(kt, 0,0666);
shmctl(id,IPC_RMID,NULL);
5.获得大小
key_t kt = ftok("/home/administrator", 0);int id = shmget(kt, 0,0666);
struct shmid_ds buff;
shmctl(id,IPC_STAT,&buff);
printf("ize: %d\n", buff.shm_segsz);
System V 共享内存实现之前的系统日志:
包括4个文件:
mylog.h sys_v_cle.c sys_v_ser.c mylog.c
头文件:
#ifndef _MYLOG_H_
#define _MYLOG_H_
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <sys/shm.h>
#define N_MSG 4 // message的个数
#define LEN_MSG 256 // 每个message的长度
//#define FILE_MODE S_IRUSR | S_IWUSR //rwxrwxrwx
#define FILE_MODE 00600 //rwxrwxrwx
#define px_ipc_name(x) (x) //空的宏定义,暂时没有用
struct msg_ctl_str {
sem_t mutex;
sem_t empty;
sem_t full;
int nput; // 下一个可以由生产者放置log信息的index序号
int nread; // 已经处理完毕的消息序号,初始为-1,这样,下一个要处理的就是0
char msgdata[N_MSG][LEN_MSG];
} msg_ctl_str;
void my_syslog (const char *msg, char *argv[]); //给客户端的函数
#endif
sys_v_ser.c。服务器采用独占方式,如果已经存在,则将ftok的第二个参数+1,再次尝试。
#include "mylog.h"
int main(int argc, char *argv[])
{
key_t kt;
int id;
int n=0;
struct msg_ctl_str *p;
int i;
// 创建共享内存区
kt = ftok(argv[1], atoi(argv[2])+n );
id = shmget(kt, sizeof(struct msg_ctl_str), IPC_CREAT | IPC_EXCL|0666);
while (id == -1)
{
++n;
kt =ftok(argv[1], atoi(argv[2])+n );
id = shmget(kt, sizeof(struct msg_ctl_str), IPC_CREAT | IPC_EXCL|0666);
}
printf("server start! key_t: %s, %d\n", argv[1], atoi(argv[2])+n );
// 映射
p = shmat( id, NULL ,0);
if (p==-1)
{
printf("shmat fail!\n");
exit(2);
}
// 初始化
sem_init(&(p->mutex),1,1);
sem_init(&(p->empty),1,N_MSG);
sem_init(&(p->full),1,0);
p->nput=0;
p->nread=-1;
for(i=0;i<N_MSG;i++)
p->msgdata[i][0]='\0';
while(1)
{
sem_wait(& (p->full));
sem_wait(& (p->mutex));
p->nread++;
p->nread %= N_MSG;
printf("处理第 %d 条: %s\n", p->nread, p->msgdata[p->nread]);
sem_post(& (p->mutex));
sem_post(& (p->empty));
}
// 不会运行
shmdt(p); // 断开
shmctl(id, IPC_RMID, NULL); //
}
sys_v_cle.c:
#include "mylog.h"
int main(int argc, char *argv[])
{
char *s="I am client";
my_syslog(s, argv);
return 0;
}
sys_v_cle.c调用了mylog.c中的函数。mylog.c:
#include "mylog.h"
void
my_syslog (const char *msg, char *argv[])
{
key_t kt;
int n=0;
int id;
struct msg_ctl_str *p;
// printf("%s %s\n", argv[1], argv[2]);
//打开
kt = ftok( argv[1], atoi(argv[2]+n) );
id = shmget(kt,0,0666);
while (id == -1)
{
++n;
kt = ftok( argv[1], atoi(argv[2]+n) );
id=shmget(kt,0,0666);
}
printf("client key_t: %s, %d--", argv[1], atoi(argv[2])+n );
//映射
p = (struct msg_ctl_str *)shmat(id,NULL,0);
if (p==-1)
{
printf("shmat fail!\n");
exit(2);
}
//干正事
sem_wait (&(p->empty)); //等待有消息的到来,没有消息的话一直阻塞在这里
sem_wait (&(p->mutex)); //取得互斥
// 处理!就是打印到标准输出而已
strncpy (p->msgdata[p->nput], msg, 255);
printf ("process %d add a msg to log (%d, %s)\n", getpid (), p->nput,
p->msgdata[p->nput]);
p->msgdata[p->nput][255] = '\0';
p->nput++;
p->nput = p->nput % N_MSG;
//
sem_post (&(p->mutex));
sem_post (&(p->full)); //empty的位置增加了一个
}
开启两个终端,第一个终端启动服务器:
administrator@ubuntu:~/test/sys_v$ ./ss /home/administrator 2 & <--启动
[4] 5936
administrator@ubuntu:~/test/sys_v$ server start! key_t: /home/administrator, 4 <--打出来的信息。客户端的参数应使用4
administrator@ubuntu:~/test/sys_v$ jobs
[3]- 运行中 ./log_server & (工作目录:~/test/log_test)
[4]+ 运行中 ./ss /home/administrator 2 &
第二个终端启动客户端:
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5937 add a msg to log (0, I am client)
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5938 add a msg to log (1, I am client)
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5939 add a msg to log (2, I am client)
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5940 add a msg to log (3, I am client)
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5941 add a msg to log (0, I am client)
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5942 add a msg to log (1, I am client)
administrator@ubuntu:~/test/sys_v$ ./cc /home/administrator 4
client key_t: /home/administrator, 4--process 5943 add a msg to log (2, I am client)
administrator@ubuntu:~/test/sys_v$
客户端一共运行了7次,写了7条消息。第一个终端中的服务器收到消息,就进行处理,把消息相关的信息打出来:
administrator@ubuntu:~/test/sys_v$ 处理第 0 条: I am client
处理第 1 条: I am client
处理第 2 条: I am client
处理第 3 条: I am client
处理第 0 条: I am client
处理第 1 条: I am client
处理第 2 条: I am client
共7条。此后服务器再次进行等待。