zynq平台tftp客户端

这是一个使用LWIP库实现的UDP TFTP客户端,支持在Zynq7020硬件平台上运行FreeRTOS系统。该客户端具备文件上传和下载功能,通过指定TFTP服务器IP和文件名,利用回调函数处理下载的数据。代码中包含了关键函数如`downloadFile`和`uploadFile`,处理数据传输和错误处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于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;
}

<think>我们正在处理一个关于Zynq设备上修改TFTP下载BIN文件路径的问题。根据用户的问题,我们需要指导用户如何更改TFTP服务器挂载路径,以便Zynq设备可以从新的路径下载BIN文件。在Zynq设备上,TFTP服务通常由TFTP服务器软件提供,例如`tftpd-hpa`(在Linux系统上)。更改TFTP的根目录(即挂载路径)需要修改TFTP服务器的配置文件。以下是针对使用`tftpd-hpa`服务的步骤(假设运行在Linux系统上):1.打开TFTP服务器的配置文件。在大多数基于Debian的系统(如Ubuntu)上,配置文件位于`/etc/default/tftpd-hpa`。2.修改`TFTP_DIRECTORY`变量的值,将其设置为你想要的路径。例如,如果你想将路径改为`/srv/tftp/new_path`,则设置:TFTP_DIRECTORY="/srv/tftp/new_path"3.如果该目录不存在,需要创建该目录并设置适当的权限(通常TFTP服务器需要对该目录有读写权限):sudomkdir-p/srv/tftp/new_pathsudochmod-R777/srv/tftp/new_path#或者更安全的权限设置,例如指定用户和组4.重启TFTP服务以使配置生效:sudosystemctlrestarttftpd-hpa注意:不同的TFTP服务器软件可能有不同的配置方式,以上是针对`tftpd-hpa`的。如果使用的是其他TFTP服务器,请参考其文档。另外,在Zynq设备上,当使用TFTP客户端下载文件时,需要指定文件相对于TFTP根目录的路径。例如,如果TFTP根目录是`/srv/tftp`,而文件位于`/srv/tftp/new_path/file.bin`,那么在Zynq上使用TFTP下载时,路径应为`new_path/file.bin`。如果用户是在Zynq设备上运行TFTP服务器(这种情况较少见,通常TFTP服务器运行在主机上),那么同样需要修改Zynq设备上的TFTP服务器配置。如果用户是在主机上运行TFTP服务器,那么修改主机上的配置即可。由于用户的问题中没有明确TFTP服务器运行的位置,我们假设是运行在主机上(开发主机),而Zynq设备是客户端。因此,总结步骤:-在主机上修改TFTP服务器的配置文件,更改根目录。-确保新目录存在并具有适当权限。-重启TFTP服务。这样,当Zynq设备通过TFTP下载文件时,只需要提供相对于新根目录的路径即可。注意:修改路径后,需要将BIN文件放在新的路径下,否则TFTP服务器将无法找到文件。下面我们将按照上述步骤详细说明。</think>### 如何修改Zynq设备的TFTP挂载路径 在Zynq设备上修改TFTP下载BIN文件的路径,需要修改TFTP服务器的配置文件。以下是具体步骤: #### 1. **定位TFTP配置文件** - 在Linux系统中,TFTP服务通常由`tftpd-hpa`提供 - 配置文件路径:`/etc/default/tftpd-hpa` ```bash sudo nano /etc/default/tftpd-hpa ``` #### 2. **修改根目录参数** 找到`TFTP_DIRECTORY`字段,将其值改为目标路径: ```ini TFTP_DIRECTORY="/new/custom/path" ``` 例如修改为: ```ini TFTP_DIRECTORY="/home/zynq/tftp_bins" ``` #### 3. **创建新目录并授权** ```bash sudo mkdir -p /home/zynq/tftp_bins sudo chmod 777 /home/zynq/tftp_bins # 或指定用户权限 sudo chown nobody:nogroup /home/zynq/tftp_bins ``` #### 4. **重启TFTP服务** ```bash sudo systemctl restart tftpd-hpa sudo systemctl status tftpd-hpa # 验证状态 ``` #### 5. **在Zynq设备验证** 在Zynq终端使用新路径下载: ```bash tftp -g -r your_file.bin 192.168.x.x -l /new/custom/path/your_file.bin ``` #### 6. **防火墙配置(如需要)** 确保防火墙允许TFTP端口(69/UDP): ```bash sudo ufw allow 69/udp ``` **关键点说明**: - TFTP默认使用`/srv/tftp`目录[^1] - 路径权限错误是常见故障原因,需确保`nobody`用户有访问权 - 修改后需重启服务使配置生效
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值