1. Overview of tftp protocol
Simple File Transfer Protocol, a set of standard protocols for file transfer on the Internet, using UDP for transmission.
Features:
① is the application layer protocol
② Implementation based on UDP protocol
③ Data transmission mode
- octet: binary mode (commonly used)
- mail: no longer supported
2. tftp download model
3. tftp protocol analysis
Error code: 0 undefined, error message 1 File not found. 2 Access violation. 3 Disk full or allocation exceeded. 4 illegal TFTP operation. 5 Unknown transfer ID. 6 File already exists. 7 No such user. 8 Unsupported option(s) requested.
4. Summary of TFTP communication process
- The server waits for the client’s request on port 69
- If the server approves the request, it will use the ephemeral port to communicate with the client.
- The number of each packet changes (starts from 1)
- Each data packet must be confirmed by ACK. If a timeout occurs, the last data packet or ACK packet needs to be resent
- The data length is transmitted in 512Byte, and the data less than 512Byte means that the data transmission is over.
5. Client download file (code)
include <stdio.h> include <head.h> include <sys/types.h> include <sys/socket.h> include <arpa/inet.h> define PORT 69 //The port number bound by the server define IP "192.168.1.109" //"192.168.122.120" //IP address of the server define FILENAME "5.png" int main(int argc, const char *argv[]) //Create a message socket int cfd = socket(AF_INET, SOCK_DGRAM, 0); if(cfd < 0) { ERR_MSG("socket"); return -1; } printf("cfd = %d\\ ",cfd); // Bind the address information structure of the client to the socket ---> binding is not required //If not bound, the operating system will bind the client to the IP of the running host and a random port number //Fill the address information structure of the server to be connected, the real address information structure is formulated according to the address family //Whoever you want to send to, fill in the address information of the person you want to send it to. //AF_INET : man 7 ip struct sockaddr_in sin; socklen_t addrlen=sizeof(sin); sin.sin_family = AF_INET; //must fill in AF_INET sin.sin_port = htons(PORT); //port number: the port number bound by the server sin.sin_addr.s_addr = inet_addr(IP);//Server bound IP //Edit read and write requests char buf[516]=""; char *ptr=buf; unsigned short *p1=(short*)buf; //Operation code *p1=htons(1); char *p2=buf + 2; //File name strcpy(p2,FILENAME); char *p3=p2 + strlen(p2); //The first 0 *p3=0; char *p4=p3 + 1; //Mode strcpy(p4,"octet"); size_t size=2 + strlen(p2) + 1 + strlen(p4) + 1; //opcode + filename + 0 + mode + 0 size_t res=0; //Send download request if(sendto(cfd,buf,size,0,(struct sockaddr*) & amp;sin,sizeof(sin))<0) { ERR_MSG("sendto"); return -1; } //Create download file and clear it int fd=open("./1.png",O_WRONLY|O_CREAT|O_TRUNC,0664); if(fd < 0) { perror("open"); return -1; } //Cycle send and receive, receive files, send ack while(1) { //receive packet res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*) &sin, &addrlen); if(res < 0) { ERR_MSG("recvfrom"); return -1; } if(write(fd,buf + 4,res-4) < 0 ) { perror("write"); return -1; } //send ACK *p1=htons(4); if(sendto(cfd,buf,4,0,(struct sockaddr*) & amp;sin,addrlen) < 0) { ERR_MSG("sendto"); return -1; } if(res-4 < 512) { printf("download success\\ "); break; } } close(cfd); close(fd); return 0; }
6. [Full] code (client download, upload file)
#include <stdio.h> #include <head.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <errno.h> #define PORT 69 //The port number bound by the server #define IP "192.168.1.107" //IP address of the server int do_download(int cfd,struct sockaddr_in sin); int do_upload(int cfd, struct sockaddr_in sin); int main(int argc, const char *argv[]) { //Create a report socket int cfd = socket(AF_INET, SOCK_DGRAM, 0); if(cfd < 0) { ERR_MSG("socket"); return -1; } printf("cfd = %d\\ ",cfd); // Bind the address information structure of the client to the socket ---> binding is not required //If not bound, the operating system will bind the client to the IP of the running host and a random port number //Fill the address information structure of the server to be connected, the real address information structure is formulated according to the address family //Whoever you want to send it to, fill in the address information //AF_INET: man 7 ip struct sockaddr_in sin; socklen_t addrlen=sizeof(sin); sin.sin_family = AF_INET; //must fill in AF_INET sin.sin_port = htons(PORT); //port number: the port number bound by the server sin.sin_addr.s_addr = inet_addr(IP); //Server bound IP char choose =0; while(1) { printf("------------------------\\ "); printf("---------1. Download --------\\ "); printf("---------2. Upload--------\\ "); printf("---------3. Exit-------\\ "); printf("------------------------\\ "); printf("------------------------\\ "); printf("Please enter >>> "); choose = getchar(); while(getchar() != 10); //Loop to get characters until \\ is encountered to end the loop switch(choose) { case '1': do_download(cfd,sin); break; case '2': do_upload(cfd,sin); break; case '3': goto END; break; default: printf("Input error! Please re-enter\\ "); } } END: //Close file descriptor close(cfd); return 0; } int do_download(int cfd, struct sockaddr_in sin) { //The package is ready to send the download request char buf[516]=""; char name[20]=""; printf("Please enter the file name to download >>> "); scanf("%s",name); while(getchar()!=10); unsigned short *p1=(short*)buf; //opcode *p1=htons(1); char *p2=buf + 2; //file name strcpy(p2,name); char *p3=p2 + strlen(p2); //the first 0 *p3=0; char *p4=p3 + 1; //mode strcpy(p4,"octet"); size_t size=2 + strlen(p2) + 1 + strlen(p4) + 1; //opcode + filename + 0 + mode + 0 //Send download request if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*) & amp;sin,sizeof(sin)) < 0) { ERR_MSG("sendto"); return -1; } //Create the download file and clear it int fd = -1; // must be initialized to an invalid file descriptor socklen_t addrlen = sizeof(sin); ssize_t res = 0; unsigned short num = 0; //Record the local block number //Send download request while(1) { \t\t//Receive data bzero(buf, sizeof(buf)); res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*) &sin, &addrlen); if(res < 0) { ERR_MSG("recvfrom"); return -1; } if(3 == buf[1]) //data packet { //Determine whether the block number of the data packet returned by the server is consistent with the locally recorded block number if(*(unsigned short*)(buf + 2) == htons((num + 1))) { num + + ; //Update the block number of the local record if(-1 == fd) { fd=open(name,O_WRONLY|O_CREAT|O_TRUNC,0664); if(fd < 0) { perror("open"); return -1; } } //write data to file if(write(fd,buf + 4,res-4) < 0 ) { perror("write"); return -1; } //send ACK buf[1] = 4; //*p1=htons(4); if(sendto(cfd,buf,4,0,(struct sockaddr*) & amp;sin,sizeof(sin)) < 0) { ERR_MSG("sendto"); return -1; } //If the received data is less than 512, jump out of the loop and end the download. if(res-4 < 512) { printf("%s file downloaded\\ ",name); break; } } } else if(5 == buf[1]) // error package { printf("Error: %d %s\\ ",ntohs(*(short*)(buf + 2)),buf + 4); close(fd); return -1; } } close(fd); return 0; } int do_upload(int cfd, struct sockaddr_in sin) { //The package is ready to send the upload request char buf[516]=""; char name[20]=""; printf("Please enter the file name to upload >>> "); scanf("%s",name); while(getchar()!=10); int fd = open(name,O_RDONLY); if(fd < 0) { if(errno == ENOENT) { printf(">>>File does not exist, please re-enter <<<\\ "); return -2; } else { ERR_MSG("open"); return -1; } } //The package is ready to send the upload request unsigned short *p1=(short*)buf; //opcode *p1=htons(2); char *p2=buf + 2; //file name strcpy(p2,name); char *p3=p2 + strlen(p2); //the first 0 *p3=0; char *p4=p3 + 1; //mode strcpy(p4,"octet"); size_t size=2 + strlen(p2) + 1 + strlen(p4) + 1; //Operation code + file name + 0 + mode + 0 //Send upload request if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*) & amp;sin,sizeof(sin)) < 0) { ERR_MSG("sendto"); return -1; } //Receive and send packets in a loop ssize_t res; unsigned short num = 0; socklen_t addrlen = sizeof(sin); while(1) { //Read data from file into buf bzero(buf, sizeof(buf)); res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*) & amp;sin, & amp;addrlen); if(res < 0) { ERR_MSG("recvfrom"); return -1; } //The range of the opcode is 1-5 because it is network byte order //So the valid opcode is stored in the high bit, that is, the position of buf[1] //printf("buf[1] = %d\\ ",buf[1]); //4 The server returns the response packet if(4 == buf[1]) //packet { //Determine whether the number of the current data packet is equal to the number of the response packet //Prevent packet loss or repeated packet receipt during transmission if(num == ntohs(*(unsigned short*)(buf + 2))) { //Modify opcode to data packet buf[1] = 3; //fill block number num + + ; *(unsigned short*)(buf + 2) = htons(num); //Read data res = read(fd,buf + 4,sizeof(buf)-4); if(res < 0) { ERR_MSG("read"); return -1; } else if(0 == res) { printf("%s file upload completed!\\ ",name); break; } //Send packet //The size of the sent data packet is, the number of bytes read res + opcode 2byte + block number 2bytes if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*) & amp;sin,sizeof(sin)) < 0) { ERR_MSG("sendto"); return -1; } } else { printf("File upload failed, please check the network environment\\ "); break; } } else if(5 == buf[1]) //Error package { printf("Error: %d %s\\ ",ntohs(*(short*)(buf + 2)),buf + 4); close(fd); return -1; } } close(fd); return 0; }
download:
Upload: