TFTP协议:简单文件传输协议,适用于在网络上进行文件传输的一套标准协议,使用UDP传输

代码如下:

  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 #include <stdlib.h>
 11 
 12 #define ERR_MSG(msg) do{\
 13     fprintf(stderr, "line:%d\n", __LINE__);\
 14     perror(msg);\
 15 }while(0)                                       
 16 
 17 #define IP "192.168.8.105"
 18 #define PORT 69
 19 
 20 int download(int sfd, struct sockaddr_in sin);
 21 int upload(int sfd, struct sockaddr_in sin);
 22 
 23 
 24 int main(int argc, const char *argv[])
 25 {
 26     //创建报时套接字 
 27     int sfd = socket(AF_INET,SOCK_DGRAM,0);
 28     if(sfd<0)
 29     {
 30         ERR_MSG("socket");
 31         return -1;
 32     }
 33 
 34     //填充服务器自身的地址信息
 35     struct sockaddr_in sin;
 36     sin.sin_family = AF_INET;
 37     sin.sin_port = htons(PORT);
 38     sin.sin_addr.s_addr = inet_addr(IP);
 39 
 40     char choose=0;
 41     while(1)
 42     {
 43         printf("****************************\n");
 44         printf("******1.download************\n");
 45         printf("******2.upload**************\n");
 46         printf("******3.exit****************\n");
 47         printf("****************************\n");
 48         printf("请输入>>>");
 49         choose = getchar();
 50         while(getchar()!=10);
 51 
 52         switch(choose)
 53         {
 54         case '1':
 55             download(sfd, sin);
 56             break;
 57         case '2':
 58             upload(sfd, sin);
 59             break;
 60         case '3':
 61             goto END;
 62         }
 63 
 64     }
 65 
 66 END:
 67     return 0;
 68 }
 69 
 70 int upload(int sfd, struct sockaddr_in sin)
 71 {
 72     char buf[600] = "";
 73     ssize_t res = 0;
 74 
 75     char filename[20] = "";
 76     printf("请输入要上传的文件名>>>");
 77     scanf("%s", filename);
 78     while(getchar()!=10);
 79 
 80     //判断文件是否存在
 81     int fd = open(filename, O_RDONLY);
 82     if(fd < 0)
 83     {
 84         ERR_MSG("open");
 85         return -1;
 86     }
 87 
 88     int size = sprintf(buf, "%c%c%s%c%s%c", 0, 2, filename, 0, "octet", 0);
 89 
 90     //发送上传请求
 91     if(sendto(sfd, buf, size, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
 92     {
 93         ERR_MSG("sendto");
 94         return -1;
 95     }
 96 
 97     socklen_t addrlen = sizeof(sin);
 98     while(1)
 99     {
100         bzero(buf, sizeof(buf));
101         //接收数据包
102         res = recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&sin, &addrlen);
103         if(res < 0)
104         {
105             ERR_MSG("recvfrom");
106             return -1;
107         }
108         printf("buf[0]:%d buf[1]:%d 操作码:%#x 快编号:%d\n", \
109                 buf[0], buf[1], ntohs(*(short*)buf), ntohs(*(short*)(buf+2)));
110 
111         //解析数据包
112         int code = ntohs(*(short*)buf);
113         int num = ntohs(*(short*)(buf+2));
114 
115         if(4 == code)
116         {
117             bzero(buf, sizeof(buf));
118 
119             //组数据包
120             *(short*)buf = htons(3);
121             *(short*)(buf+2) = htons(num+1);
122 
123             res = read(fd, buf+4, 512);
124             if(res < 0)
125             {
126                 ERR_MSG("write");
127                 return -1;
128             }
129 
130             //上传文件
131             if(sendto(sfd, buf, res+4, 0, (struct sockaddr*)&sin, addrlen) < 0)
132             {
133                 ERR_MSG("sendto");
134                 return -1;
135             }
136             if(res < 512)
137             {
138                 printf("文件上传成功\n");
139                 break;
140             }
141         }
142 
143     }
144  
145     return 0; 
146 }
147 
148 
149 int download(int sfd, struct sockaddr_in sin)
150 {
151     //发送下载请求
152     char buf[600] = "";
153     ssize_t res = 0;
154     char filename[20] = "";
155 
156     printf("请输入要下载的文件名>>>");
157     scanf("%s", filename);
158     while(getchar()!=10);
159 
160     int size = sprintf(buf, "%c%c%s%c%s%c", 0, 1, filename, 0, "octet", 0);
161 
162     //发送下载协议
163     if(sendto(sfd, buf, size, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
164     {
165         ERR_MSG("sendto");
166         return -1;
167     }
168 
169     //打开一个文件,用于存储下载到的数据
170     int fd=-1, flag = 0;
171 
172     socklen_t addrlen = sizeof(sin);
173     unsigned short num = 0;
174     while(1)
175     {
176         bzero(buf, sizeof(buf));
177         //接收数据包
178         res = recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&sin, &addrlen);
179         if(res < 0)
180         {
181             ERR_MSG("recvfrom");
182             return -1;
183         }
184 
185              if(3 == buf[1])         {
186             if(0 == flag)
187             {
188                 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0664);
189                 if(fd < 0)
190                 {
191                     ERR_MSG("open");
192                     return -1;
193                 }
194                 flag = 1;
195             }
196 
197 
198             if(htons(num+1) == *(unsigned short*)(buf+2))
199             {
200                 if(write(fd, buf+4, res-4) < 0)
201                 {
202                     ERR_MSG("write");
203                     break;
204                 }
205 
206                 //回复ACK
207                 buf[1] = 4;
208                 if(sendto(sfd, buf, 4, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
209                 {
210                     ERR_MSG("sendto");
211                     break;
212                 }
213 
214                 //判断数据是否<512
215                 if(res-4 < 512)
216                 {
217                     printf("文件 %s 下载完毕\n", filename);
218                     break;
219                 }
220 
221                 num++;
222             }
223         }
224         else if(5 == buf[1])
225         {
226             printf("ERROR: %d %s\n", ntohs(*(short*)(buf+2)), buf+4);
227             break;
228         }
229     }
230 
231     close(fd);
232     return 0;
233 }
234 
235 
~                                                                                                        
~                                                                                                        
~                                                                                                        

结果如图:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值