基于LWIP的UDP示例工程,实现tftp客户端内容,包含上传和下载功能。
硬件平台:zynq 7020
系统:FreeRTOS
接口
/**
* @brief 文件下载
*
* @param serverIp TFTP服务器IP
* @param fileName 远端文件名
* @param pTftpDownLoadCallback 接收数据回调函数(多次回调)
* @param arg 回调函数自定义参数
* @return int 非0即错
*/
int downloadFile(char * serverIp,char * fileName,tftpDownLoadCallback pTftpDownLoadCallback,void * arg);
/**
* @brief 文件上传
*
* @param serverIp TFTP服务器IP
* @param destFileName 目标文件名
* @param sourceData 文件数据缓存区
* @param dataLen 缓存区长度
* @return int 非0即错
*/
int uploadFile(char * serverIp,char * destFileName,char * sourceData,long long dataLen);
bylh_tftp_client_H
/*
* @Author: 47
* @Date: 2022-01-05 11:27:51
* @LastEditTime: 2022-01-05 16:45:44
* @LastEditors: Please set LastEditors
* @FilePath: \src\udp_perf_client.h
*/
#ifndef __UDP_PERF_CLIENT_H_
#define __UDP_PERF_CLIENT_H_
#include "lwipopts.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/udp.h"
#include "lwip/inet.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "errno.h"
#include <sleep.h>
#include "xil_printf.h"
#include "xlwipconfig.h"
typedef int (*tftpDownLoadCallback)(char * pData,int dataLen,void * arg);
int downloadFile(char * serverIp,char * fileName,tftpDownLoadCallback pTftpDownLoadCallback,void * arg);
int uploadFile(char * serverIp,char * destFileName,char * sourceData,long long dataLen);
#endif /* __UDP_PERF_CLIENT_H_ */
BYLH_TFTP_CPP
/*
* @Author: 47
* @Date: 2022-01-05 11:27:51
* @LastEditTime: 2022-01-05 16:22:06
* @LastEditors: Please set LastEditors
* @FilePath: \src\udp_perf_client.c
*/
#include "tftp_client.h"
#define TFTP_RRQ 1 //下载
#define TFTP_WRQ 2 //上传
#define TFTP_DATA 3 //数据
#define TFTP_ACK 4 //ACK
#define TFTP_ERROR 5 //Error
#define ASCII_FORMAT 1
#define OCTET_FORMAT 2
//错误种类
#define Not_defined 0
#define File_not_found 1
#define Access_violation 2
#define Disk_full 3
#define Illegal_TFTP_operation 4
#define Unknown_port 5
#define File_already_exists 6
#define No_such_user 7
#define Time_out 8
#define Read_file_Error 9
#define Cannot_create_file 10
//#define TFTP_PRINTF_DEBUG //!< lwq 2022 01 05 调试打印开关
int sendRequest(int op, const char* filename, int type, int socket)
{
static char requestBuf[128];
memset(requestBuf, 0, sizeof(requestBuf));
requestBuf[1] = op;
strcpy(requestBuf + 2, filename);
if (type == OCTET_FORMAT)
{
//!< 操作码2B + 文件名 (N B)+'\0'(1B)+模式
char * formatStr = "octet";
strcpy(requestBuf + 2+strlen(filename)+1,formatStr);
return send(socket,requestBuf,2+strlen(filename)+1+strlen(formatStr)+1,0);
}
else
{
char * formatStr = "netascii";
strcpy(requestBuf + 2+strlen(filename)+1,formatStr);
return send(socket,requestBuf,2+strlen(filename)+1+strlen(formatStr)+1,0);
}
return -1;
}
int makeack(unsigned short num, char *buffer, int size)
{
buffer[0] = 0;
buffer[1] = 0x04; //操作码为04
buffer[2] = (char)(num>>8);//块号2个字节
buffer[3] = (char)(num&0xFF);
#ifdef TFTP_PRINTF_DEBUG
printf("%s[%d]%d\r\n",__FUNCTION__,__LINE__,(char)(num>>8));
printf("%s[%d]%d\r\n",__FUNCTION__,__LINE__,(char)(num&0xFF));
#endif
return 4;
}
int sendAck(unsigned short packNum, int socket)
{
char send_buffer[10]={0};
#ifdef TFTP_PRINTF_DEBUG
printf("%s[%d]%d\r\n",__FUNCTION__,__LINE__,packNum);
#endif
int len = makeack(packNum,send_buffer,sizeof(send_buffer));
return send(socket,send_buffer,len,0);
}
int makeerr(unsigned short num,char *buffer)
{
buffer[0]=0;
buffer[1]=TFTP_ERROR;
buffer[2] = (char)(num>>8);
buffer[3] = (char)num;
return 4;
}
unsigned short transPackNum(unsigned short sorcePackNum)
{
unsigned short ret;
#ifdef TFTP_PRINTF_DEBUG
printf("%s[%d] %x \r\n",__FUNCTION__,__LINE__,sorcePackNum);
#endif
ret = (sorcePackNum>>8)+((sorcePackNum&0xFF)<<8);
return ret;
}
int downloadFile(char * serverIp,char * fileName,tftpDownLoadCallback pTftpDownLoadCallback,void * arg)
{
struct sockaddr_in addr;
if(0==serverIp||fileName==0||pTftpDownLoadCallback==0)
{
return -1;
}
int sock;
err_t err;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(69);
addr.sin_addr.s_addr = inet_addr(serverIp);
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
xil_printf("UDP client: Error creating Socket\r\n");
return -2;
}
err = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
if (err != ERR_OK) {
xil_printf("UDP client: Error on connect: %d\r\n", err);
close(sock);
return -2;
}
struct timeval tv_out;
tv_out.tv_sec = 5;
tv_out.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv_out, sizeof(tv_out));
if(sendRequest(TFTP_RRQ,fileName,OCTET_FORMAT,sock))
{
long long recvDatLen = 0;
int dataCacheLen = 0;
char * fileDataCache = (char*)malloc(520);
char * recvData = (char*)malloc(600);
unsigned short lastPackNum = -1;
while(1)
{
int recvLen = recv(sock,recvData,600,0);
printf("%d\r\n",recvLen);
if(recvLen>0)
{
if(TFTP_DATA == recvData[1])
{
unsigned short currentPackNum = transPackNum(((unsigned short*)recvData)[1]);
#ifdef TFTP_PRINTF_DEBUG
printf("currentPackNum %x %x %x\r\n",currentPackNum,recvData[2],recvData[3]);
#endif
if((unsigned short)(-1)==lastPackNum||lastPackNum+1==currentPackNum||(lastPackNum==65535&&0==currentPackNum))
{
#ifdef TFTP_PRINTF_DEBUG
printf("%s[%d]%d\r\n",__FUNCTION__,__LINE__,lastPackNum);
#endif
lastPackNum = currentPackNum;
recvDatLen+=(recvLen-4);
{//!< callbackData
if(dataCacheLen)
{
//!<TODO 上一次数据回调出去
pTftpDownLoadCallback(fileDataCache,dataCacheLen,arg);
dataCacheLen = 0;
}
//!< 缓存当前数据
memcpy(fileDataCache,recvData+4,recvLen-4);
dataCacheLen = recvLen-4;
}
sendAck(currentPackNum,sock);
if(recvLen<4+512)
{
if(dataCacheLen)
{
//!<TODO 上一次数据回调出去
pTftpDownLoadCallback(fileDataCache,dataCacheLen,arg);
dataCacheLen = 0;
}
dataCacheLen = recvLen-4;
memcpy(fileDataCache,recvData+4,recvLen-4);
if(dataCacheLen)
{
//!<TODO 最后一次数据回调出去
pTftpDownLoadCallback(fileDataCache,dataCacheLen,arg);
dataCacheLen = 0;
}
printf("%lldByte\r\n",recvDatLen);
puts("recv Finish!!!");
break;
}
}
else
{
//error
#ifdef TFTP_PRINTF_DEBUG
printf("%s[%d]%d\r\n",__FUNCTION__,__LINE__,lastPackNum);
#endif
sendAck(lastPackNum,sock);
}
}
}
else if(recvLen<0)
{
break;
}
}
free(recvData);
free(fileDataCache);
}
close(sock);
return 0;
}
//Data包填充
int makedata(unsigned short num,char *data,long long datasize,long long currentPos,char *buffer,int bufsize)
{
int pos = 0;
buffer[pos] = 0;
pos++;
buffer[pos] = TFTP_DATA; //操作码为03
pos++;
buffer[pos] = (char)(num>>8);//块号
pos++;
buffer[pos] = (char)num;
pos++;
datasize = (datasize-currentPos)>512?512:(datasize-currentPos);
memcpy(&buffer[pos],data+currentPos,datasize);//填充数据
pos = pos + datasize;
return pos;
}
int uploadFile(char * serverIp,char * destFileName,char * sourceData,long long dataLen)
{
struct sockaddr_in addr;
if(0==serverIp||destFileName==0||sourceData==0||dataLen==0)
return -1;
int sock;
err_t err;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(69);
addr.sin_addr.s_addr = inet_addr(serverIp);
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
xil_printf("UDP client: Error creating Socket\r\n");
return -2;
}
err = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
if (err != ERR_OK) {
xil_printf("UDP client: Error on connect: %d\r\n", err);
close(sock);
return -2;
}
if(sendRequest(TFTP_WRQ,destFileName,OCTET_FORMAT,sock))
{
long long currentPos = 0;
char * dataPack = (char *)malloc(600);
char * recvData = (char*)malloc(64);
unsigned short lastPackNum = -1;
while(1)
{
int recvLen = recv(sock,recvData,64,0);
if(recvLen>0)
{
if(TFTP_ACK == recvData[1])
{
unsigned short currentPackNum = transPackNum(((unsigned short*)recvData)[1]);
currentPackNum++;
//发送第一个包
int packLen = makedata(currentPackNum,sourceData,dataLen,currentPos,dataPack,600);
send(sock,dataPack,packLen,0);
if(packLen<4+512)
{
puts("Send Finish!!");
break;
}
}
else if(TFTP_ERROR == recvData[1])
{
printf("TFTP ERROR(CODE = %d)\r\n",recvData[3]);
close(sock);
free(recvData);
free(dataPack);
return -3;
}
}
}
close(sock);
free(recvData);
free(dataPack);
}
return 0;
}