私人云盘(自动云同步)

一、项目简介

模仿小米的云服务,实现一个通过TCP实现的私人云盘,因为能力有限,所以只实现自动云同步这一个功能,具体可以分为三个小功能,即保持云端和终端数据一致、实现文件的上传与下载以及手动同步

二、涉及到的知识点

主要有文件的打开与关闭,文件的发送与接收,文件的写入及socket通信,为了项目整体的间接性,还使用到的枚举类型的结构体以及链表

三、TCP通信实现流程图
四、讲解

在项目实现过程中,代码程序修改了多次,我将最终的项目程序压缩包上传到了我的资源上面,有兴趣的可以自行下载。

这里放的程序是我在编写项目程序过程中的一个版本,只实现了单个文件的传输,需要自己手动输入要传输的文件,最终的版本在资源里面请不要搞错了

1、文件说明:

①client.c 是客户端的代码

②server.c 是服务器端的代码

③tcp.c 是客户端和服务器所使用到的一些头文件,以及自己封装的一些函数和自定义的宏

④Makefile 这个就不用多说了吧

2、程序文件

client.c文件

#include "tcp.h"

#define FILENAME "森林风声-呜呼呜呼-树木摇曳.mp3"

int main(int argc,char *argv[]){

int socketfd,filefd;

int ret;

char buf[BUFSIZ];

/*检查参数*/

Argment(argc,argv);

/*创建套接字并对其初始化*/

socketfd = SocketInit_Client(argv);

/*打开文件*/

filefd = open(FILENAME,O_RDONLY);

if(filefd == -1){

ErrExit("open");

}

/*发送文件名字*/

SocketDataHandle(socketfd,FILENAME,strlen(FILENAME),(DataHand_t)send);

SocketDataHandle(socketfd,buf,1,recv);

/*发送文件内容*/

if(buf[0] == OK){

while(1){

do{

ret = read(filefd,buf,BUFSIZ);

}while(ret < 0 && errno == EINTR);

if(ret < 0){

ErrExit("read");

}

if(!ret){

break;

}

ret = SocketDataHandle(socketfd,buf,ret,(DataHand_t)send);

if(!ret){

break;

}

}

}

close(filefd);

close(socketfd);

return 0;

}

server.c文件

#include "tcp.h"

int main(int argc,char *argv[]){

int socketfd,newsocketfd,filefd;

int ret;

char buf[BUFSIZ] = {};

Addr_in clientaddr;

socklen_t addrlen = sizeof(Addr_in);

/*检查参数*/

Argment(argc,argv);

/*创建套接字*/

socketfd = SocketInit_server(argv);

/*接收客户端的连接并生成一个新的套接字*/

do{

newsocketfd = accept(socketfd,(Addr *)&clientaddr,&addrlen);

}while(newsocketfd < 0 && errno == EINTR); //erron=EINTR如果信号导致的中断,重新执行一次

if(newsocketfd == -1){

ErrExit("accept");

}

/*接收文件名字*/

ret = SocketDataHandle(newsocketfd,buf,BUFSIZ,recv);

/*创建文件*/

filefd = open(buf,O_WRONLY|O_CREAT,0660);

if(filefd == -1){

ErrExit("open");

}

buf[0] = OK;

SocketDataHandle(newsocketfd,buf,1,(DataHand_t)send);

/*接收文件*/

while(1){

ret = SocketDataHandle(newsocketfd,buf,BUFSIZ,recv);

if(!ret){

break;

}

write(filefd,buf,ret);

}

close(filefd);

close(newsocketfd);

close(socketfd);

return 0;

}

tcp.h文件

#ifndef TCP_H

#define TCP_H

/*使用的头文件*/

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

#include <strings.h>

#include <errno.h>

#include <math.h>

#include <fcntl.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/stat.h>

#include <arpa/inet.h>

#include <netinet/in.h>

#include <netinet/tcp.h>

/*自己定义的宏*/

#define ErrExit(msg) do{perror(msg); exit(EXIT_FAILURE);}while(0)

#define BACKLOG 5

#define OK '1'

typedef struct sockaddr Addr;

typedef struct sockaddr_in Addr_in;

typedef ssize_t(* DataHand_t)(int ,void *,size_t,int);

/*函数声明*/

