目录
1.要实现的功能
要实现的功能
客户端 服务器端
我们规定在输入指令以后要加上一个'#' 1.监听是否有人链接
发送指令 “put 1.txt#” 上传文件 2.接受链接
"get 1.txt#" 下载文件 3.接受指令“put 1.txt#”
"quit#" 退出 “get 1.txt#”
1.解析空格之前的是命令 char cmd[20]="get" 1.解析你recv的字符串 2.解析空格之后#之前 char filename[20]="1.txt" 2.解析空格之后#之前
3.通过strcmp来判断输入的命令是否正确 if(strcmp(cmd,"put"))
if(strcmp(cmd,"put")) 1.接收文件大小
1.获得文件的大小 int len ==stat() 12340 2.解析12340
2.将文件大小传送过去 "filesize=12340#" 3.接受文件内容并保存
3.将文件的内容发送过来 //1.从socket当中读取数据到buf中
//1.先将文件的内容读取给buf //2.将buf中的数据写到文件中
//2.将buf通过socket发送过去
2.流程图
客户端
开始->请求链接->输入buf->send服务器->buf==“quit” //-y>关闭socket对象//-n>buf中解析出cmd,filename->cmd==“put”//-y>上传文件//-n>cmd="get"//-y>下载文件//-n>error
服务器
开始->监听是否有人链接->接受链接生成newfd->recv客户端给buff->buf==“quit” //-y>关闭socket对象//-n>buf中解析出cmd,filename->cmd==“put”//-y>下载文件//-n>cmd="get"//-y>上传文件//-n>error
3.步骤
1.请求链接,监听
//一.请求链接
int tcp_connect(const char *ip,int port)
{
//创建socket对象(流式套接字TCP)
int socket_fd = socket(AF_INET,SOCK_STREAM,0);//参数是地址组,套接字类型,第三个通常置为0
if(sicket_fd < 0)
{
perror("socket error");
return -1;
}
printf("socket success\n");
//设置对方的ip地址和端口号
//定义一个结构体并为其赋值
struct sockaddr_in server;
memset(&server,'\0',sizeof(server));//清空结构体
server.sin_family =AF_INET; //ipv4协议
server.sin_port = htons(port);//端口号
server.sin_addr.s_addr = inet_addr(ip);//网络字节序
//请求链接
if(connect(socket_fd,(struct sockaddr *)&server,sizeof(server))<0)
{
perror("connect error\n");
return -1;
}
printf("connect success\n");
return socket_fd;
}
监听
int tcp_socket(const char *ip, int port)
{
//创建socket
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == socket_fd)
{
perror("create socket error");
return -1;
}
printf("socket创建成功\n");
//指定端口及ip地址
struct sockaddr_in server;
memset(&server,'\0',sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip);
//绑定ip地址及端口
if(bind(socket_fd,(struct sockaddr *)&server,sizeof(server)) < 0)
{
perror("bind error");
return -1;
}
printf("bind ok\n");
//监听是否有人连接
if(listen(socket_fd,5) < 0)
{
perror("listen error");
return -1;
}
printf("listen ok\n");
return socket_fd;
}
2.搭建号服务器后具体操作
客户端
int main(int argc, const char *argv[])
{
//入参判断
if(argc<3)
{
perror("argc error");
return -1;
}
//连接服务器返回链接后的socket对象
int fd = tcp_connect(argv[1],atoi(argv[2]));//atoi是把字符转成整形
//buf中输入值
char buf[100] = {0};
char cmd[100] = {0};
char filename[100] = {0};
fgets(buf,sizeof(buf),stdin);//键盘键入
send(fd,buf,strlen(buf),0);//发送到服务器
parseStr(buf,cmd,filename);//解析键入的字符串
if(strncmp(cmd,"quit",4)==0)break;
printf("cmd=%s",cmd);
printf("fliename=%s",filename);
DataHandler(fd,cmd,filename);//数据处理(上传下载文件)
//关闭socket
close(fd);
return 0;
}
服务器
int main(int argc, const char *argv[])
{
//入参判断
if(argc<3)
{
perror("argc error");
return -1;
}
//连接服务器返回链接后的socket对象
int newfd = tcp_tocket(argv[1],atoi(argv[2]));//atoi是把字符转成整形
//buf中输入值
char buf[100] = {0};
char cmd[100] = {0};
char filename[100] = {0};
recv(newfd,buf,sizeof(buf),0);//接收
parseStr(buf,cmd,filename);//解析命令和文件名
if(strncmp(buf,"quit",4)==0)
break;
printf("cmd=%s",cmd);
printf("filename=%s",filename);
DataHandler(newfd,cmd,filename);//数据处理函数
//关闭socket
close(newfd);
return 0;
}
3.解析字符串的函数
//编写一个子函数,根据输入的字符串进行解析命令和文件名
void parseStr(char buf[],char cmd[],char filename[])
{
// 解析命令
int i = 0;
while(buf[i]!='#')
{
if(buf[i]==' ')
break;
cmd[i]=buf[i];
i++;
}
cmd[i]='\0';
//解析文件名
if(buf[i]!=' ')//防止有别的符号
return;
i++;//把空格跳过去
int j=0;
while(buf[i+j]!='#')
{
filename[j]=buf[i+j];
j++;
}
filename[j]='\0';
}
4.数据处理函数
客户端
int DataHandler(int fd,char * cmd,char * filename)
{
if(strncmp(cmd,"put",3)==0)
{
//上传文件
upload(fd,filename);
}
else if(strncmp(cmd,"get",3)==0)
{
//下载文件
download(fd,filename);
}
else
{
printf("命令有误\n");
}
}
服务器
int DataHandler(int fd,char * cmd,char * filename)
{
if(strncmp(cmd,"get",3)==0)
{
//下载文件
download(fd,filename);
}
else if(strncmp(cmd,"get",3)==0)
{
//上传文件
upload(fd,filename);
}
else
{
printf("命令有误\n");
}
}
5.上传下载
//上传
int upload(int fd,char * filename)
{
//获得文件的大小
struct stat statbuf;
if(stat(filename,&statbuf)<0)
{
perror("stat error");
return -1;
}
printf("filesize=%d\n",statbuf.st_size);
//2.将文件大小发送过去
char filesize[20]={'\0'};
sprintf(filesize,"%d#",statbuf.st_size);
int n=send(fd,filesize,strlen(filesize),0);
printf("filesize=%s n=%d\n",filesize,n);
sleep(1);
//以只读方式打开文件
int fr=open(filename,O_RDONLY);
if(fr<0)
{
perror("open error");
return -1;
}
char bufstr[1024]={'\0'};
while(1)
{
memset(bufstr,'\0',sizeof(bufstr));
//从文件中读取数据到bufstr
int n=read(fr,bufstr,sizeof(bufstr));
if(n==0)
{
printf("文件上传成功\n");
break;
}
//将bufstr写入到socket中
send(fd,bufstr,n,0);
}
//关闭文件
close(fr);
}
//下载
int download(int fd,char * filename)
{
//接收文件大小
char buf[20]={'\0'};
recv(fd,buf,sizeof(buf),0);
//将字符串转换成整数
int filesize=atoi(buf);
printf("filesize=%d\n",filesize);
//以只写的方式打开文件,文件不存在则新建,文件存在则清空文件中的内容
int fw=0;
fw=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0777);
if(fw<0)
{
perror("open error");
return -1;
}
int total = 0;
char bufstr[1024]={'\0'};
while(1)
{
if(total>=filesize)
{
printf("文件保存成功\n");
break;
}
//从socket中读取数据
int n=recv(fd,bufstr,sizeof(bufstr),0);
total+=n;
//将读取到的数据写入到文件中
write(fw,bufstr,n);
}
close(fw);
}