私人云盘(自动云同步)

一、项目简介

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

/*检查参数*/

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(buf0 == 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 bufBUFSIZ = {};

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");

}

buf0 = 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",argv0);

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(argv2));

if(inet_aton(argv1,&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(argv2));

if(inet_aton(argv1,&(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 小时前
【筑基·059】Linux命令行入门:工程师的操作系统
linux·操作系统·命令行
闲云野鹤在人间2 小时前
docker 入门 | 第5章 网络详解
网络·docker·架构·华为云·php
半仙白桑2 小时前
内核篇第二讲:Linux exec 函数族详解
linux·linux驱动
AR-26710-2 小时前
Linux Day7——建组/用户、umask、Python脚本
linux·python
orange....2 小时前
VMware 双网卡配置:宿主机切换网络时 Ubuntu 固定 IP 访问方案
网络·ubuntu·网络安全
free-elcmacom3 小时前
C语言指针进阶——指针数组模拟二维数组,以及二级指针到底怎么理解
c语言·visual studio code
吴声子夜歌3 小时前
Shell编程实例——内务及管理任务(一)
linux·运维·shell
byte轻骑兵3 小时前
【BlueZ 】input 模块:蓝牙鼠标/键盘等输入设备的基础适配逻辑
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
山下梅子酒2253 小时前
洛谷-入门-B2049
c语言
yi碗汤园3 小时前
MQTT消息队列遥测传输协议
网络·网络协议·unity