2023年3月14日作业

该代码实现了一个简单的UDPTFTP客户端,用于从指定IP和端口下载文件。程序首先创建一个UDP套接字,然后向服务器发送下载请求,接收并处理数据包,最后将接收到的数据写入文件。在接收过程中,程序会检查数据包的正确性并发送ACK确认。
摘要由CSDN通过智能技术生成

代码段

  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/socket.h>
  4 #include <arpa/inet.h>
  5 #include <netinet/in.h>
  6 #include <string.h>
  7 #include <unistd.h>
  8 #include<sys/stat.h>
  9 #include<fcntl.h>
 10 
 11 #define ERR_MSG(msg) do{\
 12     fprintf(stderr, "line:%d ", __LINE__);\
 13     perror(msg);\
 14 }while(0)
 15 
 16 #define DIRNAME "5.png"
 17 #define PORT 69            //1024~49151
 18 #define IP  "192.168.31.201"    //IP地址,本机IP ifconfig
 19 
 20 int main(int argc, const char *argv[])
 21 {
 22     //创建报式套接字
 23     int sfd = socket(AF_INET, SOCK_DGRAM, 0);
 24     if(sfd < 0)
 25     {
 26         ERR_MSG("socket");
 27         return -1;
 28     }
 29     printf("socket create success  sfd=%d __%d__\n", sfd, __LINE__);
 30 
 31 
 32     //允许端口快速被复用
 33 
 34     //填充服务器的地址信息结构体 AF_INET : man 7 IP
 35     struct sockaddr_in sin;
 36     sin.sin_family      = AF_INET;  //必须填AF_INET;
 37     sin.sin_port        = htons(PORT);  //服务器绑定的端口,网络字节序
 38     sin.sin_addr.s_addr = inet_addr(IP);    //服务器的IP ifconfig
 39 
 40     //数据包最大为操作码+块编号+数据 = 2+2+512 = 516 bytes
 41     char buf[516] = "";
 42 
 43     //发送下载请求
 44     //组tftp协议包
 45     int size = sprintf(buf,"%c%c%s%c%s%c",0,1,DIRNAME,0,"octet",0);
 46 
 47     //发送协议包
 48     if(sendto(sfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
 49     {
 50         ERR_MSG("bind");
 51         return -1;
 52     }
 53 
 54     //创建文件用于接收文件
 55     int fd=open(DIRNAME,O_WRONLY|O_CREAT|O_TRUNC,0775);
 56 
 57     //循环接收数据包
 58     ssize_t res = 0;
 59     ssize_t flag = 0;
 60     socklen_t addrlen = sizeof(sin);
 61     struct sockaddr_in rcvAddr;    //存储获取到的数据包是从谁那里来的
 62     unsigned short tt=0;
 63     while(1)
 64     {
 65         bzero(buf, sizeof(buf));
 66 
 67         //收数据包
 68         res = recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&sin, &addrlen);
 69         if(res < 0)
 70         {
 71             ERR_MSG("recvfrom");
 72             return -1;
 73         }
 74 
 75         //判断是否成功接受数据包
 76 
 77         if(buf[1] == 3)
 78         {
 79             if(htons(tt+1) == *(unsigned short*)(buf+2))
 80             {
 81                 tt++;
 82                 //将数据写入到文件中
 83                 flag=write(fd,buf+4,res-4);
 84                 if(flag < 0)
 85                 {
 86                     ERR_MSG("write");
 87                     return -1;
 88                 }
 89 
 90 
 91                 short a = (short)buf[2];
 92                 //ACK 返回操作码以及块编号
 93                 buf[1] = 4;
 94 
 95                 if(sendto(sfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
 96                 {
 97                     ERR_MSG("sendto");
 98                     return -1;
 99                 }
100 
101 
102             }
103             if(res < 516)
104             {
105                 printf("文件信息接收完毕\n");
106                 return -1;
107             }
108         }
109 
110             else if(buf[1] == 5)                                                                                                                                                                                                                                                                                    
111             {
112                 printf("错误码:code:[%c]\tmsg[%s]\n",*(unsigned short*)(buf+2),buf+4);
113             }
114         flag = 0;
115     }
116 
117     //关闭所有文件描述符
118     close(sfd);
119     return 0;
120 }

运行结果

ubuntu@ubuntu:udp$ gcc udpfwd.c 
ubuntu@ubuntu:udp$ ./a.out 
socket create success  sfd=3 __29__
文件信息接收完毕
ubuntu@ubuntu:udp$ eog 5.png 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

malingshu404

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值