Linux系统下利用共享内存模拟迅雷下载

我的思路比较简单,具体总结如下:

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;
}

运行结果:

运行环境要求 硬件: x86或x64 CPU 下载文件夹所在卷容量大于4G 软件: Linux 32位或64位x86系列CPU Python3 >= 3.4 Py3.PyQt5 >= 5.2 详细的软件依赖参见发行版的打包文件。 其它: 拥有迅雷账户(会员/非会员均可) 许可证 GPLv3 -- Xware Desktop部分 迅雷协议 -- Xware部分 新增64位版本(迅雷下载核心1.0.31): 附件: xware-desktop_0.13.20141115_amd64.deb [1.71 MiB] 被下载 2099 次 Xware Desktop已打包,64位打包系统是kubuntu15.04,凡是64位的ubuntu15.04系,应该都能用. 迅雷版本是1.0.31,包含数个linux原生二进制程序,建议双击安装包进行安装,它还要额外的pyQt5图形库,会自动从ubuntu仓库下载. 第一次先不要登陆,先要设置.启动迅雷软件->菜单栏->文件->设置 ->挂载->添加下载目录,比如我的是/home/name/download. ->启动与登陆->xwared托管->我们选systemd托管,ETM选随xwared启动 至此设置告一段落.重启PC后,如下图会有两个迅雷的原生进程: 附件: thunder.png thunder.png [ 23.98 KiB | 被浏览 52484 次 ] 在我的kubuntu开始菜单的因特网子菜单里会有个xwared Desktop的迅雷图标,点击它就能启动迅雷了. 第一次登陆后会有激活码,点一下即可成功. 就能跟windows里的迅雷7一样用啦,速度嘛,跟windows完全一样,免费用户同样没有高速通道,要vip才能用. 32位迅雷下载核心更新至1.0.25 附件: xware-desktop_0.10.20140702_i386.deb [1.61 MiB] 被下载 7829 次 当然,有能力的同学可以自行编译,在Ubuntu上编译安装说明如下 : 编译环境: 安装必备的软件。 sudo apt-get install git build-essential devscripts 下载源代码。 git clone git://github.com/Xinkai/XwareDesktop.git 这会在当前目录下生成一个名为XwareDesktop的子目录。 切换到源代码目录XwareDesktop。 cd XwareDesktop 打包 你需要切换到XwareDesktop的源代码目录。 列出缺失的编译依赖。 dpkg-checkbuilddeps。 如果没有列出任何东西,跳过步骤2。 安装缺失的编译依赖。 sudo apt-get install 制作安装包。 dpkg-buildpackage 执行这条命令后会在你当前目录下生成数个包,其中包括xware-desktop_??????.deb安装包。 安装 回到图形化界面,在XwareDesktop的源代码目录的上级目录,你应该能找到名为xware-desktop_??????.deb的安装包文件, 双击它,按提示安装。 浏览器扩展整合 Xware Desktop接受来自命令行的参数作为新任务的网址,格式为 xware-desktop http://www.website.com/file1 ftp://www.website.com/file2 ... 以Firefox上的Flashgot为例,打开其选项。添加一个新的下载器,程序设置为xware-desktop,参数设置为[URL]。 来自命令行的参数支持http,https,ftp,ed2k,magnet,flashget,qqdl,thunder等多种协议, 也同样支持本地的torrent文件。 注:本软件同linux版115网盘存在冲突,出现如下提示: This application failed to start because it could not find or load the Qt platform plugin "xcb". Reinstalling the application may fix this problem.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不掉头发的程序猿_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值