clients(PV操作共享内核内存进行输入输出分屏) - server(进程间通信)模型实现

本文主要是介绍clients(PV操作共享内核内存进行输入输出分屏) - server(进程间通信)模型实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://blog.csdn.net/u011239443/article/details/51655335

1、拓扑结构

 

 

 

2、PV操作共享内核内存进行输入输出分屏

(1)

1 int semop(int semid,struct sembuf *sops,size_t nsops);

功能描述

操作一个或一组信号。
semid:
信号集的识别码,可通过semget获取。
sops:
指向存储信号操作结构的数组指针,信号操作结构的原型如下
1 struct sembuf
2 {
3 unsigned short sem_num; /* semaphore number */
4 short sem_op; /* semaphore operation */
5 short sem_flg; /* operation flags */
6 };

这三个字段的意义分别为:

sem_num:
操作信号在信号集中的编号,第一个信号的编号是0。
sem_op:
如果其值为正数,该值会加到现有的信号内含值中。通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。通常用于获取资源的使用权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。
sem_flg:
信号操作标志,可能的选择有两种
IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误提示。
SEM_UNDO //程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。
nsops:信号操作结构的数量,恒大于或等于1。

 

 1 void P(int semid) 
 2 {
 3     struct sembuf my_buf ;
 4     memset(&my_buf, 0, sizeof(my_buf) );
 5     my_buf.sem_num = 0 ;
 6     my_buf.sem_op = -1 ;
 7     my_buf.sem_flg = SEM_UNDO ;
 8     semop(semid, &my_buf, 1);
 9 }
10 void V(int semid)
11 {
12     struct sembuf my_buf ;
13     memset(&my_buf, 0, sizeof(my_buf) );
14     my_buf.sem_num = 0 ;
15     my_buf.sem_op = 1 ;
16     my_buf.sem_flg = SEM_UNDO ;
17     semop(semid, &my_buf, 1);
18     
19 }

 

 (2)

shmget(得到一个共享内存标识符或创建一个共享内存对象)
所需头文件
#include <sys/ipc.h>
#include <sys/shm.h>
函数说明
得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符
函数原型
int shmget(key_t key, size_t size, int shmflg)
函数传入值
key
0(IPC_PRIVATE):会建立新共享内存对象
大于0的32位整数:视参数shmflg来确定操作。通常要求此值来源于ftok返回的IPC键值
size
大于0的整数:新建的共享内存大小,以字节为单位
0:只获取共享内存时指定为0
shmflg
0:取共享内存标识符,若不存在则函数会报错
IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符
IPC_CREAT|IPC_EXCL:如果内核中不存在键值 与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错
函数返回值
成功:返回共享内存的标识符
出错:-1,错误原因存于error中

 

(3)

int semget(key_t key, int nsems, int semflg);
key
所创建或打开信号量集的键值。
nsems:
创建的信号量集中的信号量的个数,该参数只在创建信号量集时有效。
semflg:
调用函数的操作类型,也可用于设置信号量集的访问权限,两者通过or表示

 

1     shm_key = (key_t)atoi(argv[1]);
2     sem_key = (key_t)atoi(argv[2]);
3 
4     my_shm = shmget(shm_key, sizeof(MBUF), 0666|IPC_CREAT);
5 
6     my_sem = semget(sem_key, 1, 0666 | IPC_CREAT);

 

 

(4)

int semctl(int semid,int semnum,int cmd, /*union semun arg*/);

SETVAL设置信号量集中的一个单独的信号量的值。

1 semctl(my_sem, 0, SETVAL, 1);

 

 

 

(5)

shmat(把共享内存区对象映射到调用进程的地址空间)
所需头文件
#include <sys/types.h>
#include <sys/shm.h>
函数说明
连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问
函数原型
void *shmat(int shmid, const void *shmaddr, int shmflg)
函数传入值
shmid
共享内存标识符
shmaddr
指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置
shmflg
SHM_RDONLY:为只读模式,其他为读写模式
函数返回值
成功:附加好的共享内存地址
出错:-1,错误原因存于error中

 

1 p = (pMBUF)shmat(my_shm, NULL, 0);

 

 

 

(6)

client_in PV操作:

