作业--day33
2023-12-20 10:10:47
基于UDP的TFTP文件上传
#include <myhead.h>
#define PORT 69
#define IP "192.168.125.59"
int down(const char *);
int up(const char *);
int main(int argc, const char *argv[])
{
while(1){
system("clear");
//打印菜单
puts("***************功能**************");
puts("*************1. 下载*************");
puts("*************2. 上传*************");
puts("*************3. 退出*************");
int choose = -1;
char filename[128] = "";
scanf("%d", &choose);
switch(choose){
case 1:
{
printf("输入文件名>>");
scanf(" %[^\n]", filename);
if(down(filename) == -1){
return -1;
}
}
break;
case 2:
{
printf("输入文件名>>");
scanf(" %[^\n]", filename);
if(up(filename) == -1){
return -1;
}
}
break;
case 3:
return 0;
default:
puts("输入错误");
}
}
return 0;
}
int down(const char *filename){
int cfd = socket(AF_INET, SOCK_DGRAM, 0);
if(cfd == -1){
perror("socket error");
return -1;
}
char buf[516];
bzero(buf, sizeof(buf));
//设置为下载(读)操作
buf[1] = 1;
//将文件名加入协议包中
strcpy(buf+2, filename);
//模式
char mod[6] = "octet";
//将模式字符串加入协议包中
strcpy(buf+2+strlen(filename)+1, mod);
//统计协议包字节数总大小
int size = 2+strlen(filename)+1+strlen(mod)+1;
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
socklen_t socklen = sizeof(sin);
if(sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) == -1){
perror("sendto error");
return -1;
}
puts("请求成功");
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
while(1){
bzero(buf, sizeof(buf));
int res = -1;
if((res = recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &socklen)) == -1){
perror("recvfrom error");
return -1;
}
if(buf[1] == 3){
if(res < 516){//若接收字节数小于516则将数据写入后结束下载
write(fd, buf+4, res-4);
buf[1] = 4;
sendto(cfd, buf, 4, 0, (struct sockaddr *)&sin, sizeof(sin));
break;
}else{
write(fd, buf+4, 512);
buf[1] = 4;
sendto(cfd, buf, 4, 0, (struct sockaddr *)&sin, sizeof(sin));
}
}else{
printf("未知错误,错误码: %d\n", buf[3]);
close(fd);
close(cfd);
return -1;
}
}
close(fd);
close(cfd);
return 0;
}
int up(const char *filename){
int cfd = socket(AF_INET, SOCK_DGRAM, 0);
if(cfd == -1){
perror("socket error");
return -1;
}
char buf[516];
bzero(buf, sizeof(buf));
//设置为上传(写)操作
buf[1] = 2;
//将文件名加入协议包中
strcpy(buf+2, filename);
//模式
char mod[6] = "octet";
//将模式字符串加入协议包中
strcpy(buf+2+strlen(filename)+1, mod);
//统计协议包字节数总大小
int size = 2+strlen(filename)+1+strlen(mod)+1;
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
socklen_t socklen = sizeof(sin);
if(sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) == -1){
perror("sendto error");
return -1;
}
puts("请求成功");
int fd = open(filename, O_RDONLY);
//用于表示传输块的编号
short block_num = 0;
//用于操作ACK应答包的数据块的编号
short * const p = (short *)(buf+2);
int res = -1;
while(1){
recvfrom(cfd, buf, 4, 0, (struct sockaddr *)&sin, &socklen);
//printf("num = %d, block_num = %d\n", buf[1], block_num);
if(buf[1] == 4){
//使用指针p提取数据时需要注意字节序的问题
if(ntohs(*p) == 0 || block_num == ntohs(*p)){
buf[1] = 3;
res = read(fd, buf+4, 512);
*p = htons(++block_num);
size = res + 4;
if(res == 0){
break;
}else{
sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin));
}
}else{
buf[1] = 3;
sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin));
}
}else{
printf("未知错误,错误码: %d\n", buf[3]);
close(fd);
close(cfd);
return -1;
}
}
close(fd);
close(cfd);
return 0;
}
思维导图
文章来源:https://blog.csdn.net/qq_39831963/article/details/135092517
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!