2017-2018-1 20155317 IPC

- 共享内存

共享内存主要是通过映射机制实现的。以window系统调用为例子:Windows 下进程的地址空间在逻辑上是相互隔离的,但在物理上却是重叠的。所谓的重叠是指同一块内存区域可能被多个进程同时使用。当调用 CreateFileMapping 创建命名的内存映射文件对象时,Windows 即在物理内存申请一块指定大小的内存区域,返回文件映射对象的句柄 hMap。为了能够访问这块内存区域必须调用 MapViewOfFile 函数,促使 Windows 将此内存空间映射到进程的地址空间中。当在其他进程访问这块内存区域时,则必须使用OpenFileMapping 函数取得对象句柄 hMap,并调用 MapViewOfFile 函数得到此内存空间的一个映射。这样一来,系统就把同一块内存区域映射到了不同进程的地址空间中,从而达到共享内存的目的。

#include <iostream>
#include <windows.h>
#include <string>
#include <cstring>
using namespace std; int main() {
string strMapName("ShareMemory"); // 内存映射对象名称
string strComData("This is common data!"); // 共享内存中的数据
LPVOID pBuffer; // 共享内存指针 // 首先试图打开一个命名的内存映射文件对象
HANDLE hMap = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, , strMapName.c_str());
if (NULL == hMap)
{
// 打开失败,创建之
hMap = ::CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,,strComData.length()+,strMapName.c_str());
// 映射对象的一个视图,得到指向共享内存的指针,设置里面的数据
pBuffer = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, , , );
strcpy((char*)pBuffer, strComData.c_str());
cout << "写入共享内存数据:" << (char *)pBuffer << endl; }
else
{
// 打开成功,映射对象的一个视图,得到指向共享内存的指针,显示出里面的数据
pBuffer = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, , , );
cout << "读取共享内存数据:" << (char *)pBuffer << endl; } getchar(); // 注意,进程关闭后,所有句柄自动关闭,所以要在这里暂停 // 解除文件映射,关闭内存映射文件对象句柄
::UnmapViewOfFile(pBuffer);
::CloseHandle(hMap);
system("pause");
return ; }

- 管道

—管道是一种半双工的通信方式
—数据只能单向流动,而且只能在具有共同祖先的进程间使用。 所谓半双工的模式(以下是我的理解): 形象来说类似一个单刀双掷开关,有两个选择,但是二者是互斥的,当选择了一方另一方就失效。 而对于此处的管道,可以把它想成是管道的一端,一次只能调用一种功能读入或者写入,二者也是互斥的。 同时对应的fd[0]与fd[1]其实是一个类似一个临界区的资源,一次只能由一个进程使用一种功能,所以使用时要注意分配读和写的功能。
父进程创建管道和两个子进程p1和p2
¢2.子进程p1打开给定文件(如果没有,则创建文件),并向文件中写数据,写完关闭文件,然后向管道写入一条消息“ok",目的是通知进程p2可以读取文件内容了。
¢3.子进程p2通过管道读取消息,如果消息是“ok”,则打开文件,读取文件内容,并将其输出到屏幕上,关闭文件.

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<stdlib.h>
#include<sys/wait.h>
int pid1,pid2; int main()
{
int fd[];
char outpipe[],inpipe[];
while((pid1 = fork()) == -);
if(pid1 == )
{
lockf(fd[], , );
sprintf(outpipe,"\n child process 1 is sending message!\n");
write(fd[], outpipe, );
sleep();
lockf(fd[], , );
exit();
}
else
{
while((pid2 = fork()) == -);
if(pid2 == )
{
lockf(fd[], , );
sprintf(outpipe,"\n child process 2 is sending message !\n");
write(fd[], outpipe, );
sleep();
lockf(fd[], , );
exit();
}
else
{
wait();
read(fd[], inpipe, );
printf("%s\n",inpipe);
wait();
read(fd[], inpipe, );
printf("%s\n",inpipe);
exit();
}
}
}

- FIFO

FIFO与管道类似,它们最大的差别是,FIFO在文件系统中拥有一个名称,并且其打开方式与打开一个普通文件是一样的,这样就能够将FIFO用于非相关进程之间的通信。

#include<sys/types.h>
.#include<sys/stat.h>
.#include<errno.h>
.#include<fcntl.h>
.#include<stdio.h>
.#include<stdlib.h>
.#include<string.h>
.#define FIFO_SERVER "./myfifo"
.main(int argc,char** argv)
.{
. int fd;
. char w_buf[];
. int nwrite;
. if(fd==-)
. if(errno==ENXIO)
. printf("open error;no reading process\n");
. fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,);
. if(argc==)
. printf("Please send something\n");
. strcpy(w_buf,argv[]);
. if((nwrite=write(fd,w_buf,))==-)
. {
. if(errno==EAGAIN)
. printf("The FIFO has not been read yet. Please try later\n");
. }
. else
. printf("write %s to the FIFO\n",w_buf);
.}

- 信号

信号实际上是软中断,既然是中断那么信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。 信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。

