在写程序之前,我们应该首先了解TFT(Trivial File Transfer Protocol)P协议的过程:
目前TFTP有三种传送模式:
- l netascii型:一种修改的8bit ascii码
- l octet型:即binary普通的二进制型
- l mail型:过时,不再使用
具体每个包的格式在下面表格里列出:
下面附上上传和下载源码(刚学没多久,写的不是很标准,其实上传代码和下载代码基本上是一样的,只不过一个是读一个是写):
下载代码:
#include <stdio.h>
#include <unistd.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <arpa/inet.h>#include <netinet/in.h>#include <sys/socket.h>#include <fcntl.h>int main(int argc, char *argv[])
{ if(argc != 3) { printf("please input server ip and filename:\n"); exit(-1); } //copy filename to array char filename[50] = ""; strcpy(filename, argv[2]); char server_ip[INET_ADDRSTRLEN] = ""; strcpy(server_ip, argv[1]);// printf("%s\n", server_ip); //create socket int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); if(sock_fd < 0) { perror("socket"); exit(-1); } //send tftp request struct sockaddr_in server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(69); inet_pton(AF_INET, server_ip, &server_addr.sin_addr); char tftp_requst[1024] = ""; int len; len = sprintf(tftp_requst, "%c%c%s%c%s%c%s%c", 0, 1, filename, 0, "octet", 0, "tsize", 0); sendto(sock_fd, tftp_requst, len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)); unsigned char buf[1024] = ""; unsigned char cli_len = sizeof(server_addr); unsigned short num = 0; //open file and ready to write data down int fd = open(filename, O_RDWR | O_CREAT, 0666); if(fd < 0) { perror("open"); close(sock_fd); exit(-1); } socklen_t server_len = sizeof(server_addr); while(1) { len = recvfrom(sock_fd, buf, sizeof(buf), 0, (struct sockaddr *)&server_addr, &server_len); unsigned short cmd = ntohs(*((unsigned short*)buf)); printf("cmd:%d\tlen:%d\tnum:%d\n", cmd, len, ntohs(*((unsigned short*)(buf + 2)))); switch(cmd) { case 3://SEND ACK AND RECIEVE DATA { if(num + 1 == ntohs(*(unsigned short *)(buf + 2))) { write(fd, buf + 4, len - 4); num = ntohs(*(unsigned short *)(buf + 2)); } buf[1] = 4; sendto(sock_fd, buf, 4, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)); break; } case 5://error information { close(fd); close(sock_fd); unlink(filename); printf("err:%s\n", buf + 4); exit(-1); } case 6://send ACK { int i = 2; while(buf[i] != '\0') { i++; } i++; int size = atoi(buf + i); printf("size:%d\n", size);//show the size dest source sendto(sock_fd, buf, 4, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)); break; } } if(len != 516 && cmd != 6) { break; } } close(fd); close(sock_fd); return 0;}上传代码:
#include <stdio.h>
#include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> int main(int argc, char *argv[]) { if(argc != 3) { printf("please input the server ip and filename you want to upload:\n"); exit(-1); } //copy server ip char serv_ip[50] = ""; strcpy(serv_ip, argv[1]); //copy file name char filename[50] = ""; strcpy(filename, argv[2]); //create socket int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); if(sock_fd < 0) { perror("socket"); exit(-1); } //construct upload request char send_buf[1024] = ""; int len = sprintf(send_buf, "%c%c%s%c%s%c", 0, 2, filename, 0, "octet", 0); struct sockaddr_in serv_addr; bzero(&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(69); inet_pton(AF_INET, serv_ip, &serv_addr.sin_addr.s_addr); //send upload request sendto(sock_fd, send_buf, len, 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); //open the file you want to upload int fd; if( (fd = open(filename, O_RDONLY)) < 0) { perror("open"); close(sock_fd); exit(-1); } socklen_t serv_len = sizeof(struct sockaddr); unsigned short num = 0; while(1) { bzero(send_buf, sizeof(send_buf)); len = recvfrom(sock_fd, send_buf, sizeof(send_buf), 0, (struct sockaddr*)&serv_addr, &serv_len); //output the command unsigned short cmd = ntohs(*((unsigned short*)send_buf)); printf("request cmd:%d\t len:%d\tserial number:%d\n", cmd, len, ntohs(*(unsigned short*)(send_buf + 2))); switch(cmd) { case 4://if it was an answer package { if(num++ == ntohs(*(unsigned short*)(send_buf + 2)))//if the answer num is equal to the send num { sprintf(send_buf, "%c%c%c%c", 0, 3, num / 256, num % 256); len = read(fd, send_buf + 4, 512); sendto(sock_fd, send_buf, len + 4, 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); if(len < 512) { printf("upload completed\n"); close(sock_fd); close(fd); exit(0); } } break; } case 5://if it was a error package { printf("upload file failed!!!\n"); close(fd); close(sock_fd); printf("err:%s\n", send_buf + 4); break; } } }return 0; }