概述
本质:文件的上传和下载本质实际上是对文件的读写操作
上传:将需要上传的文件名发给客户端然后将文件在客户端打开并循环读取至文件末尾,边读边写至和服务器建立的连接管道,服务器接收到文件名后创建一个同名文件,然后打开该文件将客户端写至连接管道的内容读出来并将其写入文件内。这即是文件的上传过程
下载:原理和文件上传类似,只是读写的顺序和目标调换一下
注意:怎样让服务器知道客户端是下载文件还是上传文件,需要客户端发送给服务器一个指令以便让服务器知道客户端想做什么,可以封装一个结构体,成员分别为指令和需要上传或者下载的文件名。
下面直接上代码,代码连在一块的,注释在代码里
服务器端:
头文件
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
tcp服务器封装
typedef struct fileinfo{
char filename[64];
int flag;//判断是下载还是上传指令
}f_info;
int serverinit()//服务器的封装
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0)
{
perror("sockfd");
return -1;
}
printf("%dn",sockfd);
struct sockaddr_in saddr;
bzero(&saddr,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr("192.168.3.72");
saddr.sin_port = htons(8888);
int ret = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if(ret < 0)
{
perror("bind");
return -1;
}
printf("绑定成功 ret =%dn",ret);
ret = listen(sockfd,5);
if(ret < 0)
{
perror("listen");
return -1;
}
printf("listen.....n");
return sockfd;
}
int main(int argc, char *argv[])
{
int sockfd = serverinit();
struct sockaddr_in caddr;
socklen_t len = sizeof(caddr);
int connfd = accept(sockfd,(struct sockaddr*)&caddr,&len);//接受客户端的连接
if(connfd < 0 )
{
perror("accept");
return -1;
}
printf("connect success ip:%s ----- port:%u n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
f_info info;
//char filename[64] = {0};
int ret = read(connfd,&info,sizeof(info));//接收带有文件上传或下载的结构体信息
if(ret < 0)
{
perror("read");
return -1;
}
switch(info.flag)//判断指令是上传或下载
{
case 1://上传
{
int rfd = open(strcat(info.filename,"1"),O_RDWR | O_CREAT | O_TRUNC,0664);
bzero(info.filename,sizeof(info.filename));
while((ret = read(connfd,info.filename,sizeof(info.filename))) > 0)//读取客户端发送过来的文件内容
{
printf("%dn",ret);
write(rfd,info.filename,ret);//写到创建好的文件里
}
break;
}
case 2:下载
{
int wfd = open(info.filename,O_RDONLY);
bzero(info.filename,sizeof(info.filename));
if(wfd < 0)
{
perror("open");
return -1;
}
while( (ret = read(wfd,info.filename,sizeof(info.filename))) > 0)//从服务器本地的文件读取内容
{
write(connfd,info.filename,ret);//写至和客户端建立好的连接管道
}
break;
}
}
close(connfd);
close(sockfd);
return 0;
}
客户端:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
tcp客户端的封装
typedef struct fileinfo{
char filename[64];
int flag;//判断是下载还是上传
}f_info;
int clientcon(char *addr,unsigned short port)
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0)
{
perror("sockfd");
return -1;
}
printf("%dn",sockfd);
struct sockaddr_in saddr;
bzero(&saddr,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr(addr);
saddr.sin_port = htons(port);
int ret = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if(ret < 0)
{
perror("connect");
return -1;
}
printf("connect successn");
return sockfd;
}
int main(int argc, char *argv[])
{
int sockfd = clientcon("192.168.3.72",8888);
f_info info;
printf("%dn",sockfd);
//int op;
int ret;
strcpy(info.filename,"0");
info.flag = 0;
char buf[64] = {0};
int fd = 0;
printf("---------欢迎来到文件传输系统--------n");
printf("1.上传文件------2.下载文件------n");
scanf("%d",&info.flag);
switch(info.flag)
{
case 1://客户端上传
{
getchar();
printf("请输入要上传的文件名:n");
fgets(info.filename,64,stdin);
info.filename[strlen(info.filename) - 1] = '