加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
gets.c 5.17 KB
一键复制 编辑 原始数据 按行查看 历史
SpaceX_zhao 提交于 2023-05-17 12:00 . alopex modify
#include "head.h"
// 小文件的接收
void recvMinFile(int sockfd, int fd, train_t train){
printf("小文件接收\n");
while(1){
bzero(&train, sizeof(train));
// 接收数据的长度
recvn(sockfd, &train.length, sizeof(train.length));
if(train.length == 0){
break;
}
// 接收内容
recvn(sockfd, train.data, train.length);
write(fd, train.data, train.length);
}
}
// 大文件的接收, mmap方式
void recvMaxFile(int sockfd, int fd, off_t filesize){
printf("大文件接收\n");
ftruncate(fd, filesize);
char *p = (char *)mmap(NULL, filesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
ERROR_CHECK(p, MAP_FAILED, "mmap");
recvn(sockfd, p, filesize);
munmap(p, filesize);
}
// 续传的接收
void recvAgain(int sockfd, int fd, off_t filesize, off_t offset){
printf("续传接收\n");
ftruncate(fd, filesize);
char *p = (char *)mmap(NULL, filesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
ERROR_CHECK(p, MAP_FAILED, "mmap");
recvn(sockfd, p+offset, filesize-offset);
munmap(p, filesize);
}
int recvFile(int sockfd){
train_t train1, train2, train3, train4, train5;
// step1:接收文件名长度和文件名
bzero(&train1,sizeof(train1));
recvn(sockfd, &train1.length, sizeof(train1.length));
recvn(sockfd, train1.data, train1.length);
//printf("train1.data = %s\n", train1.data);
if(train1.length == 0){
recvn(sockfd, &train1.length, sizeof(train1.length));
recvn(sockfd, train1.data, train1.length);
}
// 打开文件,若不存在则新建文件
char newPath[4096] = {0};
sprintf(newPath, "%s/%s", ".", train1.data);
int fd = open(newPath, O_RDWR|O_CREAT, 0666);
ERROR_CHECK(fd, -1, "open");
// step2:接收文件总大小
bzero(&train2,sizeof(train2));
off_t fileSize;
recvn(sockfd, &train2.length, sizeof(train2.length));
recvn(sockfd, train2.data, train2.length);
memcpy(&fileSize, train2.data, sizeof(off_t));
//printf("fileSize = %ld\n", fileSize);
// step3:收取发送方的md5码
bzero(&train3,sizeof(train3));
unsigned char mdFromSender[16];
recvn(sockfd, &train3.length, sizeof(train3.length));
recvn(sockfd, train3.data, train3.length);
for(int i=0; i<train3.length; i++){
mdFromSender[i] = train3.data[i];
}
printf("recv md5 done!\n");
// step4:发送initSize,对于文件的发送方相当于偏移量
bzero(&train4,sizeof(train4));
struct stat statbuf;
fstat(fd, &statbuf);
off_t initSize = statbuf.st_size;
printf("offset = %ld\n", initSize);
train4.length = sizeof(statbuf.st_size);
memcpy(train4.data, &statbuf.st_size, train4.length);
send(sockfd, &train4, sizeof(train4.length)+train4.length, MSG_NOSIGNAL);
// 若接收方已存在同名文件且文件大小与发送方一致,
// 则计算md5码,再和发送方的md5码比较
if(initSize == fileSize){
// 接收方自己的md5码
MD5_CTX ctx;
MD5_Init(&ctx);
char buf[4096];
while(1){
bzero(buf, sizeof(buf));
ssize_t sret = read(fd, buf, sizeof(buf));
if(sret == 0){
break;
}
MD5_Update(&ctx, buf, sret);
}
unsigned char mdFromRecver[16]; // 将要保存md5码16个字节的二进
MD5_Final(mdFromRecver, &ctx);
int flag = 0;
for(int i=0; i<16; i++){
if(mdFromRecver[i] != mdFromSender[i]){
// 同名文件且文件大小一致, 但md5码不一致
flag = 1;
printf("此接收文件有错\n");
return -1;
}
}
if(flag == 0){
// 同名文件且文件大小一致,md5码也一致
printf("秒传模式\n");
printf("recv file done!\n");
printf("此接收文件无错\n");
return 0;
}
}
else{
if(initSize > 0){
// 续传的接收
recvAgain(sockfd, fd, fileSize, initSize);
}
else if(initSize == 0 && fileSize >= 100*1024*1024){
// 大文件接收
recvMaxFile(sockfd, fd, fileSize);
}
else if(initSize == 0 && fileSize < 100*1024*1024){
// 小文件接收
recvMinFile(sockfd, fd, train5);
}
}
printf("recv file done!\n");
// 接收完文件内容后lseek到开头
lseek(fd, 0, SEEK_SET);
// 非秒传模式,接收完文件后再计算接收方自己的md5码
MD5_CTX ctx;
MD5_Init(&ctx);
char buf[4096];
while(1){
bzero(buf, sizeof(buf));
ssize_t sret = read(fd, buf, sizeof(buf));
if(sret == 0){
break;
}
MD5_Update(&ctx, buf, sret);
}
unsigned char mdFromRecver[16]; // 将要保存md5码16个字节的二进
MD5_Final(mdFromRecver, &ctx);
// 比较两个md5码
for(int i=0; i<16; i++){
if(mdFromRecver[i] != mdFromSender[i]){
printf("此接收文件有错\n");
return -1;
}
}
printf("此接收文件无错误\n");
return 0;
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化