1. 基于UDP的TFTP文件传输
#include<myhead.h>//上传int do_upload(int cfd, struct sockaddr_in sin)
{//定义变量存储下载请求包char buf[516] = "";//定义变量存储文件名char fileName[40] = "";int rfd = -1;printf("请输入文件名:");scanf("%s", fileName);getchar();if((rfd=open(fileName, O_RDONLY)) == -1){perror("open error");return -1;}//发送读写请求short *ptr_opcode = (short *) buf;char *ptr_filename = (char *) (buf + 2);char *ptr_mode = ptr_filename + strlen(fileName)+1;*ptr_opcode = htons(2);strcpy(ptr_filename, fileName); strcpy(ptr_mode, "octet");size_t size_req = 2 + strlen(fileName) + 1 + strlen(ptr_mode) + 1;socklen_t socklen = (socklen_t)sizeof(sin);printf("buf=%s\n", buf);if(sendto(cfd, buf, size_req, 0, (struct sockaddr *)&sin, socklen) == -1){perror("sendto error");return -1;}printf("send requtest to svc successfully\n");//recvfrom svc for ack packageshort *ptr_ack = (short *)buf;short *ptr_bnum = ptr_ack + 2;int size_ack = sizeof(ptr_ack) + sizeof(ptr_bnum);bzero(buf, sizeof(buf));recvfrom(cfd, buf, size_ack ,0, (struct sockaddr *)&sin, &socklen);int ack_rcv = ntohs(*ptr_ack);int bnum_rcv = ntohs(*ptr_bnum);printf("1. ack=%d, bnum=%d\n", ack_rcv, bnum_rcv);printf("2. sin_port=%d, sin_ip=%s, buf=%s\n", ntohs(sin.sin_port), inet_ntoa(sin.sin_addr), buf);if(ack_rcv != 4 || bnum_rcv !=0){printf("3. ack error\n");return -1;}char *ptr_data = buf + 4;char rbuf[512] = "";int bnum = 1;while(1){printf("> bnum = %d\n", bnum);bzero(buf, sizeof(rbuf));int res = read(rfd, rbuf, sizeof(rbuf));printf("4.read res=%d, rbuf=%s\n",res, rbuf);//组装*ptr_opcode = htons(3);*ptr_bnum = htons(bnum);printf("5. *ptr_opcode=%d", ntohs(*ptr_opcode));strcpy(ptr_data, rbuf);printf("6. buf=%s\n", buf);//send to datasendto(cfd, buf, sizeof(buf),0, (struct sockaddr *)&sin, socklen);// recv ack bzero(buf, sizeof(buf));recvfrom(cfd, buf, size_ack ,0, (struct sockaddr *)&sin, &socklen);ack_rcv = ntohs(*ptr_ack);bnum_rcv = ntohs(*ptr_bnum);printf("7. ack=%d, bnum=%d\n", ack_rcv, bnum_rcv);printf("8. sin_port=%d, sin_ip=%s, buf=%s\n", ntohs(sin.sin_port), inet_ntoa(sin.sin_addr), buf);if(ack_rcv != 4 || bnum_rcv != bnum) {printf("9. ack error\n");return -1;}if(res < sizeof(buf) -4){printf("upload finished\n");break;}bnum ++;}close(rfd);close(cfd);return 0;}//实现下载功能
int do_download(int cfd, struct sockaddr_in sin)
{//定义变量存储下载请求包char buf[516] = "";//定义变量存储文件名char fileName[40] = "";int wfd = -1;printf("请输入文件名:");scanf("%s", fileName);getchar();if((wfd=open(fileName, O_WRONLY | O_CREAT | O_TRUNC , 0664 )) == -1){perror("open error");return -1;}//组装请求包short *p1 = (short *)buf;*p1 = htons(1); //表明要下载char *p2 = buf+2; //文件名段strcpy(p2, fileName);char *p4 = p2+strlen(p2)+1; //模式段strcpy(p4, "octet");int size = 4 + strlen(p2) + strlen(p4); //要发送数据的大小//向服务器发送下载请求if(sendto(cfd, buf, size, 0, (struct sockaddr*)&sin, sizeof(sin)) == -1){perror("sendto error");return -1;}printf("请求成功\n");//循环接收回复服务器发来的消息while(1){short *popcode = (short *)buf;short *pbnum =(short *)(buf + 2);char *pdata = (char *)(buf + 4);recvfrom(cfd, buf, sizeof(buf), 0,NULL, NULL);//判断操作码if( ntohs(*popcode) == 3 ){int datalen =strlen(pdata);printf("datalen=%d, data=%s\n", datalen, pdata );write(wfd, pdata, datalen );//发送确认*popcode == 4;sendto(cfd, buf, sizeof(short), 0, (struct sockaddr*)&sin, sizeof(sin));if(datalen<512){break;}}}close(wfd);close(cfd);}int main(int argc, const char *argv[])
{if(argc != 2){printf("input error\n");printf("usage:./a.out ip\n");return -1;}//1、创建套接字int cfd = socket(AF_INET, SOCK_DGRAM, 0);if(cfd == -1){perror("socket error");return -1;}//2、填充服务器地址信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(69);sin.sin_addr.s_addr = inet_addr(argv[1]);int mune = -1;while(1){system("clear"); //清屏printf("\t\t======1、下载=======\n");printf("\t\t======2、上传=======\n");printf("\t\t======0、退出=======\n");printf("请输入功能:");scanf("%d", &mune);getchar();//多分支选择switch(mune){case 1:{do_download(cfd, sin);}break;case 2:{do_upload(cfd, sin);}break;case 0:goto POS;default:printf("输入功能有误,请重新输入\n");}//阻塞printf("输入任意键,按回车清空:");while(getchar() != '\n');}POS://关闭套接字close(cfd);return 0;
}
有bug待查