Linux UDP下C語言實現TFTP協議客戶端 .

因課程實驗要求,需要使用C語言在Linux下實現TFTP協議的客戶端用於文件傳輸。TFTP,即Trivial File Transfer Protocol,有點類似於FTP協議不過要比FTP簡單許多,功能也自然沒FTP那麼全。

       根據實驗要求,客戶端在與服務端傳輸文件的時候需要同時實現上傳和下載功能,具體的功能由傳輸命令決定,如

  1. -g small.txt xxxx.edu.cn  
  2. -p medium.pdf xxxx.edu.cn   
-g small.txt xxxx.edu.cn
-p medium.pdf xxxx.edu.cn 
分別表示服務器xxxx.edu.cn下載文件small.txt和上傳medium.pdf到服務端。

傳輸過程中,每個data packet攜帶固定長度512 bytes的data,如果某一個data packet攜帶的data長度小於512 bytes,則說明正在傳輸的是最後一個data packet,傳輸data結束且收到相應的ack packet後則表示整個傳輸過程結束,斷開連接。

實驗要求實現的協議必須能夠處理packet loss和duplicated packet的情況。源代碼如下:

tftp.h文件:

  1. #ifndef _TFTP_H   
  2. #define _TFTP_H   
  3.   
  4. #if defined(SUNOS_5)   
  5. #define OS_SUNOS5   
  6. typedef short u_int16_t;  
  7. typedef int u_int32_t;  
  8. typedef char u_int8_t;  
  9. #elif defined(__GNUC__) && (defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__))   
  10. #define OS_MACOSX   
  11. #elif defined(__GNUC__) && defined(__linux__)   
  12. #define OS_LINUX   
  13. #include <linux/types.h>   
  14. #else   
  15. #error "Unsupported operating system"   
  16. #endif    
  17.   
  18. #define BLOCK_SIZE 512   
  19.   
  20. #define OPCODE_RRQ   1   
  21. #define OPCODE_WRQ   2   
  22. #define OPCODE_DATA  3   
  23. #define OPCODE_ACK   4   
  24. #define OPCODE_ERR   5   
  25.   
  26.   
  27. #define MODE_NETASCII "netascii"   
  28. #define MODE_OCTET    "octet"   
  29. #define MODE_MAIL     "mail"   
  30.   
  31. #define TFTP_PORT 20069   
  32.   
  33. /* Timeout in seconds */  
  34. #define TFTP_TIMEOUT 2   
  35.   
  36. static char *err_codes[8] = {  
  37.     "Undef",  
  38.     "File not found",  
  39.     "Access violation",  
  40.     "Disk full or allocation exceeded",  
  41.     "Illegal TFTP operation",  
  42.     "Unknown transfer ID",  
  43.     "File already exists",  
  44.     "No such user"  
  45. };  
  46.   
  47. /* 
  48.   A generic header for TFTP messages. 
  49.  */  
  50. struct tftp_msg {  
  51.     u_int16_t opcode;  
  52.     char msg[0];  
  53. };  
  54.   
  55. /* 
  56.   A TFTP read request. 
  57.  */  
  58. struct tftp_rrq {  
  59.     u_int16_t opcode;  
  60.     char req[0];  
  61. };  
  62.   
  63. #define TFTP_RRQ_HDR_LEN sizeof(struct tftp_rrq)   
  64. #define TFTP_RRQ_LEN(f,m) (sizeof(struct tftp_rrq) + strlen(f) + strlen(m) + 2)   
  65.   
  66. /* 
  67.   A TFTP write request. 
  68.  */  
  69. struct tftp_wrq {  
  70.     u_int16_t opcode;  
  71.     char req[0];  
  72. };  
  73.   
  74. #define TFTP_WRQ_HDR_LEN sizeof(struct tftp_wrq)   
  75. #define TFTP_WRQ_LEN(f,m) (sizeof(struct tftp_wrq) + strlen(f) + strlen(m) + 2)   
  76.   
  77. /* 
  78.   A TFTP data block message. 
  79.  */  
  80. struct tftp_data {  
  81.     u_int16_t opcode;  
  82.     u_int16_t blocknr;  
  83.     char data[0];  
  84. };  
  85.   
  86. #define TFTP_DATA_HDR_LEN sizeof(struct tftp_data)   
  87.   
  88. /* 
  89.   A TFTP ack message. 
  90.  */  
  91. struct tftp_ack {  
  92.     u_int16_t opcode;  
  93.     u_int16_t blocknr;  
  94. };  
  95.   
  96. #define TFTP_ACK_HDR_LEN sizeof(struct tftp_ack)   
  97.   
  98. /* 
  99.   A TFTP error message. 
  100.  */  
  101. struct tftp_err {  
  102.     u_int16_t opcode;  
  103.     u_int16_t errcode;  
  104.     char errmsg[0];  
  105. };  
  106.   
  107. #define TFTP_ERR_HDR_LEN sizeof(struct tftp_err)   
  108.   
  109. static inline char *tftp_err_to_str(int err)  
  110. {  
  111.     if (err < 0 || err > 7)  
  112.         return NULL;  
  113.       
  114.     return err_codes[err];  
  115. }  
  116.   
  117. #endif /* TFTP_H_ */  
