目标
c语言+tcp,实现一个server和client。
client可以将本地文件夹上传到server的指定文件路径上;也可以请求server指定路径下的文件夹,将远程内容写到本地。
接口形式如下:
//path 是server上文件夹的绝对地址,localpath下载到本地的地址
int save_file_from_server(char *serverip, int port, char *path, char *localpath);
//localpath是本地上传绝对路径,上传到server的指定路径下,server路径写死在逻辑中。
int upload_file_to_server(char *serverip, int port, char *localpath);
每次有一个client连接,server端就创建一个线程与client进行交互。
代码框架
server
int main(){
listenfd = socket(...);
bind(...);
listen(...);
while(1){
connfd = accept(...);
pthread_create(&tid, NULL, (void *)response, (void *)&connfd)
}
close(listenfd);
return 0;
}
client
上传文件夹
int main(int argc, char **argv)
{
char *serverip = "127.0.0.1";
int port = 11710;
char localpath[] = "...";
char path[] = "...";
upload_file_to_server(serverip, port, path);
return 0;
}
下载文件夹
char *serverip = "127.0.0.1";
int port = 11710;
char path[] = "...";
upload_file_to_server(serverip, port, path);
逻辑
上传文件夹到服务器
从服务器下载文件夹到本地
逻辑不难,难点在
- 如何确定收发数据的类型。是下载命令,还是文件名,还是文件内容?
- 如何确定一个文件已经写完?
一般来说,写文件可以用recv()函数,如下。但是收到完文件后,recv会阻塞住,不会正常结束。
while(recv_len = recv(sockfd, recv_buf, BUF_SZ, 0)){
fwrite(recv_buf, 1, recv_len , fp);
}
解决办法,每次服务器客户端通信,发送BUF_SZ个数据,预留最后五个字节,倒数前四个字节表示这次通信中的有效数据的长度,最后一个数据标志位:表示这次数据的类型。
标志位:
enum
{
FNAME_FIN = 1,//文件名,非这次传输的最后一个文件
FNAME_NFIN, //文件名,这次传输的最后一个文件
FCON_FIN, //文件内容,是这个文件的需最后的数据
FCON_NFIN, //文件内容,不是这个文件的需最后的数据
CMD, //命令
PATH, //文件路径
};
代码
用逻辑写看起来挺麻烦的,但是代码确实简单明了,每个函数最多几十行.
上贡代码:https://github.com/ltCodeW/DirTrans/