2024年2月7日发(作者:)
实验报告
学号 姓名 成绩 __________
实验二进程通信
【实验目的和要求】
1、了解进程通信的概念及方法;
2、了解信号量、管道;
3、掌握信号量、管道和命名管道编程方法。
【实验内容】
1、利用命名管道实现单机QQ聊天;
2、撰写实验报告;
【实验原理】
1、信号量(semaphore)是为那些访问相同资源的进程以及同一进程不同线程之 间提供的一个同步机制。它不是用于传输数据,而只是简单地协调对共享资源的 访问。信号量包含一个计数器,表示某个资源正在被访问和访问的次数,用来控 制多进程对共享数据的访问。一旦成功拥有了一个信号量,对它所能做的操作只 有两种:请求和释放。当执行释放操作时,系统将该信号值减1(如果小于零, 则设置为零);当执行请求操作时,系统将该信号值加1,如果加1后的值大于 设定的最大值,那么系统将会挂起处理进程,直到信号值小于最大值为止。Tuxedo
用信号量来确保在某一时刻只有一个进程对某一块共享内存进程访问。信号量配 置太低会导致Tuxedo系统应用程序无法启动。
2、管道分为两种:管道和命名管道。
管道是UNIX系统IPC的最古老形式,并且所有的UNIX系统都提供这种通 信机制。可以在有亲缘关系(父子进程或者是兄弟进程之间)进行通信,管道的 数据只能单向流动,如果想双向流动,必须创建两个管道。
管道应用的一个重大缺陷就是没有名字,因此只能用于亲缘进程之间的通信。
后来以管道为基础提出命名管道(namedpipe,FIFO)的概念,该限制得到了克 服。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式 存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只 要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以 及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得 注意的是,FIFO
严格遵循先进先出(first in first out)规则,对管道及FIFO的读 总是从开始处返回数据,对它们的写则是把数据添加到末尾。它们不支持诸如
lseek()等文件定位操作。
【程序代码】
1、lucy.c
#include
#include
#include
#include
#include
#include
#include
#include
char write_fifo_name[]="ltop_fifo";
char read_fifo_name[]="ptol_fifo";
char writer[]="Lucy";
char reader[]="Peter";
int main(int argc,char *argv[])
(
int write_fd,read_fd;
mkfifo(write_fifo_name,S_IRUSR|S_IWUSR);
mkfifo(read_fifo_name,S_IRUSR|S_IWUSR);
printf("hello,I am lucy!n");
write_fd=open(write_fifo_name,O_WRONLY);
if(write_fd<0)
(
perror("open_w");
exit(-1);
)
read_fd=open(read_fifo_name,O_RDONLY);
if(read_fd<0)
perror("open_r");
exit(-1);
)
pid_t pid;
pid=fork();
if(pid==0)
(
while(1)
(
char bufw[256]="";
printf("%s:",writer);
if(fgets(bufw,256,stdin)==NULL)
exit(1);
bufw[strlen(bufw)-1]='0';
write(write_fd,bufw,strlen(bufw)); if(strncmp(bufw,"bye",3)==0) (
close(write_fd);
unlink(write_fifo_name); exit(1);
)
)
)
else
(
while(1)
(
char bufr[256]="";
read(read_fd,bufr,256);
printf("r%s:%sn",reader,bufr);
if(strncmp(bufr,"bye",3)==0)
(
write(write_fd,"bye”,4);
close(read_fd);
unlink(read_fifo_name); exit(1);
)
printf("%s:",writer);
fflush(stdout);
)
)
return 0;
)
2、peter.c
#include
#include
#include
#include
#include
#include
#include
#include
char write_fifo_name[]="ptol_fifo";
char read_fifo_name[]="ltop_fifo";
char writer[]="Peter";
char reader[]="Lucy";
int main(int argc,char *argv[])
int write_fd,read_fd;
mkfifo(write_fifo_name,S_IRUSR|S_IWUSR);
mkfifo(read_fifo_name,S_IRUSR|S_IWUSR);
printf("hello,I am peter!n");
read_fd=open(read_fifo_name,O_RDONLY);
if(read_fd<0)
(
perror("open_r");
exit(-1);
)
write_fd=open(write_fifo_name,O_WRONLY); if(write_fd<0)
(
perror("open_w");
exit(-1);
)
pid_t pid;
pid=fork();
if(pid==0)
(
while(1)
(
char bufw[256]="";
printf("%s:",writer);
if(fgets(bufw,256,stdin)==NULL)
exit(1);
bufw[strlen(bufw)-1]='0';
write(write_fd,bufw,strlen(bufw)); if(strncmp(bufw,"bye",3)==0)
close(write_fd);
unlink(write_fifo_name);
exit(1);
) else ( while(1) (
char bufr[256]=";
read(read_fd,bufr,256);
printf("r%s:%sn",reader,bufr);
if(strncmp(bufr,"bye",3)==0)
(
write(write_fd,"bye”,4);
close(read_fd);
unlink(read_fifo_name);
exit(1);
)
printf("%s:",writer);
fflush(stdout);
)
)
return 0;
)
n【实验步骤】
1、程序lucy.c创建了
FIFO write_fifo用于向程序peter.c发送消息;peter.c程序 创建了
FIFO read_fifo用于向lucy.c发送消息;同时,lucy.c能够通过打开
peter.c创建的FIFO来得到的peter.c发来的消息,peter.c能够通过打开lucy.c
创建的FIFO来得到lucy.c发来的消息。因此两者就能互相通信了,两者必须 在线才能进行通信聊天,这个与qq的聊天功能有些类似。
2、将lucy.c和peter.c的代码编写完后,在一个终端调试即gcc lucy.c -o lucy无 错误后运行./lucy;在另外一个新终端上调试即gcc peter.c -o peter无错误后 运行./peter;开始进行聊天,若想结束聊天,则在一个终端上输入bye,俩个 终端就会同时关闭。
【实验结果】
【实验体会】
传统的进程间通信方式:无名管道pipe、有名管道fifo和信号signal管道的编程
o
1、无名管道
创建一个简单的管道,可以使用系统调用pipe()。它接受一个参数,也就是一个
包括两个整数的数组。如果系统调用成功,此数组将包括管道使用的两个文件描
述符。创建一个管道之后,一般情况下进程将产生一个新的进程。
系统调用:pipe();
注意:fd[0]用于读取管道,fd[1]用于写入管道。该函数创建的管道的两端处于一 个进程中间,在实际应用中没有太大意义,因此,一个进程在由pipe()创建管道 后,一般再fork
一个子进程,然后通过管道实现父子进程间的通信(因此也不难 推出,只要两个进程中存在亲缘关系,这里的亲缘关系指的是具有共同的祖先, 都可以采用管道方式来进行通信)。一般文件的I/O函数都可以用于管道,如close、
read、write
等等。
2、有名管道
创建有名管道用mkfifo()。
创建有名管道用mkfifo()。
头文件
#include
#include
函数原型
int mkfifo(const char * pathname, mode_t mode)
函数传入值
Pathname:要创建的的管道
Mode:设置管道权限
函数返回值
若成功则为0,若出错返回-1
FIFO相关出错信息:
EACCES
(无存取权限)
EEXIST
(指定文件不存在)
ENAMETOOLONG
(路径名太长)
ENOENT
(包含的目录不存在)
ENOSPC
(文件系统余空间不足)
ENOTDIR
(文件路径无效)
EROFS
(指定的文件存在于只读文件系统中)
3、信号发送和捕捉
信号发送:kill()和raise()
kill()函数同读者熟知的kill系统命令一样,可以发送信号给进程或进程组,它
不仅可以中止进程(实际上发出SIGKILL信号),也可以向进程发送其他信号。
kill()函数语法:
头文件
#include
#include
函数原型
int kill(pid_t pid,int sig)
函数传入值
Pid:
正数:要发送信号的进程号
0:信号被发送到所有的当前进程在同一进程组的进程
-1:信号发给所有的进程表中的进程
<-1:信号发给进程组号为-pid的每一个进程
Sig:信号
函数返回值
若成功则为0,若出错返回-1。
4、fflush(stdout)目的是清空缓冲,强制结果马上显示到屏幕上。
本文发布于:2024-02-07 11:51:21,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170727788164710.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |