沫颖 的学生作业:
代码
shm.h
#ifndef __SHM_H__
#define __SHM_H__
#include
#include
#include
#include
#include
#include
#include
#include
#define PATHNAME "."
#define PROID 40
#define SHM_SIZE 4096
#endif
shm_write.c
#include "shm.h"
// 清理共享内存资源的函数
void cleanup_shm(int shm_id, void *shm_addr)
{
if (shm_addr != NULL)
{
// 解除共享内存映射
if (shmdt(shm_addr) == -1)
{
perror("[ERROR] shmdt() in cleanup:");
}
}
if (shm_id != -1)
{
if (shmctl(shm_id, IPC_RMID, NULL) == -1)
{
perror("[ERROR] shmctl() in cleanup:");
}
}
}
// 从给定文件描述符读取文件内容并写入共享内存的函数,改进后添加写入数据长度信息
int write_file_to_shm(int fd, void *shm_addr)
{
char buffer[SHM_SIZE - sizeof(int)];
ssize_t rbytes;
ssize_t total_written = sizeof(int);
int data_length = 0;
while ((rbytes = read(fd, buffer, sizeof(buffer))) > 0)
{
// 根据实际读取到的字节数来写入共享内存
data_length += rbytes;
memcpy((char *)shm_addr + total_written, buffer, rbytes);
total_written += rbytes;
}
if (rbytes == -1)
{
perror("[ERROR] read() :");
return -1;
}
memcpy(shm_addr, &data_length, sizeof(int));
return 0;
}
int main(int argc, char const *argv[])
{
// 判断控制台输入参数(需要传输的文件路径)
if (2 != argc)
{
printf("[ERROR] Usage : %s \n", argv[0]);
exit(EXIT_FAILURE);
}
int fd;
// 打开文件
fd = open(argv[1], O_RDONLY);
if (fd == -1)
{
perror("[ERROR] open() :");
exit(EXIT_FAILURE);
}
key_t key_shm;
// 生成唯一key
key_shm = ftok(PATHNAME, PROID);
if (key_shm == -1)
{
perror("[ERROR] ftok() :");
exit(EXIT_FAILURE);
}
int shm_id;
// 创建共享内存
shm_id = shmget(key_shm, SHM_SIZE, IPC_CREAT | 0666);
if (shm_id == -1)
{
perror("[ERROR] shmget() :");
exit(EXIT_FAILURE);
}
// 映射共享内存
void *shm_addr = NULL;
shm_addr = shmat(shm_id, NULL, 0);
if (shm_addr == (void *)-1)
{
perror("[ERROR] shmat() :");
close(fd);
exit(EXIT_FAILURE);
}
// 读取文件内容并写入共享内存
if (write_file_to_shm(fd, shm_addr) == -1)
{
close(fd);
// 出现错误时,先清理资源再返回错误码
cleanup_shm(shm_id, shm_addr);
exit(EXIT_FAILURE);
}
// // 正常结束前手动调用清理资源的函数
// cleanup_shm(shm_id, shm_addr);
// 成功写入共享内存
printf("write to shm success!\n");
// 关闭文件
close(fd);
return 0;
}
shm_read.c
#include "shm.h"
// 清理共享内存资源的函数
void cleanup_resources(int shm_id, void *shm_addr, int fd)
{
if (shm_addr != NULL)
{
// 解除共享内存映射
if (shmdt(shm_addr) == -1)
{
perror("[ERROR] shmdt() in cleanup:");
}
}
if (shm_id != -1)
{
if (shmctl(shm_id, IPC_RMID, NULL) == -1)
{
perror("[ERROR] shmctl() in cleanup:");
}
}
if (fd != -1)
{
// 关闭文件描述符
close(fd);
}
}
// 从共享内存中读取固定长度的数据
ssize_t read_fixed_length_from_shm(void *shm_addr, char *buffer, size_t length)
{
ssize_t rbytes = 0;
while (rbytes < length)
{
buffer[rbytes] = ((char *)shm_addr)[rbytes];
rbytes++;
}
return rbytes;
}
int main(int argc, char const *argv[])
{
int fd;
// 打开文件
fd = open(argv[1], O_CREAT | O_RDWR, 0666);
if (fd == -1)
{
perror("[ERROR] open() :");
exit(EXIT_FAILURE);
}
key_t key_shm;
// 生成唯一key
key_shm = ftok(PATHNAME, PROID);
if (key_shm == -1)
{
perror("[ERROR] ftok() :");
exit(EXIT_FAILURE);
}
int shm_id;
// 创建共享内存
shm_id = shmget(key_shm, SHM_SIZE, IPC_CREAT | 0666);
if (shm_id == -1)
{
perror("[ERROR] shmget() :");
exit(EXIT_FAILURE);
}
// 映射共享内存
void *shm_addr = NULL;
shm_addr = shmat(shm_id, NULL, 0);
if (shm_addr == (void *)-1)
{
perror("[ERROR] shmat() :");
close(fd);
exit(EXIT_FAILURE);
}
int data_length;
memcpy(&data_length, shm_addr, sizeof(int));
char buffer[SHM_SIZE];
ssize_t rbytes;
if (data_length > 0)
{
// 根据获取到的数据长度从共享内存读取相应字节的数据到缓冲区
rbytes = read_fixed_length_from_shm((char *)shm_addr + sizeof(int), buffer, data_length);
if (rbytes == -1)
{
perror("[ERROR] read from shm:");
// 出现错误时,先清理资源再返回错误码
cleanup_resources(shm_id, shm_addr, fd);
return EXIT_FAILURE;
}
// 将缓冲区中的数据写入文件
if (write(fd, buffer, rbytes) == -1)
{
perror("[ERROR] write() :");
// 出现错误时,先清理资源再返回错误码
cleanup_resources(shm_id, shm_addr, fd);
return EXIT_FAILURE;
}
}
// 正常结束前手动调用清理资源的函数
cleanup_resources(shm_id, shm_addr, fd);
// 成功写入文件
printf("write success\n");
// 关闭文件
close(fd);
return 0;
}