1 while( P(my_sem), p -> m_flag == 1)
2         {
3             V(my_sem);
4             sleep(1);
5         }
6         strcpy(p ->m_buf, line);
7         p ->m_flag = 1 ;
8         V(my_sem);

 

 

 (7)

shmdt(断开共享内存连接)
所需头文件
#include <sys/types.h>
#include <sys/shm.h>
函数说明
与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存
函数原型
int shmdt(const void *shmaddr)
函数传入值
shmaddr:连接的共享内存的起始地址
函数返回值
成功:0
出错:-1,错误原因存于error中

 

 

1 shmdt(p);

 

 

(8)

删除内存 删除 信号量

 

shmctl(共享内存管理)
所需头文件
#include <sys/types.h>
#include <sys/shm.h>
函数说明
完成对共享内存的控制
函数原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
函数传入值
shmid
共享内存标识符
cmd
IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中
IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内
IPC_RMID:删除这片共享内存
buf
共享内存管理结构体。具体说明参见共享内存内核结构定义部分
函数返回值
成功:0
出错:-1,错误原因存于error中

 

 

 

1 shmctl(my_shm, IPC_RMID, NULL) ;
2 semctl(my_sem, 0, IPC_RMID);//0为信号量编号

 

 

 

3、clients - server 通信

(1)上下线信息管道

server:

 1 char file_name[128]  = "";
 2     char client_r[128], client_w[128];
 3     char line[32] ;
 4     int fd_read ;
 5     int client_id ;
 6     int fd_cr , fd_cw ;
 7     FILE* fp ;
 8     sprintf(file_name, "%s/%s", PATH, NAME);
 9     mkfifo(file_name, 0666) ;
10     fd_read = open(file_name, O_RDONLY);
11     open(file_name, O_WRONLY);
12     
13     fp = fdopen(fd_read, "r");

client_in:

1 char server_name[128]= "" ;
2     char read_file[128], write_file[128] ;
3     char msg[32] ="" ;
4     int fd_r, fd_w ;
5     sprintf(server_name, "%s/%s", PATH, SERVER);
6     int fd_server = open(server_name, O_WRONLY);
7     sprintf(msg, "%d\n", getpid());
8     write(fd_server, msg, strlen(msg));

 

(2) 读写管道

client_in:

 1 memset(read_file, 0, 128);
 2     memset(write_file, 0, 128);
 3 
 4     sprintf(read_file, "%s/%d_r.fifo", PATH, getpid());
 5     sprintf(write_file, "%s/%d_w.fifo", PATH, getpid());
 6 
 7     mkfifo(read_file, 0666);
 8     mkfifo(write_file, 0666);
 9 
10     fd_r = open(read_file, O_RDONLY);
11     fd_w = open(write_file, O_WRONLY);

 

server:

while(memset(line, 0 , 32), fgets(line, 32, fp) != NULL)// "pid\n"{// cr  cw pid_r.fifo  pid_w.fifosscanf(line, "%d", &client_id);printf("client: %d request !\n", client_id) ;memset(client_r, 0, 128);memset(client_w, 0, 128);sprintf(client_r, "%s/%d_r.fifo", PATH, client_id);sprintf(client_w, "%s/%d_w.fifo", PATH, client_id);fd_cw = open(client_r, O_WRONLY);fd_cr = open(client_w, O_RDONLY);/******************/close(fd_cr);close(fd_cw);}

 

 

(3)信息传递

client_in:

 1 while(memset(line, 0, 1024), fgets(line, 1024, stdin) != NULL)
 2 {
 3 write(fd_w, line, strlen(line));
 4 
 5 memset(line, 0, 1024);
 6 
 7 read(fd_r, line, 1024);
 8 /**
 9 ************
10 */
11 
12 }

 

server:

1 write(fd_wr, buf, strlen(buf));

 

 

4、server fork 子进程对客户端传来的信息进行处理

(1)fork

