After more than a day of research, the TFTP client has been easily implemented and some problems have been encountered in the project process. Most of the problems are due to the vague understanding of basic concepts such as C ++ type conversion, after receiving the deep-rooted influence of C language, my understanding of C ++'s inheritance and classes is still on paper. in practical use, I have some difficulties.
Now we will briefly analyze the process of implementing the TFTP client.
Through the TFTP protocol, we can know that the TFTP client has five types of datagram: read/write request packets, response packets, data packets, and error packets.
Based on the Protocol, we can define the structures of five types of packets as follows:
// TFTP header <br/> struct tftp_head <br/> {<br/> byte opcode [2]; <br/> byte block [2]; <br/> byte other [datasize]; <br/> }; </P> <p> // TFTP request package <br/> struct tftp_rrwq <br/>{< br/> byte opcode [2]; <br/> string filename; <br/> byte flag1; <br/> string mode; <br/> byte flag2; <br/> }; </P> <p>/data packets </P> <p> struct tftp_data <br/> {<br/> byte opcode [2]; <br/> byte blocknum [2]; <br/> byte data [datasize]; <br/> }; </P> <p> // Response Message <br/> struct tftp_ack <br/> {<br/> byte opcode [2]; <br/> byte blocknum [2]; <br/> }; </P> <p> // error data packet <br/> struct tftp_error <br/> {<br/> byte opcode [2]; <br/> byte errornum [2]; <br/> byte data [datasize]; <br/> byte flag; <br/>}; <br/>
Note: The establishment of tftp_head is mainly to determine the packet type during packet capture.
During the specific implementation of data packet transmission, I divided various operations into two interface classes: communication and data packet operations.
Communication:
# Define tftpport 69 </P> <p> class tftpconnectcontrol <br/> {<br/> word versionrequired; <br/> wsadata; <br/> socket clientsocket; <br/> sockaddr_in clientsock_in; </P> <p> Public: <br/> tftpconnectcontrol (); <br/> ~ Tftpconnectcontrol (); <br/> bool sendtotftpserver (char * senddata); <br/> bool recvtftppackage (char receivebuf [datasize + 4]); <br/> }; </P> <p> // version Verification <br/> tftpconnectcontrol: tftpconnectcontrol () <br/>{< br/> versionrequired = makeword (2, 2 ); <br/> int err = wsastartup (versionrequired, & wsadata); // version Verification <br/> If (! Err) <br/>{< br/> cout <"version Verification Successful! "<Endl; <br/>}< br/> else <br/>{< br/> cout <" version Verification Failed! "<Endl; <br/> return; <br/>}</P> <p> clientsocket = socket (af_inet, sock_dgram, ipproto_udp ); // create a UDP socket <br/> If (clientsocket = invalid_socket) // socket creation failed <br/>{< br/> cout <"invalid socket" <Endl; <br/> return; <br/>}< br/> memset (& clientsock_in, 0, sizeof (clientsock_in); <br/> clientsock_in.sin_family = af_inet; <br/> clientsock_in.sin_addr.s_un.s_addr = inet_addr ("***. ***. ***. * ** "); <br/> clientsock _ In. sin_port = htons (tftpport); <br/>}</P> <p> tftpconnectcontrol ::~ Tftpconnectcontrol () <br/>{< br/> closesocket (clientsocket); <br/> wsacleanup (); <br/> return; <br/>}</P> <p> // send data packets </P> <p> bool tftpconnectcontrol: sendtotftpserver (char * senddata) <br/>{ <br/> cout <"IP:" <inet_ntoa (clientsock_in.sin_addr) <Endl; <br/> cout <"Port: "<ntohs (clientsock_in.sin_port) <Endl; <br/> int err = sendto (clientsocket, senddata, sizeof (senddata), 0, (sockaddr *) & clientsock_in, sizeof (Sockaddr_in); // data packet transmission <br/> If (ERR = socket_error) // data transmission error <br/>{< br/> DWORD res = wsagetlasterror (); <br/> cout <"Transmission Error:" <res <Endl; <br/> // closesocket (clientsocket); <br/> return false; <br/>}< br/> cout <"data packet sent successfully! "<Endl; <br/> return true; <br/>}</P> <p> // receives data packets <br/> bool tftpconnectcontrol :: recvtftppackage (char receivebuf [datasize + 4]) <br/>{< br/> int Len = sizeof (sockaddr); <br/> int err = recvfrom (clientsocket, receivebuf, sizeof (receivebuf), 0, (sockaddr *) & clientsock_in, & Len); // receives data packets <br/> If (ERR = socket_error) <br/>{< br/> DWORD res = wsagetlasterror (); <br/> cout <"receiving error:" <res <Endl; <br/> return false; <br/>}</P> <p> return true; <br/>}< br/>
Data Packet processing:
// Determine whether the file is uploaded <br/> bool fileeof (byte datapack []) <br/> {<br/> return (strlen (const char *) datapack) <512 & strlen (const char *) datapack)> = 0 )? True: false; <br/>}</P> <p> class tftppackagecontrol <br/>{< br/> char tftpdata [datasize + 4]; // reserved buffer <br/> int recvblock; // receives the block number <br/> string filename; // file name </P> <p> public: <br/> tftppackagecontrol (string name); // constructor <br/> tftppackagecontrol (); // constructor 2 <br/> ~ Tftppackagecontrol (); // destructor <br/> void createtftprrq (); // create a file request package <br/> void createack (); // create an ACK packet <br/> bool recv_tftp_file (char * packagedata); // determine whether the file is transmitted <br/> bool dealwithdatapackage (char * datapackage ); // process data packets <br/> void setfilename (string name); <br/> char * gettftpdata (); <br/> }; </P> <p> // constructor <br/> tftppackagecontrol: tftppackagecontrol (string name) <br/>{< br/> memset (tftpdata, 0, size Of (tftpdata); <br/> recvblock = 0; <br/> filename = Name; <br/>}</P> <p> // constructor 2 <br/> tftppackagecontrol: tftppackagecontrol () <br/>{< br/> memset (tftpdata, 0, sizeof (tftpdata); <br/> recvblock = 0; <br/> filename = ""; </P> <p >}</P> <p> // structure <br/> tftppackagecontrol ::~ Tftppackagecontrol () <br/> {<br/> memset (tftpdata, 0, sizeof (tftpdata); <br/> recvblock = 0; <br/> filename = ""; <br/>}</P> <p> // set the recipient's file name <br/> void tftppackagecontrol: setfilename (string name) <br/>{< br/> filename = Name; <br/>}</P> <p> // create rrq data packet <br/> void tftppackagecontrol :: createtftprrq () <br/>{< br/> struct tftp_rrwq package; <br/> memset (package. opcode, 0x01, sizeof (package. opcode); <br/> package. filename. assign (filename); <br/> memset (& package. flag1, 0, sizeof (package. flag1); <br/> package. mode = "netascii"; // netascii for ASCII files, octet for binary files <br/> memset (& package. flag2, 0, sizeof (package. flag2); <br/> memcpy (tftpdata, (char *) & package, sizeof (Package )); <br/>}</P> <p> // create an ACK packet <br/> void tftppackagecontrol: createack () <br/>{< br/> struct tftp_ack * ackpackage = (struct tftp_ack *) malloc (sizeof (tftp_ack); <br/> memset (ackpackage-> opcode, 0x04, sizeof (ackpackage-> opcode); <br/> memset (ackpackage-> blocknum, recvblock, sizeof (ackpackage-> blocknum )); <br/> memcpy (tftpdata, (char *) & ackpackage, sizeof (ackpackage )); <br/>}</P> <p> // determines whether a data packet is received. <br/> bool tftppackagecontrol: recv_tftp_file (char * packagedata) <br/> {<br/> struct tftp_head * Data = (struct tftp_head *) packagedata; <br/> recvblock = (INT) * Data-> block; <br/> If (memcmp (data-> opcode, "0x03", sizeof (data-> opcode) <br/> return true; <br/> else <br/> return false; <br/>}</P> <p> char * tftppackagecontrol: gettftpdata () <br/>{< br/> return tftpdata; <br/>}</P> <p> // whether a file has been processed <br/> bool tftppackagecontrol :: dealwithdatapackage (char * datapackage) <br/>{< br/> char filedata [datasize]; <br/> struct tftp_data * Data = (struct tftp_data *) datapackage; <br/> memcpy (filedata, data-> data, sizeof (data-> data); </P> <p> ofstream fout; <br/> fout. open (filename. c_str (); <br/> fout <filedata; <br/> fout. close (); <br/> return fileeof (data-> data); </P> <p>}
Of course, this is only the initial design of the TFTP client. It will be improved as the project progresses and will be recorded here for the time being. (* ^__ ^ *)