私人云盘(自动云同步)

一、项目简介

模仿小米的云服务,实现一个通过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

相关推荐
乔巴不是狸猫13 分钟前
第11周作业
linux
嵌入式科普40 分钟前
嵌入式科普(24)从SPI和CAN通信重新理解“全双工”
c语言·stm32·can·spi·全双工·ra6m5
Bessssss1 小时前
centos权限大集合,覆盖多种权限类型,解惑权限后有“. + t s”问题!
linux·运维·centos
silver6872 小时前
Linux 下的 GPT 和 MBR 分区表详解
linux
lqqjuly2 小时前
特殊的“Undefined Reference xxx“编译错误
c语言·c++
R-sz2 小时前
14: curl#6 - “Could not resolve host: mirrorlist.centos.org; 未知的错误“
linux·python·centos
code_abc3 小时前
Shell 脚本编程基础:变量
linux
星如雨落3 小时前
Linux shell脚本对常见图片格式批量转换为PDF文件
linux·shell
冰红茶兑滴水3 小时前
云备份项目--工具类编写
linux·c++