1 if(fork() == 0)
2         {
3             child_main(fd_cr, fd_cw);
4             close(fd_cr);
5             close(fd_cw);
6             exit(1);
7         }

 

 (2)reserve 函数

 1 void reverse(char* str)
 2 {
 3     int bg, end ;
 4     char tmp ;
 5     bg = 0 ;
 6     end = strlen(str) - 1 ;
 7     while(bg < end)
 8     {
 9         tmp = str[bg] ;
10         str[bg] = str[end] ;
11         str[end] = tmp ;
12         bg ++ ;
13         end -- ;
14     }
15 
16 }

 

 (3) child_main  read and write

 1 void child_main(int fd_rd, int fd_wr)
 2 {
 3     char buf[1024] ;
 4     while(memset(buf, 0, 1024), read(fd_rd, buf, 1024) != 0)
 5     {
 6             reverse(buf);
 7             write(fd_wr, buf, strlen(buf));
 8     }
 9 
10 }

 

 (4)防止僵尸进程

  如果子进程先退出,系统不会自动清理掉子进程的环境,而必须由父进程调用wait或waitpid函数来完成清理工作,如果父进程不做清理工作,则已经退出的子进程将成为僵尸进程(defunct)。

 

 

1 signal(17, child_handle);

 

下次收到17号信号(子进程退出信号) 就 调用 child_handle 函数

 

1 void child_handle(int sig_num)
2 {
3     printf("a child exit!\n");
4     wait(NULL);
5 }

 

 

5、详细代码:

server:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #include<unistd.h>
 5 #include<sys/stat.h>
 6 #include<sys/types.h>
 7 #include<fcntl.h>
 8 #include<signal.h>
 9 #define PATH "/home/comst/pipe"
10 #define NAME "server.fifo"
11 
12 void child_handle(int sig_num)
13 {
14     printf("a child exit!\n");
15     wait(NULL);
16 }
17 void reverse(char* str)
18 {
19     int bg, end ;
20     char tmp ;
21     bg = 0 ;
22     end = strlen(str) - 1 ;
23     while(bg < end)
24     {
25         tmp = str[bg] ;
26         str[bg] = str[end] ;
27         str[end] = tmp ;
28         bg ++ ;
29         end -- ;
30     }
31 
32 }
33 void child_main(int fd_rd, int fd_wr)
34 {
35     char buf[1024] ;
36     while(memset(buf, 0, 1024), read(fd_rd, buf, 1024) != 0)
37     {
38             reverse(buf);
39             write(fd_wr, buf, strlen(buf));
40     }
41 
42 }
43 int main(int argc, char* argv[])
44 {
45     signal(17, child_handle);
46     char file_name[128]  = "";
47     char client_r[128], client_w[128];
48     char line[32] ;
49     int fd_read ;
50     int client_id ;
51     int fd_cr , fd_cw ;
52     FILE* fp ;
53     sprintf(file_name, "%s/%s", PATH, NAME);
54     mkfifo(file_name, 0666) ;
55     fd_read = open(file_name, O_RDONLY);
56     open(file_name, O_WRONLY);
57     
58     fp = fdopen(fd_read, "r");
59 
60     while(memset(line, 0 , 32), fgets(line, 32, fp) != NULL)// "pid\n"
61     {// cr  cw pid_r.fifo  pid_w.fifo
62         sscanf(line, "%d", &client_id);
63         printf("client: %d request !\n", client_id) ;
64         memset(client_r, 0, 128);
65         memset(client_w, 0, 128);
66 
67         sprintf(client_r, "%s/%d_r.fifo", PATH, client_id);
68 
69         sprintf(client_w, "%s/%d_w.fifo", PATH, client_id);
70 
71         fd_cw = open(client_r, O_WRONLY);
72         fd_cr = open(client_w, O_RDONLY);
73         if(fork() == 0)
74         {
75             child_main(fd_cr, fd_cw);
76             close(fd_cr);
77             close(fd_cw);
78             exit(1);
79         }
80         close(fd_cr);
81         close(fd_cw);
82     }
83 
84 
85 
86     
87     memset(file_name, 0, 128);
88     sprintf(file_name, "%s/%s", PATH, NAME);
89     unlink(file_name);
90     return 0 ;
91 }

 

 

 

 

client.h:

 1 #ifndef __CLINET_H__
 2 #define __CLINET_H__
 3 
 4 #include<stdio.h>
 5 #include<stdlib.h>
 6 #include<string.h>
 7 #include<unistd.h>
 8 #include<sys/types.h>
 9 #include<sys/ipc.h>
