如何解决TFTP客户端和服务器端通信中的小端到大端问题
how to over come Little endian to big endian problem in TFTP client and server communication.?
我正在为cPP中的TFTP客户端创建WRQ数据包。该代码在小端序系统(PC)中工作良好,在大端序系统中创建数据包时存在问题。
代码是
#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和Word如何克服这个问题。还有一点,我的服务器是小端序(普通Linux机器)硬件是大端序
当你处理其中一台机器可能是大端序时,你需要在发送时将所有内容转换为网络字节顺序。
您需要的功能是htonl
, htons
(主机到网络长/短)
当接收到数据时,使用反向将其转换为本地机器需要的任何数据;ntohl
和ntohs
。在大端机器上,这些都是无操作的,数据保持不变。在小端机器上,它们转换成正确的(小端)字节顺序。
编辑:回复OP下面的评论:
你的WORD
是unsigned short
。这意味着您需要在addWord()
函数中使用htons()
来转换它:
bool cTFTPPacket::addWord(WORD w)
{
w = htons(w);
if (!addByte(*(((BYTE*)&w)+1)))
{
return false;
}
return (!addByte(*((BYTE*)&w)));
}
然后在getWord()
函数中反转这个过程:
WORD cTFTPPacket::getWord(int offset)
{
WORD hi = getByte(offset);
//WORD lo = getByte(offset + 1);
WORD lo = getByte(offset + 1);
return nstoh((hi<<8)|lo);
}
"传统"方法是假装只有两个可能的订单(尽管我至少见过三个),等等机器是两个8位字节的互补体。一个更好的方法是逻辑处理数字格式。对于unsigned,类似于:
void
insertUnsigned16Bits( char* dest, unsigned value )
{
*dest ++ = (value >> 8) & 0xFF;
*dest ++ = (value ) & 0xFF;
}
unsigned
extractUnsigned16Bits( char const* source )
{
unsigned result = 0;
result |= (*source ++ & 0xFF) << 8;
result |= (*source ++ & 0xFF);
return result;
}
这很容易扩展到任意大小的无符号整数
对于有符号输出,如果格式指定2的补码,只需转换对于unsigned—标准要求这样的转换做正确事情在输入上,为了便于携带,你必须读到一个更大的类型,测试您读取的无符号值是否大于最大有符号值,如果是,减去相应的无符号值马克思;然而,在大多数机器上,只是读入unsigned转换成有符号的类型就可以了
传统的方法是使用htons
(将16位值从主机字节顺序转换为网络字节顺序)和ntohs
(从网络字节顺序转换为主机字节顺序);类似ntohl
和htonl
的32位值
- 服务器端事件C++实现?
- 如何使用 GRPC c++ 读取异步服务器端流
- QAbstractSocket 从服务器端关闭连接时的奇怪行为
- 从服务器端关闭主套接字
- 在GRPC服务器端呼叫时检索SSL证书
- BLE在Linux环境中使用C++的服务器端实现
- 如何在服务器端验证用户请求(在我的特定情况下)
- 如何检测端口是否已在服务器端使用(在windows上的C++中)
- RPC C++服务器端动态终结点
- 如果另一侧失去了他的净连接,我该如何从客户端/服务器端检测
- 如何使用php级别以下的代码进行服务器端编程
- 在没有 SO_LINGER > 0 的情况下强制关闭服务器端套接字可能会丢失数据,对吧?
- 提升ASIO TCP,为什么我不能在服务器端只有一个数据套接字可以打开和关闭
- FTP服务器端口处于主动模式和被动模式
- MongoDB C++驱动程序服务器端查询计数
- CORBA C++/Java应用程序中服务器端的分段故障(核心转储)
- 正在比较服务器端收到的字符串-C++
- 如何在boostc++中添加http服务器端口的路径
- 如何解决TFTP客户端和服务器端通信中的小端到大端问题
- 需要在HTML+JavaScript的客户端和Java/C++的服务器端程序之间进行通信