本文主要是介绍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);
功能描述
1 struct sembuf 2 { 3 unsigned short sem_num; /* semaphore number */ 4 short sem_op; /* semaphore operation */ 5 short sem_flg; /* operation flags */ 6 };
这三个字段的意义分别为:
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)
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(进程间通信)模型实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!