目录
1、什么是共享内存?
共享内存本质上就是内存中的一块区域,用于进程间通信使用。所有访问这块空间的程序都能访问改数据。
2、实现思路
3、upload和download代码
3.1、头文件
#ifndef __COMMON_H__
#define __COMMON_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#define IPC_PATH "./" // IPC路径
#define IPC_MASK 1 // IPC标识
#define MSG_LEN 256 // 消息长度
#define PAGE_SIZE 4096 // 一页的大小,共享内存设置大小时,最好以当前系统的整数页好
typedef struct demo_inf
{
int shm_id; // 共享内存id
char *shm_p; // 共享内存地址
char *file_path; // upload file path
long other_id; // download id
} SDI, *P_SDI;
#endif
3.2、upload
#include "common.h"
P_SDI Upload_Init(char *file_path);
int Running_upload(P_SDI p_sdi);
void get_file_size(int signum);
int Upload_Free(P_SDI p_sdi);
int Upload_Free(P_SDI p_sdi)
{
free(p_sdi);
printf("free 成功!\n");
return 0;
}
void get_file_size(int signum)
{
printf("get_file_size signal\n");
}
void file_upload_continue(int signum);
void file_upload_continue(int signum)
{
if (signum == SIGUSR2)
{
printf("file download continue!\n");
}
if (signum == SIGALRM)
{
printf("the last download\n");
}
}
P_SDI Upload_Init(char *file_path)
{
if (file_path == (char *)NULL)
{
printf("will upload file path is NULL..\n");
return (P_SDI)-1;
}
P_SDI p_sdi = (P_SDI)malloc(sizeof(SDI));
if (p_sdi == (P_SDI)NULL)
{
perror("malloc error");
return (P_SDI)-1;
}
// 创建Key值
key_t key = ftok(IPC_PATH, IPC_MASK);
if (key == -1)
{
perror("ftok error");
return (P_SDI)-1;
}
else
{
printf("key = %d\n", key);
}
p_sdi->file_path = file_path;
printf("请输入接收方的PID : \n");
scanf("%ld", &p_sdi->other_id);
// 创建共享内存ID
if ((p_sdi->shm_id = shmget(key, PAGE_SIZE, IPC_CREAT | 0666)) == -1)
{
perror("shmget error");
return (P_SDI)-1;
}
// 共享内存的映射
if ((p_sdi->shm_p = (char *)shmat(p_sdi->shm_id, NULL, 0)) == (char *)-1)
{
perror("shmat error");
return (P_SDI)-1;
}
if (signal(SIGUSR1, get_file_size) == SIG_ERR)
{
perror("signal file_upload_continue error");
return (P_SDI)-1;
}
if (signal(SIGUSR2, file_upload_continue) == SIG_ERR)
{
perror("signal file_upload_continue error");
return (P_SDI)-1;
}
if (signal(SIGALRM, file_upload_continue) == SIG_ERR)
{
perror("signal file_upload_continue error");
return (P_SDI)-1;
}
return p_sdi;
}
int Running_upload(P_SDI p_sdi)
{
// 先计算文件的大小
struct stat sb;
memset(&sb, 0, sizeof(sb));
stat(p_sdi->file_path, &sb);
// 把文件大小数据先传给对面
long file_size = sb.st_size;
printf("file_size = %ld\n", file_size);
char file_size_str[MSG_LEN];
memset(file_size_str, 0, sizeof(char) * MSG_LEN);
memset(p_sdi->shm_p, 0, PAGE_SIZE);
sprintf(file_size_str, "%ld", file_size);
memcpy(p_sdi->shm_p, file_size_str, strlen(file_size_str));
// 先暂停,等对面准备接收了再发数据
pause();
// 给download发送定时器信号,让对面接收数据大小
usleep(30000);
if (kill(p_sdi->other_id, SIGUSR1) == -1)
{
perror("kill error");
return -1;
}
// 根据文件大小判断要传几次
int fd = open(p_sdi->file_path, O_RDONLY);
if (fd == -1)
{
perror("open error");
return -1;
}
char file_date[PAGE_SIZE];
int i;
pause();
for (i = 0; i < (int)(file_size / PAGE_SIZE); i++)
{
memset(file_date, 0, sizeof(char) * PAGE_SIZE);
memset(p_sdi->shm_p, 0, PAGE_SIZE);
int read_ret = read(fd, file_date, PAGE_SIZE);
if (read_ret == -1)
{
perror("read error");
return -1;
}
else
{
printf("read_ret = %d\n", read_ret);
}
// 将数据放到共享内存中
memcpy(p_sdi->shm_p, file_date, read_ret);
// 发信号给download,让它下载
usleep(30000);
if (kill(p_sdi->other_id, SIGUSR2) == -1)
{
perror("kill error");
return -1;
}
pause(); // 接收信号继续下载
}
// 发送最后一次
if ((file_size / PAGE_SIZE) != 0)
{
int read_ret = read(fd, file_date, file_size % PAGE_SIZE);
if (read_ret == -1)
{
perror("read error");
return -1;
}
else
{
printf("read_ret = %d, 剩余:%d\n", read_ret, (int)(file_size % PAGE_SIZE));
}
// 将数据放到共享内存中
memset(p_sdi->shm_p, 0, PAGE_SIZE);
memcpy(p_sdi->shm_p, file_date, file_size % PAGE_SIZE);
// 发信号给download,让它下载,且是最后一次
usleep(30000);
if (kill(p_sdi->other_id, SIGUSR2) == -1)
{
perror("kill error");
return -1;
}
pause();
usleep(30000);
if (kill(p_sdi->other_id, SIGALRM) == -1)
{
perror("kill error");
return -1;
}
}
return 0;
}
// ./upload upload_file_path
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("输入参数有误!\n");
return -1;
}
printf("upload pid is %ld \n", (long)getpid());
P_SDI p_sdi = Upload_Init(argv[1]);
if (p_sdi == (P_SDI)-1)
{
printf("Upload process init error");
return -1;
}
if (Running_upload(p_sdi) == -1)
{
printf("uplaod running error\n");
return -1;
}
if (Upload_Free(p_sdi) == -1)
{
perror("Upload Free error...\n");
return -1;
}
return 0;
}
3.3、download
#include "common.h"
P_SDI Download_Init(char *file_path, key_t key);
int Running_Download(P_SDI p_sdi);
void file_download_continue(int signum);
void get_file_size(int signum);
int Download_Free(P_SDI p_sdi);
int Download_Free(P_SDI p_sdi)
{
// 解除映射
if (shmdt(p_sdi->shm_p) == -1)
{
perror("p_sdi->shm_p error");
return -1;
}
// 删除映射
if (shmctl(p_sdi->shm_id, IPC_RMID, NULL) == -1)
{
perror("shmctl error...\n");
return -1;
}
printf("解除并删除共享内存成功\n");
return 0;
}
void get_file_size(int signum)
{
printf("get_file_size signal\n");
}
void file_download_continue(int signum)
{
if (signum == SIGUSR2)
{
printf("file download continue!\n");
}
if (signum == SIGALRM)
{
printf("the last download\n");
}
}
P_SDI Download_Init(char *file_path, key_t key)
{
if (file_path == (char *)NULL)
{
printf("will upload file path is NULL..\n");
return (P_SDI)-1;
}
P_SDI p_sdi = (P_SDI)malloc(sizeof(SDI));
if (p_sdi == (P_SDI)NULL)
{
perror("malloc error");
return (P_SDI)-1;
}
p_sdi->file_path = file_path;
printf("请输入发送方的PID : \n");
scanf("%ld", &p_sdi->other_id);
// 创建共享内存ID
if ((p_sdi->shm_id = shmget(key, PAGE_SIZE, IPC_CREAT | 0666)) == -1)
{
perror("shmget error");
return (P_SDI)-1;
}
// 共享内存的映射
if ((p_sdi->shm_p = (char *)shmat(p_sdi->shm_id, NULL, 0)) == (char *)-1)
{
perror("shmat error");
return (P_SDI)-1;
}
if (signal(SIGUSR1, get_file_size) == SIG_ERR)
{
perror("signal get_file_size error");
return (P_SDI)-1;
}
if (signal(SIGUSR2, file_download_continue) == SIG_ERR)
{
perror("signal file_download_continue error");
return (P_SDI)-1;
}
if (signal(SIGALRM, file_download_continue) == SIG_ERR)
{
perror("signal file_download_continue error");
return (P_SDI)-1;
}
return p_sdi;
}
int Running_Download(P_SDI p_sdi)
{
usleep(30000);
if (kill(p_sdi->other_id, SIGUSR1) == -1)
{
perror("kill error");
return -1;
}
// 先获取文件大小
pause();
char file_size_str[MSG_LEN];
memset(file_size_str, 0, sizeof(char) * MSG_LEN);
memcpy(file_size_str, p_sdi->shm_p, MSG_LEN);
long file_size = atol(file_size_str);
printf("file_size = %ld\n", file_size);
umask(0000);
int fd = open(p_sdi->file_path, O_WRONLY | O_CREAT, 0777);
if (fd == -1)
{
perror("open error");
return -1;
}
// 循环读数据
usleep(30000);
if (kill(p_sdi->other_id, SIGUSR2) == -1)
{
perror("kill error");
}
char file_date[PAGE_SIZE];
int i;
for (i = 0; i < (int)(file_size / PAGE_SIZE); i++)
{
pause();
memset(file_date, 0, sizeof(char) * PAGE_SIZE);
memcpy(file_date, p_sdi->shm_p, PAGE_SIZE);
printf("sizeof(file_date) = %ld\n", sizeof(file_date));
int write_ret = write(fd, file_date, sizeof(file_date));
if (write_ret == -1)
{
perror("read error");
return -1;
}
else
{
printf("write_ret = %d\n", write_ret);
}
// 发信号给upload,让它继续上传
usleep(30000);
if (kill(p_sdi->other_id, SIGUSR2) == -1)
{
perror("kill errror");
return -1;
}
}
// 接收最后一次
if ((file_size / PAGE_SIZE) != 0)
{
pause();
memset(file_date, 0, sizeof(char) * PAGE_SIZE);
memcpy(file_date, p_sdi->shm_p, file_size % PAGE_SIZE);
int last_write_ret = write(fd, file_date, file_size % PAGE_SIZE);
if (last_write_ret == -1)
{
perror("read error");
return -1;
}
else
{
printf("last_write_ret = %d\n", last_write_ret);
}
// 发信号给uoload,表示下完了
usleep(2000);
if (kill(p_sdi->other_id, SIGALRM) == -1)
{
perror("kill error");
return -1;
}
else
{
printf("发送定时器信号成功\n");
}
pause();
}
return 0;
}
// ./download download_file_path key
int main(int argc, char *argv[])
{
if (argc != 3)
{
printf("输入参数有误!\n");
return -1;
}
printf("download pid is %ld \n", (long)getpid());
P_SDI p_sdi = Download_Init(argv[1], atoi(argv[2]));
if (p_sdi == (P_SDI)-1)
{
printf("Download process init error");
return -1;
}
if (Running_Download(p_sdi) == -1)
{
printf("uplaod running error\n");
return -1;
}
if (Download_Free(p_sdi) == -1)
{
perror("Download_Free error...\n");
return -1;
}
return 0;
}