linux系统编程-进程间通信练手

write
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*************************************************************************
> File Name: write.c
> Author: Hengliy
> Mail hengliy_li@163.com
> Created Time: Fri 23 Jan 2018 06:01:46 AM EST
************************************************************************/

#include<stdio.h>
#include<sys/mman.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<string.h>

struct STU{
int id;
char* name;
char sex;
};

int main(int argc,char* argv[])
{
int fd;
struct STU student={10,"hengliy",'m'};
char *mm;
if(argc<2){
printf("argc<2");
exit(-1);
}

fd=open(argv[1],O_RDWR|O_CREAT,0664);
ftruncate(fd,sizeof(student));

mm=mmap(NULL,sizeof(student),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(mm==MAP_FAILED)
{
perror("error");
exit(-1);
}

close(fd);
//循环修改映射文件
while(1){
//映射到文件就可以直接用memcpy搬运内存啦!
memcpy(mm,&student,sizeof(student));
student.id++;
sleep(1);
}
munmap(mm,sizeof(student));

return 0;
}

read

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*************************************************************************
> File Name: write.c
> Author: Hengliy
> Mail hengliy_li@163.com
> Created Time: Wed 21 Jan 2018 10:03:30 PM EST
************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/mman.h>
struct STU{
int id;
char name[20];
char sex;
};

void sys_err(char* str)
{
perror(str);
exit(-1);
}

int main(int argc,char* argv[])
{
int fd;
struct STU student;
struct STU* mm;

if(argc<2){
printf("argc<2");
exit(-1);
}
fd=open(argv[1],O_RDONLY);
if(fd==-1)
sys_err("open error");
//进行地址空间映射到fd
mm=mmap(NULL,sizeof(student),PROT_READ,MAP_SHARED,fd,0);
if(mm==MAP_FAILED)
sys_err("map error");

close(fd);

while(1)
{
printf("id=%d name=%s sex=%c\n",mm->id,mm->name,mm->sex);
sleep(2);
}
//别忘了取消映射
munmap(mm,sizeof(student));

return 0;
}

多进程拷贝大文件

实现拷贝一个超大文件,为提高效率,可以采用多进程并行拷贝的方法实现;假设有n个进程进行拷贝,每个进程拷贝len/n个字节,最后一个进程拷贝剩下的len%(len/n)个字节。
为了降低复杂度,可以用mmap来进行拷贝,通过指针操作内存地址,设置内个进程拷贝的起始,结束位置,使用MAP_SHARED选项将内存中所做的修改反映到物理磁盘上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*************************************************************************
> File Name: ncopy.c
> Author: Hengliy
> Mail hengliy_li@163.com
> Created Time: Fri 23 Jan 2018 07:45:15 AM EST
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

int main (int argc,char* argv[])
{
int src_fd,dst_fd;
int per_length=4096,last_length,n,i,lseek=0,file_length=0;
struct stat file_stat;
char* src_p,*dst_p;
pid_t pid;
if(argc<3){
perror("open src error");
exit(1);
}
//打开源文件
if((src_fd=open(argv[1],O_RDWR))==-1)
{
perror("open srcFile error");
exit(-1);
}
//用户具有读写权限,组用户和其他用户只有读权限
if((dst_fd=open(argv[2],O_CREAT|O_RDWR|O_TRUNC,0644))==-1)
{
perror("open dstFile error");
exit(-1);
}

if((stat(argv[1],&file_stat))==-1)
{
perror("get stat error");
exit(1);
}
file_length=file_stat.st_size;
n=file_length/per_length;
last_length=file_length%per_length;

#ifdef DEBUG
printf("file_length=%d per_length=%d last_length=%d n=%d\n",file_length,per_length,last_length,n);
#endif

if((ftruncate(dst_fd,file_length)==-1))
{
perror("ftruncate error");
exit(1);
}
for(i=0;i<n;i++)
{
pid=fork();
if(pid==0)//子进程
{
printf("i'm %dth process,parent_pid=%u,lseek=%d\n",i,getppid(),lseek);
break;
}
else if(pid>0)//如果是父进程
{
sleep(1);
lseek+=per_length;
}else{
perror("open error");
exit(1);
}
}

#ifdef DEBUG
printf("ready to copy %dth mmap\n",i);
#endif

if(i < n+1)
{
if(lseek+per_length < file_length)//复制分割好的部分
{
src_p = mmap(NULL, per_length, PROT_READ|PROT_WRITE, MAP_SHARED, src_fd, lseek);
if(src_p == MAP_FAILED){
perror("src mmap error");
exit(1);
}
dst_p = mmap(NULL, per_length, PROT_READ|PROT_WRITE, MAP_SHARED, dst_fd, lseek);
if(dst_p == MAP_FAILED){
perror("dst mmap error");
exit(1);
}
memcpy(dst_p, src_p, per_length);
munmap(src_p, per_length);
munmap(dst_p, per_length);
}
else//剩余部分的复制
{
#ifdef DEBUG
printf("last_size is %d\n", last_length);
#endif
src_p = mmap(NULL, last_length, PROT_READ|PROT_WRITE, MAP_SHARED, src_fd, lseek);
if(src_p == MAP_FAILED){
perror("last_src mmap error");
exit(1);
}
dst_p = mmap(NULL, last_length, PROT_READ|PROT_WRITE, MAP_SHARED, dst_fd, lseek);
if(dst_p == MAP_FAILED){
perror("last_dst mmap error");
exit(1);
}
memcpy(dst_p, src_p, last_length);
munmap(src_p, last_length);
munmap(dst_p, last_length);
}
}

close(src_fd);
close(dst_fd);
return 0;
}

使用FIFO实现本地聊天室

1、服务器端要有一个公共的共享的管道,用来实现用户到服务器之间的通信,并创建一个链表,用于存储用户登录信息。
2、服务器端要跟每一个用户建立一个管道用于服务器与用户之间的通信,并且进行用户数据转发,当用户退出之后,这条管道自动删除。
3、数据包的格式,首先是协议号,源id,目标id,数据内容

服务端思路
1.先创建一个公共管道,接收客户端的消息
2.根据用户登陆后发出的第一个包来创建以用户名命名的管道文件
3.用一个链表来存储用户的登录列表,随时增添
4.根据用户发送数据包的id号来判定将要执行什么操作,1是登录,2是聊天,4.是退出登录
5.转发数据包,是直接发以目标用户名命名的管道文件,但首先要确认登录列表里面有没有目标用户。
6.随着用户发出退出登录的包,把用户的登陆信息,管道文件删掉

客户端思路
1.登陆的时候输入用户名
2.随着用户登录打开公共信道,向服务器发送登录消息,
3.一边接受服务器发来的消息,一遍等待用户输入信息
4.把用户的信息自动封装成数据包的格式发给服务器

头文件

defination.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*************************************************************************
> File Name: defination.h
> Author: Hengliy
> Mail hengliy_li@163.com
> Created Time: Fri 24 Jan 2018 09:50:10 AM EST
************************************************************************/
#ifndef _DEFINATION_H
#define _DEFINATION_H

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>

#define SERVER_FIFO_NAME "/var/tmp/fifoServer"
#define CLIENT_FIFO_NAME "/var/tmp/fifoClient%d"
#define BUFF_SIZE PIPE_BUF
#define MSG_LEN 64
#define CLIENT_FIFO_NAME_LEN 64

typedef struct fifo_msg{
pid_t client_pid;
char msg[MSG_LEN];
}fifo_msg_t;

#endif

服务器

server.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/*************************************************************************
> File Name: server.c
> Author: Hengliy
> Mail hengliy_li@163.com
> Created Time: Fri 24 Jan 2018 09:42:35 AM EST
************************************************************************/
#include "defination.h"

int main(int argc, char *argv[])
{
int fifo_id = -1;
int server_fifo_fd = -1;

if (access(SERVER_FIFO_NAME, F_OK) < 0){
fifo_id = mkfifo(SERVER_FIFO_NAME, 0777);
if (fifo_id < 0){
perror("mkfifo error\n");
return -1;
}
}

server_fifo_fd = open(SERVER_FIFO_NAME, O_RDONLY);
if (server_fifo_fd < 0){
perror("open fifo error\n");
return -1;
}

fifo_msg_t client_msg;
memset(&client_msg, 0, sizeof(client_msg));
int read_bytes = 0;

do {
read_bytes = read(server_fifo_fd, &client_msg, sizeof(client_msg));
if (read_bytes < 0){
perror("read error\n");
close(server_fifo_fd);
return -1;
}

char *tmp_msg = client_msg.msg;
while (*tmp_msg){
*tmp_msg = toupper(*tmp_msg);
tmp_msg++;
}

char client_fifo[CLIENT_FIFO_NAME_LEN] = { 0 };
snprintf(client_fifo, CLIENT_FIFO_NAME_LEN - 1, CLIENT_FIFO_NAME, client_msg.client_pid);

int client_fifo_fd = open(client_fifo, O_WRONLY);
if (client_fifo_fd < 0){
perror("open client fifo error\n");
}

write(client_fifo_fd, &client_msg, sizeof(client_msg));
printf("write to client:%d\n", client_msg.client_pid);
close(client_fifo_fd);

} while (read_bytes > 0);

close(server_fifo_fd);
return 0;
}

客户端

client.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*************************************************************************
> File Name: server.c
> Author: Hengliy
> Mail hengliy_li@163.com
> Created Time: Fri 24 Jan 2018 16:20:39 AM EST
************************************************************************/
#include "defination.h"

int main(int argc, char *argv[])
{
pid_t client_pid = -1;
int server_fifo_fd = -1;
int client_fifo_fd = -1;

server_fifo_fd = open(SERVER_FIFO_NAME, O_WRONLY);
if (server_fifo_fd < 0){
perror("open server fifo error\n");
return -1;
}

client_pid = getpid();

char client_fifo_name[CLIENT_FIFO_NAME_LEN] = {0};
snprintf(client_fifo_name, CLIENT_FIFO_NAME_LEN - 1, CLIENT_FIFO_NAME, client_pid);
if (mkfifo(client_fifo_name, 0777) < 0){
perror("mkfifo client error\n");
close(server_fifo_fd);
return -1;
}

fifo_msg_t client_msg;
memset(&client_msg, 0, sizeof(client_msg));
client_msg.client_pid = client_pid;

#define TRY_TIMES 3
int times = 0;
for (times = 0; times < TRY_TIMES; times++){
snprintf(client_msg.msg, MSG_LEN - 1, "client_pid:%d\n", client_pid);
write(server_fifo_fd, &client_msg, sizeof(client_msg));

client_fifo_fd = open(client_fifo_name, O_RDONLY);
if (client_fifo_fd < 0){
perror("open client fifo error\n");
close(server_fifo_fd);
unlink(client_fifo_name);
return -1;
}

int n = read(client_fifo_fd, &client_msg, sizeof(client_msg));
if (n > 0){
printf("reveive msg from server:%s", client_msg.msg);
}

close(client_fifo_fd);
}

close(server_fifo_fd);
unlink(client_fifo_name);
return 0;
}

本文标题:linux系统编程-进程间通信练手

文章作者:Hengliy

发布时间:2018年01月16日 - 14:01

最后更新:2018年02月24日 - 11:02

原始链接:http://hengliy.github.io/2018/01/16/LINUX系统编程-进程间通信练手/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。