项目介绍:
模拟FTP原理:客户端连接服务器后,向服务器发送一个文件。文件名可以通过参数指定,服务器端接收客户端传来的文件(文件名随意),如果文件不存在自动创建文件,如果文件存在,那么清空文件然后写入。
项目技术点:
TCP客户端和服务器的搭建
目录IO获取路径下的文件名用于展示
标准IO或文件IO的打开,读取以及写入操作文件
TCP协议需要考虑如何防止粘包的发生(建议发送和接收的大小一致)
参考内容:
(1)client.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
int main(int argc, const char* argv[])
{
//1.socket
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0)
{
perror("socket is error:");
return -1;
}
//绑定套接字
struct sockaddr_in saddr,caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[2]));
saddr.sin_addr.s_addr = inet_addr(argv[1]);
char buf[128];
if(connect(sockfd,(struct sockaddr *)&saddr,sizeof(saddr)) < 0)
{
perror("connect is error:");
return -1;
}
while(1)
{
//选择功能
printf("功能1--------list--------\n");
printf("功能2--------put--------\n");
printf("功能3--------get--------\n");
printf("功能4--------quit-------\n");
printf("请选择功能:\n");
int num;
scanf("%d",&num);
//显示该目录下的所有文件
if(num == 1)
{
send(sockfd,&num,4,0);
while(1)
{
char stu[128];
int flag = 1;
send(sockfd,&flag,4,0);
int res = recv(sockfd,stu,sizeof(stu),0);
printf("%s\n",stu);
if(stu[0] == 0)
{
break;
}
}
}
//上传文件
else if(num == 2)
{
printf("请输入要上传的文件名\n");
send(sockfd,&num,4,0);
char stu[512];
scanf("%s",stu);
//以只读形式打开已有文件
int fd = open(stu,O_RDONLY);
//判断文件是否存在
if(access(stu,F_OK) == -1)
{
printf("输入文件不存在,请重新输入:\n");
break;
}
while(1)
{
char s[512];
int flag = 0;
int res = read(fd,s,sizeof(s));
if(res == 0){break;}
send(sockfd,s,sizeof(s),0);
recv(sockfd,&flag,4,0);
}
printf("上传成功\n");
}
//下载文件
else if(num == 3)
{
send(sockfd,&num,4,0);
printf("请输入要下载的文件\n");
char c[32];
scanf("%s",c);
if(c[strlen(c)-1] == '\n')
c[strlen(c)-1] = '\0';
send(sockfd,c,32,0);
//创建新的文件并打开
int fd = open(c,O_WRONLY | O_TRUNC | O_CREAT,0666);
char ct[256]="";
while(1)
{
int flag = 1;
int res = recv(sockfd,ct,sizeof(ct)-1,0);
if(strlen(ct)==0)
{
break;
}
//写入新的文件内,下载成功
write(fd,ct,strlen(ct));
}
printf("下载成功\n");
//关闭文件
close(fd);
}
//退出(仅客户端),服务端仍然等待其他客户端连接
else if(num == 4)
{
send(sockfd,&num,4,0);
}
else
{
printf("抱歉,您输入的数字有误,请重新输入\n");
}
}
close(sockfd);
return 0;
}
(2)server.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
#include <dirent.h>
typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
int main(int argc, const char* argv[])
{
//1.socket
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0)
{
perror("socket is error:");
return -1;
}
//绑定套接字
struct sockaddr_in saddr,caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
int len = sizeof(caddr);
char buf[128];
if(bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr)) < 0)
{
perror("bind is error:");
return -1;
}
if(listen(sockfd,5) < 0)
{
perror("listen is error:");
return -1;
}
while(1)
{
printf("-------等待客户端连接-----------\n");
int acceptfd = accept(sockfd,(struct sockaddr *)&caddr,&len);
if(acceptfd < 0)
{
perror("accept is error:");
return -1;
}
printf("-------客户端连接成功------------\n");
while(1)
{
int num;
printf("请选择功能\n");
int res = recv(acceptfd,&num,sizeof(num),0);
if(res < 0)
{
perror("recv is error:");
return -1;
}
else if(res == 0)
{
printf("recv is exit:\n");
break;
}
else
{
if(num == 1)
{
struct dirent *file = NULL;
DIR *dp = opendir("./");
if (dp == NULL)
{
perror("opendir is error:");
return -1;
}
while((file = readdir(dp)) != NULL)
{
if(file->d_name[0] == '.' )
{
continue;
}
int flag = 0;
recv(acceptfd,&flag,4,0);
send(acceptfd,file->d_name,128,0);
}
int flag = 0;
recv(acceptfd,&flag,4,0);
char bb[128] ={0};
send(acceptfd,bb,128,0);
}
else if(num == 2)
{
//新建文件并打开
int fd = open("./3",O_WRONLY | O_TRUNC | O_CREAT,0666);
while(1)
{
char ss[512];
int flag = 1;
//接收内容
int res = recv(acceptfd,ss,sizeof(ss),0);
if(res == 0){break;}
//写入
write(fd,ss,strlen(ss));
send(acceptfd,&flag,4,0);
}
//关闭文件
close(fd);
}
else if(num == 3)
{
printf("进入功能:\n");
char c[32] = {0};
recv(acceptfd,c,32,0);
printf("%s\n",c);
int fd = open(c,O_RDONLY);
while(1)
{
char st[256]="";
int flag=1;
int res = read(fd,st,sizeof(st)-1);
//阻塞性接收并传送回文件数据与内容
if(res == 0)
{
char dt[256]="";
send(acceptfd,dt,sizeof(dt)-1,0);
break;
}
if(flag==1)
{
send(acceptfd,st,sizeof(st)-1,0);
}
}
}
else if(num == 4)
{
break;
}
else
{
printf("抱歉,您输入的数字有误,请重新输入\n");
}
}
}
}
close(sockfd);
return 0;
}