如何解决TFTP客户端和服务器通信中小端到大端的问题?
我正在 cPP 中为 TFTP 客户端创建 WRQ 数据包。该代码在 Little Endian 系统(PC)中工作正常,但在创建数据包时在 Big Endian 系统中存在问题。
代码是
#define TFTP_OPCODE_READ 1
#define TFTP_OPCODE_WRITE 2
#define TFTP_OPCODE_DATA 3
#define TFTP_OPCODE_ACK 4
#define TFTP_OPCODE_ERROR 5
#define cTFTPPacket_MAX_SIZE 1024
#define cTFTPPacket_DATA_SIZE 512
#define TFTP_DEFAULT_TRANSFER_MODE "octet" //"netascii", "octet", or "mail"
typedef unsigned char BYTE;
typedef unsigned short WORD;
///////////////////////// below is Packet.cpp file ///////
bool cTFTPPacket::addByte(BYTE b)
{
if (mCurPacketSize >= cTFTPPacket_MAX_SIZE)
{
return false;
}
mData[mCurPacketSize] = (unsigned char)b;
mCurPacketSize++;
return true;
}
bool cTFTPPacket::addWord(WORD w)
{
if (!addByte(*(((BYTE*)&w)+1)))
{
return false;
}
return (!addByte(*((BYTE*)&w)));
}
bool cTFTPPacket::addString(char* str)
{
int n = strlen(str);
int i=0;
for (i=0;i<n;i++)
{
if (!addByte(*(str + i)))
{
return false;
}
}
return true;
}
预期数据包是
0x00 0x02 string 0x00 octet 0x00
在大端中获取是
0x02 0x00 string 0x00 octet 0x00
创建数据包的代码
bool cTFTPPacket::createWRQ(char* filename)
{
/* structure is the same as RRQ */
clear();
addWord(TFTP_OPCODE_WRITE);
addString(filename);
addByte(0);
addString(TFTP_DEFAULT_TRANSFER_MODE);
addByte(0);
return true;
}
bool cTFTPPacket::createACK(int packet_num)
{
clear();
addWord(TFTP_OPCODE_ACK);
addWord(packet_num);
return true;
}
bool cTFTPPacket::createData(int block, char* mData, int data_size)
{
/* 2 bytes 2 bytes n bytes
----------------------------------------
DATA | 03 | Block # | Data |
---------------------------------------- */
clear(); // to clean the memory location
addWord(TFTP_OPCODE_DATA);
addWord(block);
addMemory(mData, data_size);
return true;
}
bool cTFTPPacket::addMemory(char* buffer, int len)
{
bool oStatus=false;
if (mCurPacketSize + len >= cTFTPPacket_MAX_SIZE)
{
cout<<("Packet max size exceeded");
oStatus= false;
}
else
{
memcpy(&(mData[mCurPacketSize]), buffer, len);
mCurPacketSize += len;
oStatus= true;
}
return oStatus;
}
BYTE cTFTPPacket::getByte(int offset)
{
return (BYTE)mData[offset];
}
WORD cTFTPPacket::getWord(int offset)
{
WORD hi = getByte(offset);
//WORD lo = getByte(offset + 1);
WORD lo = getByte(offset + 1);
return ((hi<<8)|lo);
}
WORD cTFTPPacket::getNumber()
{
if (this->isData() || this->isACK())
{
return this->getWord(2);
}
else
{
return 0;
}
}
bool cTFTPPacket::getString(int offset, char* buffer, int len)
{
bool oStatus=false;
if (offset > mCurPacketSize)
{
oStatus=false;
}
else if (len < mCurPacketSize - offset)
{
oStatus= false;
}
else
{
memcpy(buffer, &(mData[offset]), mCurPacketSize - offset);
oStatus= true;
}
return oStatus;
}
bool cTFTPPacket::createError(int error_code, char* message) {
/* 2 bytes 2 bytes string 1 byte
----------------------------------------
ERROR | 05 | ErrorCode | ErrMsg | 0 |
---------------------------------------- */
clear();
addWord(TFTP_OPCODE_ERROR);
addWord(error_code);
addString(message);
addByte(0);
return true;
}
int cTFTPPacket::getSize()
{
return mCurPacketSize;
}
bool cTFTPPacket::setSize(int size)
{
if (size <= cTFTPPacket_MAX_SIZE)
{
mCurPacketSize = size;
return true;
}
else
{
return false;
}
}
bool cTFTPPacket::isRRQ()
{
return (this->getWord(0) == TFTP_OPCODE_READ);
}
bool cTFTPPacket::isWRQ()
{
return (this->getWord(0) == TFTP_OPCODE_WRITE);
}
bool cTFTPPacket::isACK()
{
return (this->getWord(0) == TFTP_OPCODE_ACK);
}
bool cTFTPPacket::isData() {
return (this->getWord(0) == TFTP_OPCODE_DATA);
}
bool cTFTPPacket::isError()
{
return (this->getWord(0) == TFTP_OPCODE_ERROR);
}
void cTFTPPacket::clear()
{
mCurPacketSize = 0;
memset(mData, mCurPacketSize, cTFTPPacket_MAX_SIZE);
}
unsigned char* cTFTPPacket::getData(int offset)
{
return &(mData[offset]);
}
bool cTFTPPacket::copyData(int offset, char* dest, int length)
{
bool oStatus=false;
if (offset > this->getSize())
{
oStatus= false;
}
else if (length < (this->getSize() - offset))
{
oStatus= false;
}
else
{
memcpy(dest, &(mData[offset]), (this->getSize()-offset));
oStatus= true;
}
return oStatus;
}
void cTFTPPacket::dumpData() {
xRM_DEBUG("\n--------------DATA DUMP---------------------\n");
xRM_DEBUG("Size: " << mCurPacketSize );
for (int i = 0; i < mCurPacketSize; i++)
{
xRM_DEBUG(mData[i]);
cout<<mData[i];
}
}
cTFTPPacket::~cTFTPPacket() {
}
我认为问题发生在Addword 和 get Word 如何解决这个问题。 还有一件事,我的服务器是小端(普通的 Linux 机器),而硬件是大端
i am creating WRQ packet for TFTP client in cPP. the code works fine in Little endian system (PC) and have proble m with Big Endian system while creating packets.
the code is
#define TFTP_OPCODE_READ 1
#define TFTP_OPCODE_WRITE 2
#define TFTP_OPCODE_DATA 3
#define TFTP_OPCODE_ACK 4
#define TFTP_OPCODE_ERROR 5
#define cTFTPPacket_MAX_SIZE 1024
#define cTFTPPacket_DATA_SIZE 512
#define TFTP_DEFAULT_TRANSFER_MODE "octet" //"netascii", "octet", or "mail"
typedef unsigned char BYTE;
typedef unsigned short WORD;
///////////////////////// below is Packet.cpp file ///////
bool cTFTPPacket::addByte(BYTE b)
{
if (mCurPacketSize >= cTFTPPacket_MAX_SIZE)
{
return false;
}
mData[mCurPacketSize] = (unsigned char)b;
mCurPacketSize++;
return true;
}
bool cTFTPPacket::addWord(WORD w)
{
if (!addByte(*(((BYTE*)&w)+1)))
{
return false;
}
return (!addByte(*((BYTE*)&w)));
}
bool cTFTPPacket::addString(char* str)
{
int n = strlen(str);
int i=0;
for (i=0;i<n;i++)
{
if (!addByte(*(str + i)))
{
return false;
}
}
return true;
}
Expected packet is
0x00 0x02 string 0x00 octet 0x00
Obtain in big endian is
0x02 0x00 string 0x00 octet 0x00
Code to create the Packets are
bool cTFTPPacket::createWRQ(char* filename)
{
/* structure is the same as RRQ */
clear();
addWord(TFTP_OPCODE_WRITE);
addString(filename);
addByte(0);
addString(TFTP_DEFAULT_TRANSFER_MODE);
addByte(0);
return true;
}
bool cTFTPPacket::createACK(int packet_num)
{
clear();
addWord(TFTP_OPCODE_ACK);
addWord(packet_num);
return true;
}
bool cTFTPPacket::createData(int block, char* mData, int data_size)
{
/* 2 bytes 2 bytes n bytes
----------------------------------------
DATA | 03 | Block # | Data |
---------------------------------------- */
clear(); // to clean the memory location
addWord(TFTP_OPCODE_DATA);
addWord(block);
addMemory(mData, data_size);
return true;
}
bool cTFTPPacket::addMemory(char* buffer, int len)
{
bool oStatus=false;
if (mCurPacketSize + len >= cTFTPPacket_MAX_SIZE)
{
cout<<("Packet max size exceeded");
oStatus= false;
}
else
{
memcpy(&(mData[mCurPacketSize]), buffer, len);
mCurPacketSize += len;
oStatus= true;
}
return oStatus;
}
BYTE cTFTPPacket::getByte(int offset)
{
return (BYTE)mData[offset];
}
WORD cTFTPPacket::getWord(int offset)
{
WORD hi = getByte(offset);
//WORD lo = getByte(offset + 1);
WORD lo = getByte(offset + 1);
return ((hi<<8)|lo);
}
WORD cTFTPPacket::getNumber()
{
if (this->isData() || this->isACK())
{
return this->getWord(2);
}
else
{
return 0;
}
}
bool cTFTPPacket::getString(int offset, char* buffer, int len)
{
bool oStatus=false;
if (offset > mCurPacketSize)
{
oStatus=false;
}
else if (len < mCurPacketSize - offset)
{
oStatus= false;
}
else
{
memcpy(buffer, &(mData[offset]), mCurPacketSize - offset);
oStatus= true;
}
return oStatus;
}
bool cTFTPPacket::createError(int error_code, char* message) {
/* 2 bytes 2 bytes string 1 byte
----------------------------------------
ERROR | 05 | ErrorCode | ErrMsg | 0 |
---------------------------------------- */
clear();
addWord(TFTP_OPCODE_ERROR);
addWord(error_code);
addString(message);
addByte(0);
return true;
}
int cTFTPPacket::getSize()
{
return mCurPacketSize;
}
bool cTFTPPacket::setSize(int size)
{
if (size <= cTFTPPacket_MAX_SIZE)
{
mCurPacketSize = size;
return true;
}
else
{
return false;
}
}
bool cTFTPPacket::isRRQ()
{
return (this->getWord(0) == TFTP_OPCODE_READ);
}
bool cTFTPPacket::isWRQ()
{
return (this->getWord(0) == TFTP_OPCODE_WRITE);
}
bool cTFTPPacket::isACK()
{
return (this->getWord(0) == TFTP_OPCODE_ACK);
}
bool cTFTPPacket::isData() {
return (this->getWord(0) == TFTP_OPCODE_DATA);
}
bool cTFTPPacket::isError()
{
return (this->getWord(0) == TFTP_OPCODE_ERROR);
}
void cTFTPPacket::clear()
{
mCurPacketSize = 0;
memset(mData, mCurPacketSize, cTFTPPacket_MAX_SIZE);
}
unsigned char* cTFTPPacket::getData(int offset)
{
return &(mData[offset]);
}
bool cTFTPPacket::copyData(int offset, char* dest, int length)
{
bool oStatus=false;
if (offset > this->getSize())
{
oStatus= false;
}
else if (length < (this->getSize() - offset))
{
oStatus= false;
}
else
{
memcpy(dest, &(mData[offset]), (this->getSize()-offset));
oStatus= true;
}
return oStatus;
}
void cTFTPPacket::dumpData() {
xRM_DEBUG("\n--------------DATA DUMP---------------------\n");
xRM_DEBUG("Size: " << mCurPacketSize );
for (int i = 0; i < mCurPacketSize; i++)
{
xRM_DEBUG(mData[i]);
cout<<mData[i];
}
}
cTFTPPacket::~cTFTPPacket() {
}
i figured the proble is occuring in Addword and get Word how to over come this problem.
and one more thing my server is little endian (normal linux machine) and hardware is big endian
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当您处理其中一台机器可能是大端字节序时,您需要在发送时将所有内容转换为网络字节顺序。
您需要的函数是 htonl、htons(主机到网络长/短)
当接收到数据时,您可以使用相反的方法将数据转换为本地计算机需要的任何内容;
ntohl
和ntohs
。在大端机器上,这些是无操作的并且数据保持不变。在小端机器上,它们转换为正确的(小端)字节顺序。编辑:回复下面OP的评论:
您的
WORD
是一个无符号短
。这意味着您需要在addWord()
函数中使用htons()
对其进行转换:然后在
getWord()
函数中反转该过程:When you're dealing with the possibility of one of the machines involved being big endian you need to convert everything to network byte order when you send.
The functions you need are
htonl
,htons
(host to network long / short)When receiving the data you convert to whatever the local machine needs using the reverse;
ntohl
andntohs
. On the big endian machine these are no-op and the data remains unchanged. On the little endian machine they convert to the correct (little endian) byte order.Edit: In reply to OP's comment below:
Your
WORD
is anunsigned short
. This means you need to convert it usinghtons()
in youraddWord()
function:And then reverse the process in your
getWord()
function:“传统”方法是假装只有两个
可能的顺序(虽然我至少见过三个),并且所有
机器是8位字节的二进制补码。更好的方法是
逻辑处理数字格式。对于无符号,类似于:
这很容易扩展到可以是的任何大小的无符号整数
代表在您的机器上。
对于有符号输出,如果格式指定2的补码,只需转换
到无符号——标准要求这样的转换才能正确进行
事物。在输入方面,要真正便携,您必须读取更大的内容
type,测试读取的无符号值是否大于
最大有符号值,如果是,则减去相应的无符号值
最大限度;然而,在大多数机器上,只需读入无符号,然后
转换为有符号类型将会起作用。
The "traditional" approach is to pretend that there are only two
possible orderings (although I've seen at least three), and that all
machines are twos complement with 8 bit bytes. A better approach is to
process the numeric format logically. For unsigned, something like:
This easily extends to any size of unsigned integers that can be
represented on your machine.
For signed output, if the format specifies 2's complement, just convert
to unsigned—the standard requires such conversions to do the right
thing. On input, to be really portable, you have to read into a larger
type, test whether the unsigned value you read is greater than the
maximum signed value, and if so, subtract the corresponding unsigned
max; on most machines, however, just reading into an unsigned, then
converting to the signed type will work.
传统的方法是使用 htons(将 16 位值从主机字节顺序转换为网络字节顺序)和 ntohs(从网络字节顺序转换为主机字节顺序);类似地,对于 32 位值,
ntohl
和htonl
。The traditional approach is to use
htons
(to convert a 16 bit value from host to network byte order) andntohs
(to convert from network to host byte order); similarlyntohl
andhtonl
for 32bit values.