当前位置:   article > 正文

使用TFTP协议和UDP/IP模型写一个客户端实现与服务器之间文件的下载与上传

使用TFTP协议和UDP/IP模型写一个客户端实现与服务器之间文件的下载与上传

  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<stdlib.h>
  4. #include<unistd.h>
  5. #include<sys/stat.h>
  6. #include<sys/types.h>
  7. #include<fcntl.h>
  8. #include<pthread.h>
  9. #include<sys/wait.h>
  10. #include<signal.h>
  11. #include<sys/socket.h>
  12. #include<arpa/inet.h>
  13. #include<netinet/in.h>
  14. #include<time.h>
  15. #define ERR_MSG(msg) do{\
  16. fprintf(stderr, "line:%d ", __LINE__);\
  17. perror(msg);\
  18. }while(0)
  19. #define SER_IP "192.168.116.201" //服务器IP:w
  20. #define SER_PORT 69
  21. int do_download(int cfd,struct sockaddr_in sin){
  22. char filename[20] = "";
  23. char buf[516] = {0};
  24. printf("请输入要下载的文件名>>> ");
  25. scanf("%s", filename);
  26. while(getchar()!=10);
  27. short* p1 = (short*)buf;
  28. *p1 = htons(1);
  29. char* p2 = buf+2;
  30. strcpy(p2, filename);
  31. char* p4 = p2+strlen(p2)+1;
  32. strcpy(p4, "octet");
  33. int size = 4+strlen(p2)+strlen(p4);
  34. //发送下载请求
  35. if(sendto(cfd, buf, sizeof(buf), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
  36. {
  37. ERR_MSG("sendto");
  38. return -1;
  39. }
  40. printf("发送成功\n");
  41. socklen_t addrlen=sizeof(sin);
  42. ssize_t res=0;
  43. unsigned short num=1;
  44. int fd=-1;
  45. //int fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0664);//打开对应文件
  46. while(1){
  47. bzero(buf,sizeof(buf));
  48. res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);
  49. if(res<0){
  50. ERR_MSG("recvfrom");
  51. return -1;
  52. }
  53. if(buf[1]==3){//数据包头
  54. if(htons(num)==*(unsigned short*)(buf+2)){//数据包编号确认
  55. num++;
  56. if(fd==-1){
  57. fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0664);
  58. }
  59. printf("数据包编号正确\n");
  60. int ssize=write(fd,buf+4,res-4);//将数据内容写入文件
  61. buf[1]=4;
  62. //*(unsigned short*)(buf+2)=htons(num);
  63. int sres=sendto(cfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin));//发送应答包
  64. if(res<516){//退出
  65. printf("download success\n");
  66. break;
  67. }
  68. }
  69. }else if(buf[1]==5){
  70. printf("收到错误包\n");
  71. fprintf(stderr, "DOWNLOAD_ERROR:%d : %s\n", ntohs(*(short*)(buf+2)), buf+4);
  72. break;
  73. continue;
  74. }
  75. }
  76. close(fd);//关闭文件
  77. return 0;
  78. }
  79. int do_upload(int cfd, struct sockaddr_in sin)
  80. {
  81. //组包准备发送下载请求
  82. char buf[516]="";
  83. char name[20]="";
  84. printf("请输入要上传的文件名>>> ");
  85. scanf("%s",name);
  86. while(getchar()!=10);
  87. unsigned short *p1=(short*)buf; //操作码
  88. *p1=htons(2);
  89. char *p2=buf+2; //文件名
  90. strcpy(p2,name);
  91. char *p3=p2+strlen(p2); //第一个0
  92. *p3=0;
  93. char *p4=p3+1; //模式
  94. strcpy(p4,"octet");
  95. size_t size=2+strlen(p2)+1+strlen(p4)+1; //操作码+文件名+0+模式+0
  96. //发送上传请求
  97. if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
  98. {
  99. ERR_MSG("sendto");
  100. return -1;
  101. }
  102. //创建下载文件并清空
  103. socklen_t addrlen = sizeof(sin);
  104. ssize_t res = 0;
  105. unsigned short num = 0; //记录本地的块编号
  106. int fd=open(name,O_RDONLY);
  107. if(fd < 0)
  108. {
  109. fprintf(stderr,"未找到该文件\n");//原因可能是没有该文件
  110. return -1;
  111. }
  112. //发送上传请求
  113. while(1)
  114. {
  115. res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);
  116. if(4==res){//接受应答包
  117. if(buf[1]==4){
  118. if(htons(num)==*(short*)(buf+2)){
  119. num++;
  120. printf("正确接受应答包%d %d\n",__LINE__,ntohs(*(short*)(buf+2)));
  121. }
  122. }else{
  123. fprintf(stderr,"接受错误\n");
  124. return -1;
  125. }
  126. }
  127. else if(5 == buf[1]) //错误包
  128. {
  129. printf("错误: %d %s\n",ntohs(*(short*)(buf+2)),buf+4);
  130. close(fd);
  131. return -1;
  132. }else if(res<0){
  133. ERR_MSG("recvfrom");
  134. return -1;
  135. }
  136. //发送数据
  137. bzero(buf+4,512);
  138. ssize_t size_r=read(fd,buf+4,512);
  139. buf[1]=3;
  140. //使用应答包的块编号
  141. *(unsigned short*)(buf+2)=htons(num);
  142. res = sendto(cfd,buf,size_r+4,0,(struct sockaddr*)&sin,addrlen);//发送数据包
  143. if(res < 0)
  144. {
  145. ERR_MSG("sendto");
  146. return -1;
  147. }
  148. if(size_r<512)break;//文件读取完毕
  149. }
  150. close(fd);
  151. return 0;
  152. }
  153. int main(int argc, const char *argv[])
  154. {
  155. int cfd = socket(AF_INET, SOCK_DGRAM, 0);
  156. if(cfd < 0)
  157. {
  158. ERR_MSG("socket");
  159. return -1;
  160. }
  161. struct sockaddr_in sin;
  162. sin.sin_family = AF_INET;
  163. sin.sin_port = htons(SER_PORT);
  164. sin.sin_addr.s_addr = inet_addr(SER_IP);
  165. char c = 0;
  166. while(1)
  167. {
  168. system("clear");
  169. printf("---------------------------\n");
  170. printf("----------1. 下载----------\n");
  171. printf("----------2. 上传----------\n");
  172. printf("----------3. 退出----------\n");
  173. printf("---------------------------\n");
  174. c = getchar();
  175. while(getchar() != 10);
  176. switch(c)
  177. {
  178. case '1':
  179. do_download(cfd, sin);
  180. break;
  181. case '2':
  182. do_upload(cfd,sin);
  183. break;
  184. case '3':
  185. goto END;
  186. break;
  187. default:
  188. printf("输入错误,请重新输入\n");
  189. }
  190. printf("输入任意字符清屏>>>");
  191. while(getchar()!=10);
  192. }
  193. END:
  194. close(cfd);
  195. return 0;
  196. }

效果图:

1下载

客户端

服务器端

下载5.png成果 

2上传

客户端

 

服务器端

上传成功 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/285860?site
推荐阅读
相关标签
  

闽ICP备14008679号