10 #include<sys/shm.h>
11 #include<sys/sem.h>
12 typedef struct tag
13 {
14     int m_flag ;
15     char m_buf[1024] ;
16 }MBUF, *pMBUF;
17 void P(int semid) ;
18 void V(int semid);
19 #endif

 

 

 

 

 

 

 

client_in:

 1 #include "client.h"
 2 #include<sys/stat.h>
 3 #include<sys/types.h>
 4 #include<sys/fcntl.h>
 5 #define PATH "/home/comst/pipe"
 6 #define SERVER "server.fifo"
 7 int main(int argc, char* argv[])//shm_key sem_key
 8 {
 9 
10     char server_name[128]= "" ;
11     char read_file[128], write_file[128] ;
12     char msg[32] ="" ;
13     int fd_r, fd_w ;
14     sprintf(server_name, "%s/%s", PATH, SERVER);
15     int fd_server = open(server_name, O_WRONLY);
16     sprintf(msg, "%d\n", getpid());
17     write(fd_server, msg, strlen(msg));
18 
19     memset(read_file, 0, 128);
20     memset(write_file, 0, 128);
21 
22     sprintf(read_file, "%s/%d_r.fifo", PATH, getpid());
23     sprintf(write_file, "%s/%d_w.fifo", PATH, getpid());
24 
25     mkfifo(read_file, 0666);
26     mkfifo(write_file, 0666);
27 
28     
29 
30 
31     fd_r = open(read_file, O_RDONLY);
32     fd_w = open(write_file, O_WRONLY);
33 
34 
35     key_t shm_key, sem_key ;
36     int my_shm, my_sem ;
37 
38     char line[1024] ;
39 
40     pMBUF p ;
41     shm_key = (key_t)atoi(argv[1]);
42     sem_key = (key_t)atoi(argv[2]);
43 
44     my_shm = shmget(shm_key, sizeof(MBUF), 0666|IPC_CREAT);
45 
46     my_sem = semget(sem_key, 1, 0666 | IPC_CREAT);
47     semctl(my_sem, 0, SETVAL, 1);
48 
49 
50     p = (pMBUF)shmat(my_shm, NULL, 0);
51     memset(p, 0, sizeof(MBUF));
52 
53     while(memset(line, 0, 1024), fgets(line, 1024, stdin) != NULL)
54     {
55         write(fd_w, line, strlen(line));
56 
57         memset(line, 0, 1024);
58 
59         read(fd_r, line, 1024);
60         while( P(my_sem), p -> m_flag == 1)
61         {
62             V(my_sem);
63             sleep(1);
64         }
65         strcpy(p ->m_buf, line);
66         p ->m_flag = 1 ;
67         V(my_sem);
68 
69     }
70 
71     while( P(my_sem), p -> m_flag == 1)
72     {
73         V(my_sem);
74         sleep(1);
75     }
76     strcpy(p ->m_buf, "over");
77     p ->m_flag = 1 ;
78     V(my_sem);
79 
80     sleep(3);
81 
82 
83 
84 
85     shmdt(p);
86     shmctl(my_shm, IPC_RMID, NULL) ;
87 
88     semctl(my_sem, 0, IPC_RMID);
89 
90 
91 
92 }

 

 

 

 

 

client_out:

 1 #include "client.h"
 2 int main(int argc, char* argv[])//shm_key sem_key
 3 {
 4     key_t shm_key, sem_key ;
 5     int my_shm, my_sem ;
 6 
 7     char line[1024] ;
 8 
 9     pMBUF p ;
10     shm_key = atoi(argv[1]);
11     sem_key = atoi(argv[2]);
12 
13     my_shm = shmget(shm_key, sizeof(MBUF), 0666);
14 
15     my_sem = semget(sem_key, 1, 0666 );
16     semctl(my_sem, 0, SETVAL, 1);
17 
18 
19     p = (pMBUF)shmat(my_shm, NULL, 0);
20     memset(p, 0, sizeof(MBUF));
21 
22     while(1)
23     {
24         while(P(my_sem), p -> m_flag == 0)
25         {
26             V(my_sem);
27             sleep(1);
28         }
29         printf("%d :  %s\n", getpid(), p -> m_buf);
30         if(strcmp(p ->m_buf, "over") == 0)
31         {
32 
33             V(my_sem);
34             break ;
35         }
36         p -> m_flag = 0 ;
37         V(my_sem);
38 
39     }
40 
41 
42 
43 
44 
45     shmdt(p);
46 
47 
48 
49 
50 }

 

 

 

 

 

 