#ifndef _TFTP_H
#define _TFTP_H

#if defined(SUNOS_5)
#define OS_SUNOS5
typedef short u_int16_t;
typedef int u_int32_t;
typedef char u_int8_t;
#elif defined(__GNUC__) && (defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__))
#define OS_MACOSX
#elif defined(__GNUC__) && defined(__linux__)
#define OS_LINUX
#include <linux/types.h>
#else
#error "Unsupported operating system"
#endif 

#define BLOCK_SIZE 512

#define OPCODE_RRQ   1
#define OPCODE_WRQ   2
#define OPCODE_DATA  3
#define OPCODE_ACK   4
#define OPCODE_ERR   5


#define MODE_NETASCII "netascii"
#define MODE_OCTET    "octet"
#define MODE_MAIL     "mail"

#define TFTP_PORT 20069

/* Timeout in seconds */
#define TFTP_TIMEOUT 2

static char *err_codes[8] = {
	"Undef",
	"File not found",
	"Access violation",
	"Disk full or allocation exceeded",
	"Illegal TFTP operation",
	"Unknown transfer ID",
	"File already exists",
	"No such user"
};

/*
  A generic header for TFTP messages.
 */
struct tftp_msg {
	u_int16_t opcode;
	char msg[0];
};

/*
  A TFTP read request.
 */
struct tftp_rrq {
	u_int16_t opcode;
	char req[0];
};

#define TFTP_RRQ_HDR_LEN sizeof(struct tftp_rrq)
#define TFTP_RRQ_LEN(f,m) (sizeof(struct tftp_rrq) + strlen(f) + strlen(m) + 2)

/*
  A TFTP write request.
 */
struct tftp_wrq {
	u_int16_t opcode;
	char req[0];
};

#define TFTP_WRQ_HDR_LEN sizeof(struct tftp_wrq)
#define TFTP_WRQ_LEN(f,m) (sizeof(struct tftp_wrq) + strlen(f) + strlen(m) + 2)

/*
  A TFTP data block message.
 */
struct tftp_data {
	u_int16_t opcode;
	u_int16_t blocknr;
	char data[0];
};

#define TFTP_DATA_HDR_LEN sizeof(struct tftp_data)

/*
  A TFTP ack message.
 */
struct tftp_ack {
	u_int16_t opcode;
	u_int16_t blocknr;
};

#define TFTP_ACK_HDR_LEN sizeof(struct tftp_ack)

/*
  A TFTP error message.
 */
struct tftp_err {
	u_int16_t opcode;
	u_int16_t errcode;
	char errmsg[0];
};

#define TFTP_ERR_HDR_LEN sizeof(struct tftp_err)

static inline char *tftp_err_to_str(int err)
{
	if (err < 0 || err > 7)
		return NULL;
	
	return err_codes[err];
}

#endif /* TFTP_H_ */


