我的思路比较简单,具体总结如下:
1、服务器端启动,直接将所有文件上传至共享内存区
2、在服务器端本次共模拟两个文件,视频文件 1.mp4、图片1.jpg,两个文件各开辟一块过程内存区
3、文件资源名字通过映射发送至两端
4、客户端启动,通过文件名字自主选择要下载的文件资源
5、主函数中由父进程创建两个兄弟进程,由父进程发送自定义信号,指挥其子进程进行下载
这里总结一下我遇到的比较大的问题:
1、如果上传文本文件,在客户端获取文件大小比较简单,strlen()函数直接搞定,因为文本文件中存储的其实可以看成一个比较的字符串而已。
但是音视频以及图片类型的二进制文件,strlen()函数则无法运用,我也尝试了不少方法,例如循序判断字符,lseek等等,都无济于事。所这里我再次开辟了一块共享内存区存储文件的大小。
2、如何通过父进程指挥其子进程去下载呢?
我是通过注册自定义信号SIGUSR1和SIGUSR2,然后通过kill(getpid(),执行函数)传递信号,去指挥子进程下载。
3、其他细微问题这里便不再赘述,都是一些变量未初始化、函数参数忘记使用、未删除映射区、未删除共享内存关联等等小问题。
废话不多说,上代码!
服务器端:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <error.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#define SHMKEY01 100//1.jpg的共享内存区
#define SHMKEY02 200//1.mp4的共享内存区
#define SHMKEY03 300//1.txt的共享内存区
#define SIZE 4096000
int shmid,shmid02,shmid03;
char *buf = NULL;//共享内存1
char *buf02 = NULL;//共享内存2
int fp;//文件描述符1
int fp02;//文件描述符2
int fp03;//文件描述符3
int fd;//内存映射
static int num01=0;
static int num02=0;
typedef struct
{
int n1;
int n2;
}NUM;
NUM info[1];
NUM *buf03 = NULL;//共享内存3
int main(int argc,char *argv[])
{
printf("文件正在上传服务器,请稍后...\n");
sleep(3);
printf("文件上传成功!\n");
shmid = shmget(SHMKEY01, SIZE, 0664 | IPC_CREAT);
if(shmid==-1)
{
printf("servre()...shmget() fail!\n");
exit(1);
}
printf("server() shmid=%d\n",shmid);
buf = (char *)shmat(shmid, NULL, 0);
if(NULL == buf)
{
perror("error");
exit(1);
}
fp = open("/home/lianpan/0924/homework/1.jpg",O_RDONLY);//上传图片1.jpg
int ret01 = read(fp,buf,SIZE);
printf("当前服务器获取到文件1.jpg共%d个字节\n",ret01);
info[0].n1 = ret01;
shmid02 = shmget(SHMKEY02, SIZE, 0664 | IPC_CREAT);
if(shmid02 == -1)
{
printf("servre()...shmget() fail!\n");
exit(1);
}
printf("server() shmid02=%d\n",shmid02);
buf02 = (char *)shmat(shmid02, NULL, 0);
if(NULL == buf02)
{
perror("error");
exit(1);
}
fp02 = open("/home/lianpan/0924/homework/1.mp4",O_RDONLY);//上传视频1.mp4
int ret02 = read(fp02,buf02,SIZE);
printf("当前服务器获取到文件1.mp4共%d个字节\n",ret02);
info[0].n2 = ret02;
shmid03 = shmget(SHMKEY03, 4, 0664 | IPC_CREAT);
if(shmid03 == -1)
{
printf("servre()...shmget() fail!\n");
exit(1);
}
printf("server() shmid03=%d\n",shmid03);
buf03 = (NUM *)shmat(shmid03, NULL, 0);
if(NULL == buf03)
{
perror("error");
exit(1);
}
*buf03 = info[0];
fd = open("readme.txt",O_RDWR|O_CREAT,0664);//readme.txt文件映射到共享内存区
if(-1 == fd)
{
perror("内存映射失败");
exit(-1);
}
int len = lseek(fd,0,SEEK_END);
printf("当前服务器获取到文件readme.txt为%d个字节大小\n",len);
system("ipcs -m");
// printf("info[0].n1=%d,info[0].n2=%d\n",info[0].n1,info[0].n2);
char *p = NULL;
p = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//将文件映射到共享内存
if(p == MAP_FAILED)
{
perror("mmap error");
exit(1);
}
// printf("文件read.txt的内容为:\n%s\n",p);
munmap(p,len);//关闭映射区
close(fp);//关闭文件描述符
close(fp02);
shmdt(buf);
shmdt(buf02);
sleep(15);
return 0;
}
客户端:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <error.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <pthread.h>
#define SHMKEY01 100//1.jpg的共享内存区
#define SHMKEY02 200//1.mp4的共享内存区
#define SHMKEY03 300//1.txt的共享内存区
#define SIZE 4096000
int shmid,shmid02,shmid03;//共享内存返回值
int pid;//父子进程
char *buf = NULL;//共享内存1
char *buf02 = NULL;//共享内存2
//char *buf03 = NULL;//共享内存3
int fp;//文件描述符1
int fp02;//文件描述符2
int fp03;//文件描述符3
int fd;//内存映射
int len;//映射区内容大小
int num1 = 0;//接收文件大小
int num2 = 0;//接收文件大小
typedef struct
{
int n1;
int n2;
}NUM;
NUM *buf03 = NULL;
void client01()
{
shmid = shmget(SHMKEY01, SIZE, 0);
if(shmid==-1)
{
printf("servre()...shmget() fail!\n");
exit(1);
}
printf("server() shmid=%d\n",shmid);
buf = (char *)shmat(shmid, NULL, 0);
if(NULL == buf)
{
perror("error");
exit(1);
}
/*
int mm=0;
for(int j=0;;j++)
{
if(*(buf+j) == EOF)
break;
else
mm++;
}
printf("mm=%d\n",mm);
int mmm = strlen(buf);
printf("mmm=%d\n",mmm);
*/
fp = open("1.jpg",O_RDWR|O_CREAT,0777);
int ret = write(fp,buf,num1);
int n = lseek(fp,0,SEEK_END);
printf("文件1.jpg的大小为:%d\n",n);
if(ret == -1)
{
perror("write error");
exit(1);
}
else
printf("由共享内存区buf写入到文件1.jpg大小为:%d\n",n);
close(fp);//此时就可以关闭文件描述符
}
void client02()
{
shmid02 = shmget(SHMKEY02, SIZE, 0);
if(shmid02 == -1)
{
printf("servre()...shmget() fail!\n");
exit(1);
}
printf("server() shmid02=%d\n",shmid02);
buf02 = (char *)shmat(shmid02, NULL, 0);
if(NULL == buf02)
{
perror("error");
exit(1);
}
fp02 = open("1.mp4",O_RDWR|O_CREAT,0777);
int ret = write(fp02,buf02,num2);
int m = lseek(fp02,0,SEEK_END);
printf("文件1.mp4的大小为:%d\n",m);
if(ret == -1)
{
perror("write error");
exit(1);
}
else
printf("由共享内存区buf02写入到文件2.txt大小为:%d\n",ret);
close(fp02);
}
void client03()
{
shmid03 = shmget(SHMKEY03, 4, 0664 | IPC_CREAT);
if(shmid03 == -1)
{
printf("servre()...shmget() fail!\n");
exit(1);
}
printf("server() shmid03=%d\n",shmid03);
buf03 = (NUM *)shmat(shmid03, NULL, 0);
if(NULL == buf03)
{
perror("error");
exit(1);
}
// printf("%d\n",buf03->n1);
// printf("%d\n",buf03->n2);
}
//内存映射
void mmaptest(void)
{
fd = open("../readme.txt",O_RDWR|O_CREAT,0664);//readme.txt文件映射到共享内存区
if(-1 == fd)
{
perror("内存映射失败");
exit(-1);
}
int len = lseek(fd,0,SEEK_END);
// printf("当前获取到文件readme.txt为%d个字节大小\n",len);
char *p = NULL;
p = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//将文件映射到共享内存
if(p == MAP_FAILED)
{
perror("mmap error");
exit(1);
}
// printf("文件readme.txt的内容为:\n%s\n",p);
}
int main(int argc,char *argv[])
{
client03();//内存共享获取文件大小
num1 = buf03->n1;//结构体元素赋值全局变量
num2 = buf03->n2;
// printf("%d\n",num1);
// printf("%d\n",num2);
char ch;
int SHMKEY04 = 400;
shmid03 = shmget(SHMKEY04,4,IPC_CREAT | 0777);
if(shmid03 == -1)
{
printf("main...shmget() fail!\n");
exit(1);
}
printf("创建共享内存成功 shmid03=%d\n",shmid03);
int *p = NULL;
int j=0;
p = (int *)shmat(shmid03,NULL,0);
*p = 1;
signal(SIGUSR1,client01);//注册自定义信号1
signal(SIGUSR2,client02);//注册自定义信号2
// signal(SIGUSR3,client02);
mmaptest();
printf("请选择您要下载的文件资源:\n1、1.jpg\n2、1.mp4\n");
scanf("%c",&ch);
switch(ch)
{
case '1':
pid = fork();
if(pid == 0)
{
printf("我是第一个子进程\n");
if(*p == 1)
{
printf("文件正在下载中,请等待...\n");
static int n=6;
for(int j=0;j<5;j++)
{
printf("目前下载进程...%d%%\n",n);
n += 13;
usleep(500000);
}
printf("目前下载进程...100%%\n");
printf("文件下载成功,请返回查看!\n");
kill(getpid(),SIGUSR1);
*p = 0;
sleep(1);
}
}
else if(pid > 0)
{
// printf("我是父进程\n");
}
break;
case '2':
pid = fork();
if(pid == 0)
{
printf("我是第二个子进程\n");
static int n=7;
if(*p == 1)
{
printf("文件正在下载中,请等待...\n");
for(int j=0;j<5;j++)
{
printf("目前下载进程...%d%%\n",n);
n += 13;
usleep(500000);
}
printf("目前下载进程...100%%\n");
printf("文件下载成功,请返回查看!\n");
kill(getpid(),SIGUSR2);
*p = 0;
sleep(1);
}
}
else if(pid > 0)
{
// printf("我是父进程\n");
}
break;
default:
break;
}
shmctl(shmid,IPC_RMID,0);//删除共享内存区
shmctl(shmid02,IPC_RMID,0);
shmctl(shmid03,IPC_RMID,0);
munmap(p,len);//删除映射区
return 0;
}