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实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依