tftp.c文件:

  1. #include <sys/types.h>   
  2. #include <sys/socket.h>   
  3. #include <netinet/in.h>   
  4. #include <stdio.h>   
  5. #include <string.h>   
  6. #include <netdb.h>   
  7. #include <stdlib.h>   
  8. #include <unistd.h>   
  9. #include <sys/stat.h>   
  10. #include <fcntl.h>   
  11. #include <sys/select.h>   
  12.   
  13. #include <netinet/in.h>   
  14. #include <arpa/inet.h>   
  15. #include <sys/time.h>   
  16.   
  17. #include "tftp.h"   
  18.   
  19. //extern int h_errno;   
  20.   
  21. #define TFTP_TYPE_GET 0   
  22. #define TFTP_TYPE_PUT 1   
  23.   
  24. /* Should cover most needs */  
  25. #define MSGBUF_SIZE (TFTP_DATA_HDR_LEN + BLOCK_SIZE)   
  26.   
  27. /* Record last transmited data and its length in case of packet loss */  
  28. char* lastTransferData;  
  29. int lastTransferDataLength;  
  30.   
  31. /* 
  32.  * NOTE: 
  33.  * In tftp.h you will find definitions for headers and constants. Make 
  34.  * sure these are used throughout your code. 
  35.  */  
  36.   
  37. /* A connection handle */  
  38. struct tftp_conn {  
  39.     int type; /* Are we putting or getting? */  
  40.     FILE *fp; /* The file we are reading or writing */  
  41.     int sock; /* Socket to communicate with server */  
  42.     int blocknr; /* The current block number */  
  43.     char *fname; /* The file name of the file we are putting or getting */  
  44.     char *mode; /* TFTP mode */  
  45.     struct sockaddr_in peer_addr; /* Remote peer address */  
  46.     socklen_t addrlen; /* The remote address length */  
  47.     char msgbuf[MSGBUF_SIZE]; /* Buffer for messages being sent or received */  
  48. };  
  49.   
  50. /* Close the connection handle, i.e., delete our local state. */  
  51. void tftp_close(struct tftp_conn *tc) {  
  52.     if (!tc)  
  53.         return;  
  54.     fclose(tc->fp);  
  55.     close(tc->sock);  
  56.     free(tc);  
  57. }  
  58.   
  59. /* Connect to a remote TFTP server. */  
  60. struct tftp_conn *tftp_connect(int type, char *fname, char *mode,const char *hostname)   
  61. {  
  62.     struct addrinfo hints;  
  63.     struct addrinfo * res = NULL;  
  64.     struct tftp_conn *tc;  
  65.   
  66.     if (!fname || !mode || !hostname)  
  67.         return NULL ;  
  68.   
  69.     tc = malloc(sizeof(struct tftp_conn));  
  70.   
  71.     if (!tc)  
  72.         return NULL ;  
  73.   
  74.     /* Create a socket. 
  75.      * Check return value. */  
  76.        
  77.     /* Specify communication domain (protocol family) and communication semantics (socket type) */  
  78.     if ((tc->sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {  
  79.         fprintf(stderr, "Unable to create socket...\n");  
  80.         free(tc);  
  81.         return NULL ;  
  82.     }  
  83.     /* Check the type = read or write file */  
  84.     if (type == TFTP_TYPE_PUT)  
  85.         tc->fp = fopen(fname, "rb");  
  86.     else if (type == TFTP_TYPE_GET)  
  87.         tc->fp = fopen(fname, "wb");  
  88.     else {  
  89.         fprintf(stderr, "Invalid TFTP mode, must be put or get\n");  
  90.         return NULL ;  
  91.     }  
  92.   
  93.     if (tc->fp == NULL ) {  
  94.         fprintf(stderr, "File I/O error!\n");  
  95.         close(tc->sock);  
  96.         free(tc);  
  97.         return NULL ;  
  98.     }  
  99.   
  100.     /* initial settings for getaddrinfo function */  
  101.     memset(&hints, 0, sizeof(hints));  
  102.     hints.ai_family = PF_UNSPEC;  
  103.     hints.ai_socktype = SOCK_DGRAM;  
  104.     char port_str[5];  
  105.     sprintf(port_str, "%d", 20069);  
  106.   
  107.     /* get address from host name. 
  108.      * If error, gracefully clean up.*/  
  109.       
  110.     /* host address information is stored in the varible res */  
  111.     int errorcode = getaddrinfo(hostname, port_str, &hints, &res);  
  112.     if (errorcode != 0) {  
  113.         fprintf(stderr, "Unable to get host address...\n");  
  114.         close(tc->sock);  
  115.         free(tc);  
  116.         return NULL ;  
  117.     }  
  118.   
  119.     /* Assign address to the connection handle. 
  120.      * You can assume that the first address in the hostent 
  121.      * struct is the correct one */  
  122.   
  123.     /* initial settings for varible tc which will be used in the later transmition */  
  124.     memcpy(&tc->peer_addr, res->ai_addr, res->ai_addrlen);  
  125.     tc->addrlen = sizeof(struct sockaddr_in);  
  126.     tc->type = type;  
  127.     tc->mode = mode;  
  128.     tc->fname = fname;  
  129.     tc->blocknr = 0;  
  130.     memset(tc->msgbuf, 0, MSGBUF_SIZE);  
  131.     return tc;  
  132. }  
  133.   
  134. /* 
  135.  Send a read request to the server. 
  136.  1. Format message. 
  137.  2. Send the request using the connection handle. 
  138.  3. Return the number of bytes sent, or negative on error. 
  139.  */  
  140. int tftp_send_rrq(struct tftp_conn *tc) {     
  141.     /* struct tftp_rrq *rrq; */  
  142.     struct tftp_rrq* pTftp_rrq = malloc(TFTP_RRQ_LEN((*tc).fname,(*tc).mode));  
  143.     memset(pTftp_rrq, 0, TFTP_RRQ_LEN((*tc).fname,(*tc).mode));  
  144.     pTftp_rrq->opcode = htons(OPCODE_RRQ);//transform host ascii to net ascii   
  145.     memcpy(pTftp_rrq->req, (*tc).fname, strlen((*tc).fname));  
  146.     memcpy(pTftp_rrq->req + strlen((*tc).fname) + 1, (*tc).mode,  
  147.             strlen((*tc).mode));  
  148.     /* send read request to the server */  
  149.     int rqtResult = sendto(tc->sock, pTftp_rrq,  
  150.             TFTP_RRQ_LEN((*tc).fname,(*tc).mode), 0,  
  151.             (struct sockaddr*) (&(tc->peer_addr)), (*tc).addrlen);  
  152.     free(pTftp_rrq);  
  153.     return rqtResult;  
  154. }  
  155. /* 
  156.  Send a write request to the server. 
  157.  1. Format message. 
  158.  2. Send the request using the connection handle. 
  159.  3. Return the number of bytes sent, or negative on error. 
  160.  */  
  161. int tftp_send_wrq(struct tftp_conn *tc) {  
  162.     /* struct tftp_wrq *wrq; */  
  163.     struct tftp_wrq* pTftp_wrq = malloc(TFTP_WRQ_LEN(tc->fname, tc->mode));  
  164.     memset(pTftp_wrq, 0, TFTP_WRQ_LEN(tc->fname, tc->mode));  
  165.     pTftp_wrq->opcode = htons(OPCODE_WRQ);//transform host ascii to net ascii   
  166.     memcpy(pTftp_wrq->req, tc->fname, strlen(tc->fname));  
  167.     memcpy(pTftp_wrq->req + strlen(tc->fname) + 1, tc->mode, strlen(tc->mode));  
  168.     /* send write request to the server */  
  169.     int rqtResult = sendto(tc->sock, pTftp_wrq,  
  170.             TFTP_WRQ_LEN(tc->fname, tc->mode), 0,  
  171.             (struct sockaddr*) (&(tc->peer_addr)), (*tc).addrlen);  
  172.     free(pTftp_wrq);  
  173.     return rqtResult;  
  174. }  
  175.   
  176. /* 
  177.  Acknowledge reception of a block. 
  178.  1. Format message. 
  179.  2. Send the acknowledgement using the connection handle. 
  180.  3. Return the number of bytes sent, or negative on error. 
  181.  */  
  182. int tftp_send_ack(struct tftp_conn *tc) {  
  183.     /* struct tftp_ack *ack; */  
  184.     struct tftp_ack* pTftp_ack = (struct tftp_ack*) malloc(TFTP_ACK_HDR_LEN);  
  185.     pTftp_ack->opcode = htons(OPCODE_ACK);//transform host ascii to net ascii   
  186.     /* Get receiving data block number from tc->msgbuf and ack to the server */  
  187.     tc->blocknr = ntohs(((struct tftp_data*) tc->msgbuf)->blocknr);  
  188.     pTftp_ack->blocknr = htons(tc->blocknr);  
  189.     int result =sendto(tc->sock, pTftp_ack,TFTP_ACK_HDR_LEN, 0, (struct sockaddr*)(&(tc->peer_addr)), (*tc).addrlen);  
  190.     free(pTftp_ack);  
  191.     return result;  
  192. }  
  193.   
  194. /* 
  195.  Send a data block to the other side. 
  196.  1. Format message. 
  197.  2. Add data block to message according to length argument. 
  198.  3. Send the data block message using the connection handle. 
  199.  4. Return the number of bytes sent, or negative on error. 
  200.  
  201.  TIP: You need to be able to resend data in case of a timeout. When 
  202.  resending, the old message should be sent again and therefore no 
  203.  new message should be created. This can, for example, be handled by 
  204.  passing a negative length indicating that the creation of a new 
  205.  message should be skipped. 
  206.  */  
  207. int tftp_send_data(struct tftp_conn *tc, int length) {  
  208.     /* struct tftp_data *tdata; */  
  209.     struct tftp_data* pTftp_data = malloc(TFTP_DATA_HDR_LEN+BLOCK_SIZE);  
  210.     memset(pTftp_data,0,TFTP_DATA_HDR_LEN+length);  
  211.     pTftp_data->opcode=htons(OPCODE_DATA);  
  212.     /* Get receiving ack number from tc->msgbuf and send data to the server */  
  213.     /* Retransmit old block in case of packet loss */  
  214.     if(tc->blocknr==1+ntohs(((struct tftp_ack*)tc->msgbuf)->blocknr))  
  215.     {  
  216.         pTftp_data->blocknr=htons(tc->blocknr);  
  217.         memcpy(pTftp_data->data,lastTransferData,lastTransferDataLength);  
  218.         /* transmit last transfered data */  
  219.         int result=sendto(tc->sock, pTftp_data, TFTP_DATA_HDR_LEN+lastTransferDataLength,   
  220.                          0,(struct sockaddr*)(&(tc->peer_addr)), (*tc).addrlen);  
  221.         return result;  
  222.     }  
  223.     //************Transmit new block**********************//   
  224.     else{  
  225.         tc->blocknr=ntohs(((struct tftp_ack*)tc->msgbuf)->blocknr)+1;  
  226.         pTftp_data->blocknr=htons(tc->blocknr);  
  227.         /* read data from local file system and send it to the server */  
  228.         if(!feof(tc->fp))  
  229.         {  
  230.             int dataLength=fread(pTftp_data->data,1,length,tc->fp);  
  231.             int result=sendto(tc->sock, pTftp_data, TFTP_DATA_HDR_LEN+dataLength, 0,(struct sockaddr*)(&(tc->peer_addr)), (*tc).addrlen);  
  232.             /* record data as lastTranserData in case of packet loss */  
  233.             lastTransferData=malloc(dataLength);  
  234.             memset(lastTransferData,0,dataLength);  
  235.             memcpy(lastTransferData,pTftp_data->data,dataLength);  
  236.             lastTransferDataLength=dataLength;  
  237.             return result;  
  238.         }  
  239.     }  
  240.     return -1;  
  241. }  
  242.   
  243.     /* 
  244.      Transfer a file to or from the server. 
  245.      */  
  246. int tftp_transfer(struct tftp_conn *tc) {  
  247.     int retval = 0; //Transfer result   
  248.     int len;        //Transfer data length   
  249.     int totlen = 0; //Transfer total length   
  250.     int recvResult; //Length of reveiving data   
  251.     int sendResult; //Length of sending data   
  252.     struct timeval timeout; //Time out setting   
  253.     fd_set fdst;    //File descriptor for select function   
  254.     u_int16_t errorCode; //Error code   
  255.     int isEnd=0;    //Transfer is end or not: 0-not, 1-end   
  256.   
  257.     /* Sanity check */  
  258.     if (!tc)  
  259.         return -1;  
  260.   
  261.     len = 0;  
  262.   
  263.     /* After the connection request we should start receiving data 
  264.      * immediately */  
  265.     /* Check if we are putting a file or getting a file and send 
  266.      * the corresponding request. */  
  267.     if (TFTP_TYPE_GET == tc->type) {  
  268.         tftp_send_rrq(tc);  
  269.     } else if (TFTP_TYPE_PUT == tc->type) {  
  270.         tftp_send_wrq(tc);  
  271.     } else {  
  272.         return -1;  
  273.     }  
  274.       
  275.     /* 
  276.      Put or get the file, block by block, in a loop. 
  277.      */  
  278.     do {  
  279.         /* 1. Wait for something from the server (using 
  280.          * 'select'). If a timeout occurs, resend last block 
  281.          * or ack depending on whether we are in put or get 
  282.          * mode. */  
  283.   
  284.         /* ... */  
  285.         while (1) {  
  286.         /* Set a timeout for resending data. */  
  287.             timeout.tv_sec = TFTP_TIMEOUT;  
  288.             timeout.tv_usec = 0;  
  289.   
  290.             FD_ZERO(&fdst);//Clear file descriptor set to enable status checking   
  291.             FD_SET(tc->sock, &fdst);//add fiel descriptor to the set   
  292.             /* Check status of values in the fdst to see if any fd is ready for reading or writing */  
  293.             int sltRlt = select(tc->sock + 1, &fdst, NULL, NULL, &timeout);  
  294.             if (sltRlt < 0) { //Error in the select function   
  295.                 return -1;  
  296.             } else if (sltRlt == 0) { //Time out in the selection function, no readable, writable or error fds   
  297.                 //******Retransmit********//   
  298.                 if (TFTP_TYPE_GET == tc->type)  
  299.                 {  
  300.                     /* Retransmit read request */  
  301.                     if(0==tc->blocknr)  
  302.                     {  
  303.                         tftp_send_rrq(tc);  
  304.                     }  
  305.                     /* Retransmit ack packet */  
  306.                     else{  
  307.                         printf("%s,%d\n""Retransmit Ack", tc->blocknr);  
  308.                         tftp_send_ack(tc);  
  309.                     }  
  310.   
  311.                 }   
  312.                 else if (TFTP_TYPE_PUT == tc->type)  
  313.                 {  
  314.                     /* Retransmit write request */  
  315.                     if(0==tc->blocknr)  
  316.                     {  
  317.                         tftp_send_wrq(tc);  
  318.                     }  
  319.                     /* Retransmit data packet */  
  320.                     else{  
  321.   
  322.                         printf("%s,%d\n""Retransmit Data", tc->blocknr);  
  323.                         sendResult=tftp_send_data(tc,BLOCK_SIZE);  
  324.                     }  
  325.                 } else {  
  326.                         return -1;  
  327.                 }  
  328.                 continue;//Continue to wait for receiving data   
  329.             }   
  330.             else {//readable, writable or error fds exist   
  331.                 /* receive data */  
  332.                 recvResult = recvfrom(tc->sock, tc->msgbuf,  
  333.                 sizeof(tc->msgbuf), 0,(struct sockaddr*) (&(tc->peer_addr)),&tc->addrlen);  
  334.                 break;  
  335.             }  
  336.         }  
  337.         u_int16_t msgType = ntohs(((struct tftp_msg*) (tc->msgbuf))->opcode);//Msg type   
  338.         int serverSendBlkNr=0; //receiving data block number sent by server   
  339.         int serverAckBlkNr=0;  //receiving ack block number sent by server   
  340.           
  341.         /* 2. Check the message type and take the necessary action. */  
  342.         switch (msgType) {  
  343.   
  344.         case OPCODE_DATA:  
  345.             /* Received data block, send ack */  
  346.             serverSendBlkNr=ntohs(((struct tftp_data*) tc->msgbuf)->blocknr);  
  347.             /* receive correct data packet and discard duplicated dat packets */  
  348.             if(tc->blocknr == serverSendBlkNr-1)  
  349.             {  
  350.                 /* write correct data to file */  
  351.                 fwrite(tc->msgbuf+ TFTP_DATA_HDR_LEN, 1, recvResult-TFTP_DATA_HDR_LEN, tc->fp);  
  352.                 totlen += recvResult - TFTP_DATA_HDR_LEN;  
  353.                 printf("%s,%d,%d,%d\n","Get",serverSendBlkNr,recvResult - TFTP_DATA_HDR_LEN,totlen);  
  354.             }  
  355.             /* Send ack packet to server */  
  356.             tftp_send_ack(tc);  
  357.             /* if length of receiving data packet is less than 516(512+4) bytes,  
  358.             then the connection should be terminated */  
  359.             if(recvResult<516)  
  360.             {  
  361.                 isEnd=1;  
  362.                 printf("%s\n""End of receiving data");  
  363.             }  
  364.             break;  
  365.   
  366.             case OPCODE_ACK:  
  367.             /* Received ACK, send next block */  
  368.             serverAckBlkNr = ntohs(((struct tftp_ack*)tc->msgbuf)->blocknr);  
  369.             /* receive correct ack packet and discard duplicated ack packets */  
  370.             if(tc->blocknr == serverAckBlkNr && serverAckBlkNr>0)  
  371.             {  
  372.                 totlen+=sendResult-TFTP_DATA_HDR_LEN;  
  373.                 printf("%s,%d,%d,%d\n","Put",serverAckBlkNr,sendResult-TFTP_DATA_HDR_LEN,totlen);  
  374.                 /* if length of sending data packet is less than 516(512+4) bytes,  
  375.             then the connection should be terminated */  
  376.                 if(sendResult<516 && serverAckBlkNr>0)  
  377.                 {  
  378.                     isEnd=1;  
  379.                     printf("%s\n""End of sending data");  
  380.                     break;  
  381.                 }  
  382.             }  
  383.             /* Send data packet to server */  
  384.             sendResult=tftp_send_data(tc,BLOCK_SIZE);  
  385.             break;  
  386.   
  387.             case OPCODE_ERR:  
  388.             /* Handle error... */  
  389.             errorCode=ntohs(((struct tftp_err*) (tc->msgbuf))->errcode);  
  390.             fprintf(stderr,"%s", err_codes[errorCode]);  
  391.             retval=-1;  
  392.             goto out;  
  393.             break;  
  394.   
  395.             default:  
  396.             fprintf(stderr, "\nUnknown message type\n");  
  397.             goto out;  
  398.         }  
  399.   
  400.     } while (isEnd==0);  
  401.   
  402.     printf("\nTotal data bytes sent/received: %d.\n", totlen);  
  403.     out: return retval;  
  404. }  
  405.   
  406. int main(int argc, char **argv) {  
  407.     char *fname = NULL;  
  408.     char *hostname = NULL;  
  409.     char *progname = argv[0];  
  410.     int retval = -1;  
  411.     int type = -1;  
  412.     struct tftp_conn *tc;  
  413.   
  414.     /* Check whether the user wants to put or get a file. */  
  415.     while (argc > 0) {  
  416.   
  417.         if (strcmp("-g", argv[0]) == 0) {  
  418.             fname = argv[1];  
  419.             hostname = argv[2];  
  420.   
  421.             type = TFTP_TYPE_GET;  
  422.             break;  
  423.         } else if (strcmp("-p", argv[0]) == 0) {  
  424.             fname = argv[1];  
  425.             hostname = argv[2];  
  426.   
  427.             type = TFTP_TYPE_PUT;  
  428.             break;  
  429.         }  
  430.         argc--;  
  431.         argv++;  
  432.     }  
  433.   
  434.     /* Print usage message */  
  435.     if (!fname || !hostname) {  
  436.         fprintf(stderr, "Usage: %s [-g|-p] FILE HOST\n", progname);  
  437.         return -1;  
  438.     }  
  439.   
  440.     /* Connect to the remote server */  
  441.     tc = tftp_connect(type, fname, MODE_OCTET, hostname);  
  442.   
  443.     if (!tc) {  
  444.         fprintf(stderr, "Failed to connect!\n");  
  445.         return -1;  
  446.     }  
  447.   
  448.     /* Transfer the file to or from the server */  
  449.     retval = tftp_transfer(tc);  
  450.   
  451.     if (retval < 0) {  
  452.         fprintf(stderr, "File transfer failed!\n");  
  453.     }  
  454.   
  455.     /* We are done. Cleanup our state. */  
  456.     tftp_close(tc);  
  457.   
  458.     return retval;  
  459. }  
發佈了0 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章