P_V func

 1 #include "client.h"
 2 void P(int semid) 
 3 {
 4     struct sembuf my_buf ;
 5     memset(&my_buf, 0, sizeof(my_buf) );
 6     my_buf.sem_num = 0 ;
 7     my_buf.sem_op = -1 ;
 8     my_buf.sem_flg = SEM_UNDO ;
 9     semop(semid, &my_buf, 1);
10 }
11 void V(int semid)
12 {
13     struct sembuf my_buf ;
14     memset(&my_buf, 0, sizeof(my_buf) );
15     my_buf.sem_num = 0 ;
16     my_buf.sem_op = 1 ;
17     my_buf.sem_flg = SEM_UNDO ;
18     semop(semid, &my_buf, 1);
19     
20 }

 


这篇关于clients(PV操作共享内核内存进行输入输出分屏) - server(进程间通信)模型实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1023083

相关文章

Python 中的 with open文件操作的最佳实践

《Python中的withopen文件操作的最佳实践》在Python中,withopen()提供了一个简洁而安全的方式来处理文件操作,它不仅能确保文件在操作完成后自动关闭,还能处理文件操作中的异... 目录什么是 with open()?为什么使用 with open()?使用 with open() 进行

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

OpenCV图像形态学的实现

《OpenCV图像形态学的实现》本文主要介绍了OpenCV图像形态学的实现,包括腐蚀、膨胀、开运算、闭运算、梯度运算、顶帽运算和黑帽运算,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起... 目录一、图像形态学简介二、腐蚀(Erosion)1. 原理2. OpenCV 实现三、膨胀China编程(

通过Spring层面进行事务回滚的实现

《通过Spring层面进行事务回滚的实现》本文主要介绍了通过Spring层面进行事务回滚的实现,包括声明式事务和编程式事务,具有一定的参考价值,感兴趣的可以了解一下... 目录声明式事务回滚:1. 基础注解配置2. 指定回滚异常类型3. ​不回滚特殊场景编程式事务回滚:1. ​使用 TransactionT

Android实现打开本地pdf文件的两种方式

《Android实现打开本地pdf文件的两种方式》在现代应用中,PDF格式因其跨平台、稳定性好、展示内容一致等特点,在Android平台上,如何高效地打开本地PDF文件,不仅关系到用户体验,也直接影响... 目录一、项目概述二、相关知识2.1 PDF文件基本概述2.2 android 文件访问与存储权限2.

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Spring Shell 命令行实现交互式Shell应用开发

《SpringShell命令行实现交互式Shell应用开发》本文主要介绍了SpringShell命令行实现交互式Shell应用开发,能够帮助开发者快速构建功能丰富的命令行应用程序,具有一定的参考价... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定义S

SpringBatch数据写入实现

《SpringBatch数据写入实现》SpringBatch通过ItemWriter接口及其丰富的实现,提供了强大的数据写入能力,本文主要介绍了SpringBatch数据写入实现,具有一定的参考价值,... 目录python引言一、ItemWriter核心概念二、数据库写入实现三、文件写入实现四、多目标写入

Android Studio 配置国内镜像源的实现步骤

《AndroidStudio配置国内镜像源的实现步骤》本文主要介绍了AndroidStudio配置国内镜像源的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、修改 hosts,解决 SDK 下载失败的问题二、修改 gradle 地址,解决 gradle

SpringSecurity JWT基于令牌的无状态认证实现

《SpringSecurityJWT基于令牌的无状态认证实现》SpringSecurity中实现基于JWT的无状态认证是一种常见的做法,本文就来介绍一下SpringSecurityJWT基于令牌的无... 目录引言一、JWT基本原理与结构二、Spring Security JWT依赖配置三、JWT令牌生成与