void Argment(int argc,char *argv[]);

int SocketInit_Client(char *argv[]);

int SocketInit_server(char *argv[]);

int SocketDataHandle(int fd,void *buf,size_t len,DataHand_t datahandle);

//参数检查函数

void Argment(int argc,char *argv[]){

if(argc < 3){

fprintf(stdin,"%s<addr><port>\n",argv[0]);

exit(EXIT_FAILURE);

}

}

//初始化客户端套接字函数

int SocketInit_Client(char *argv[]){

int socketfd;

Addr_in addr;

/*创建套接字*/

socketfd = socket(AF_INET,SOCK_STREAM,0);

if(socketfd == -1){

ErrExit("socket");

}

/*设置通信结构体*/

bzero(&addr,sizeof(addr));

addr.sin_family = AF_INET;

addr.sin_port = htons(atoi(argv[2]));

if(inet_aton(argv[1],&addr.sin_addr) == 0){

fprintf(stderr,"Invalid address\n");

exit(EXIT_FAILURE);

}

/*发起连接请求*/

if(connect(socketfd,(Addr *)&addr,sizeof(addr)) == -1){

ErrExit("connect");

}

return socketfd;

}

//初始化服务器端套接字函数

int SocketInit_server(char *argv[]){

int socketfd;

Addr_in addr;

/*创建套接字*/

socketfd = socket(AF_INET,SOCK_STREAM,0);

if(socketfd == -1){

ErrExit("socket");

}

/*设置地址快速重用*/

int flag = 1;

if(setsockopt(socketfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag)) == -1){

perror("setsockopt");

}

/*设置通信结构体*/

bzero(&addr,sizeof(addr));

addr.sin_family = AF_INET;

addr.sin_port = htons(atoi(argv[2]));

if(inet_aton(argv[1],&(addr.sin_addr)) == 0){

fprintf(stderr,"Invalid address\n");

exit(EXIT_FAILURE);

}

/*绑定通信结构体*/

if(bind(socketfd,(Addr *)&addr,sizeof(addr)) == -1){

ErrExit("bind");

}

/*设置套接字的模式为监听*/

if(listen(socketfd,BACKLOG) == -1){

ErrExit("listen");

}

return socketfd;

}

//数据处理函数

int SocketDataHandle(int fd,void *buf,size_t len,DataHand_t datahandle){

int ret;

char *str = datahandle == recv?"recv":"send";

do{

ret = datahandle(fd,buf,len,0);

}while(ret < 0 && errno == EINTR);

if(ret < 0){

ErrExit(str);

}

return ret;

}

#endif

Makefile文件

all:server client

CC=gcc

CFLAGS=-g -Wall

server:server.c

client:client.c

MV_client:

mv client /mnt/hgfs/Share/

clean:server client

rm server client

相关推荐
蒹葭玉树2 分钟前
【C++上岸】C++常见面试题目--操作系统篇(第二十八期)
linux·c++·面试
醉颜凉2 分钟前
【LeetCode】打家劫舍III
c语言·算法·leetcode·树 深度优先搜索·动态规划 二叉树
一匹电信狗5 分钟前
【LeetCode_21】合并两个有序链表
c语言·开发语言·数据结构·c++·算法·leetcode·stl
Up九五小庞9 分钟前
用arpspoof实现100%批量切断192.168.110.10 - 192.168.110.100 断网(双向欺骗)--九五小庞
网络·开源
2501_9277730713 分钟前
imx6驱动
linux·运维·服务器
躺柒22 分钟前
读数字时代的网络风险管理:策略、计划与执行04风险指引体系
大数据·网络·信息安全·数字化·网络管理·网络风险管理
hy____12329 分钟前
Linux_进程间通信
linux·运维·服务器
独角鲸网络安全实验室1 小时前
本地信任成“致命漏洞”:数千Clawdbot Agent公网裸奔,供应链与内网安全告急
网络·网关·安全·php·漏洞·clawdbot·信任机制漏洞
郭涤生1 小时前
C++的函数是否可以做到完全覆盖Linux和windows的跨平台
linux·c++·windows
ai_xiaogui1 小时前
Tailscale实现家庭与公司网络双向通信教程:子网路由配置详解
网络·tailscale·双向通信·子网路由配置详解·tailscale双向互访