#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
void new_op(int,siginfo_t*,void*);
int main(int argc,char**argv)
{
struct sigaction act;
union sigval mysigval;
int i;
int sig;
pid_t pid;
char data[];
mset(data,,sizeof(data));
for(i=; i < ; i++)
data[i]='';
mysigval.sival_ptr=data;
sig=atoi(argv[]);
p
sid=getpid();
sigemptyset(&act.sa_mask);
act.sa_sigaction=new_op;//三参数信号处理函数
act.sa_flags=SA_SIGINFO;//信息传递开关
if(sigaction(sig,&act,NULL) < )
{
printf("install sigal error\n");
}
while()
{
sleep();
printf("wait for the signal\n");
sigqueue(pid,sig,mysigval);//向本进程发送信号,并传递附加信息
}
}
void new_op(int signum,siginfo_t *info,void *myact)//三参数信号处理函数的实现
{
int i;
for(i=; i<; i++)
{
printf("%c\n ",(*( (char*)((*info).si_ptr)+i))); }
printf("handle signal %d over;",signum);
}

- 消息队列

“消息”是在两台计算机间传送的数据单位。消息可以非常简单,例如只包含文本字符串;也可以更复杂,可能包含嵌入对象。

消息被发送到队列中“消息队列”是在消息的传输过程中保存消息的容器。消息队列管理器在将消息从它的源中继到它的目标时充当中间人。队列的主要目的是提供路由并保证消息的传递;如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传递它。

“消息队列”是 Microsoft 的消息处理技术,它在任何安装了 Microsoft Windows 的计算机组合中,为任何应用程序提供消息处理和消息队列功能,无论这些计算机是否在同一个网络上或者是否同时联机。

消息队列网络”是能够相互间来回发送消息的任何一组计算机网络中的不同计算机在确保消息顺利处理的过程中扮演不同的角色。它们中有些提供路由信息以确定如何发送消息,有些保存整个网络的重要信息,而有些只是发送和接收消息。

“消息队列”安装期间,管理员确定哪些服务器可以互相通信,并设置特定服务器的特殊角色。构成此“消息队列”网络的计算机称为“站点”,它们之间通过“站点链接”相互连接。每个站点链接都有一个关联的“开销”,它由管理员确定,指示了经过此站点链接传递消息的频率。

“消息队列”管理员还在网络中设置一台或多台作为“路由服务器”的计算机。路由服务器查看各站点链接的开销,确定经过多个站点传递消息的最快和最有效的方法,以此决定如何传递消息。

#include  < stdio.h >
#include < stdlib.h >
#include < ctype.h >
#include < sys / ipc.h >
#include < sys / types.h >
#include < sys / msg.h > #define MAX_SEND_SIZE 80 struct mymsgbuf
{
long mtype;
char mtext[MAX_SEND_SIZE];
} ;
void send_message( int qid, struct mymsgbuf * qbuf, long type, char * text);
void read_message( int qid, struct mymsgbuf * qbuf, long type);
void remove_queue( int qid);
void change_queue_mode( int qid, char * mode);
void usage( void ); int main( int argc, char * argv[])
{
key_t key;
int msgqueue_id;
struct mymsgbuf qbuf; if ( == argc)
usage();
key = ftok( " . " , ' m ' );
if ((msgqueue_id = msgget(key,IPC_CREAT | )) ==- )
{
perror( " msgget " );
exit( );
}
switch (tolower(argv[ ][ ]))
{
case ' s ' :
send_message(msgqueue_id,( struct mymsgbuf * ) & qbuf,
atol(argv[ ]),argv[ ]);
break ;
case ' r ' :
read_message(msgqueue_id, & qbuf,atol(argv[ ]));
break ;
case ' d ' :
remove_queue(msgqueue_id);
break ;
case ' m ' :
change_queue_mode(msgqueue_id,argv[ ]);
break ;
default :
usage();
}
return ;
}
void send_message( int qid, struct mymsgbuf * qbuf, long type, char * text)
{
printf( " send a message /n " );
qbuf -> mtype = type;
strcpy(qbuf -> mtext,text);
if ((msgsnd(qid,( struct msgbuf * )qbuf,strlen(qbuf -> mtext) + , )) ==- )
{
perror( " msgsnd " );
exit( );
}
}
void read_message( int qid, struct mymsgbuf * qbuf, long type)
{
printf( " reading a message./n " );
qbuf -> mtype = type;
msgrcv(qid,( struct msgbuf * )qbuf,MAX_SEND_SIZE,type, );
printf( " Type: %1d Text: %s/n " ,qbuf -> mtype,qbuf -> mtext);
}
void remove_queue( int qid)
{
msgctl(qid,IPC_RMID, );
}
void change_queue_mode( int qid, char * mode)
{
struct msqid_ds myqueue_ds;
msgctl(qid,IPC_STAT, & myqueue_ds);
sscanf(mode, " %ho " , & myqueue_ds.msg_perm.mode);
msgctl(qid,IPC_SET, & myqueue_ds);
}
void usage( void )
{
fprintf(stderr, " msgtool -A utility for tinkering with msg queue/n " );
fprintf(stderr, " /nUSAGE:msgtool (s)end <type> <messagetext>/n " );
fprintf(stderr, " (r)ecv<type>/n " );
fprintf(stderr, " (d)elete/n " );
fprintf(stderr, " (m)ode<octal mode>/n " );
exit( );
}
05-13 12:35