我正在玩网络,而且我已经将一大堆数据转换成我想要的数据块。
基本上我已经制作了一个模型数据包,我希望我的数据包看起来有点像。本质上是一个Char(8位值),表示消息是什么,并且由switch语句检测到,然后根据该8位值之后的数据填充值。我期待我的数据包中包含各种可能不合适的消息。
例如,我最终可能会以心跳结束,或者聊天消息中的一串文字等等。
我只是想能够对我的程序说,从char数组中的某个点获取数据并将类型转换(如果那就是它的术语?)将它们转换为我想要的数据。有什么简单的方法可以做到这一点?
char bufferIncoming[15];
ZeroMemory(bufferIncoming,15);
//Making a mock packet
bufferIncoming[0] = 0x01; //Heartbeat value
bufferIncoming[1] = 0x01; //Heartbeat again just cause I can
bufferIncoming[2] = 0x10; //This should = 16 if its just an 8bit number,
bufferIncoming[3] = 0x00; // This
bufferIncoming[4] = 0x00; // and this
bufferIncoming[5] = 0x00; // and this
bufferIncoming[6] = 0x09; // and this should equal "9" of its is a 32bit number (int)
bufferIncoming[7] = 0x00;
bufferIncoming[8] = 0x00;
bufferIncoming[9] = 0x01;
bufferIncoming[10] = 0x00; //These 4 should be 256 I think when combines into an unsigned int
//End of mockup packet
int bufferSize = 15; //Just an arbitrary value for now
int i = 0;
while (i < bufferSize)
{
switch (bufferIncoming[i])
{
case 0x01: //Heart Beat
{
cout << "Heartbeat ";
}
break;
case 0x10: //Player Data
{
//We've detected the byte that indicates the following 8 bytes will be player data. In this case a X and Y position
playerPosition.X = ??????????; //How do I combine the 4 hex values for this?
playerPosition.Y = ??????????;
}
break;
default:
{
cout << ".";
}
break;
}
i++;
}
cout << " End of Packet\n";
更新
按照Clairvoire的想法,我添加了以下内容。
playerPosition.X = long(bufferIncoming[3]) << 24 | long(bufferIncoming[4]) << 16 | long(bufferIncoming[5]) << 8 | long(bufferIncoming[6]);
注意我改变了移动值。
另一个重要的变化是
unsigned char bufferIncoming[15]
如果我不这样做,我会得到负值与每个元素的组合。我不知道编译器在引擎盖下做了什么,但这很令人讨厌。
你可以想象这不是我首选的解决方案,但我会试一试。 “Chad”有一个很好的例子,说明我如何构建它,而一位来自工作的程序员也推荐了他的实现。但...
我有这种感觉,必须有一种更快捷的方式来做我想做的事情。我尝试过像......
playerPosition.X = *(bufferIncoming + 4) //Only giving me the value of the one hex value, not the combined >_<
playerPosition.X = reinterpret_cast<unsigned long>(&bufferIncoming); //Some random number that I dont know what it was
..以及我删除的其他一些不起作用的东西。我期待做的是指向char缓冲区中的某个位置并说“嘿playerPosition,从这个位置开始读取,并根据那里的字节数据填写你的值”。
比如说......
playerPosition = (playerPosition)bufferIncoming[5]; //Reads from this spot and fills in the 8 bytes worth of data
//or
playerPosition.Y = (playerPosition)bufferIncoming[9]; //Reads in the 4 bytes of values
...为什么它不像那样或类似的东西?
答案 0 :(得分:1)
可能有一个漂亮的版本,但我个人会用左移和ors组合四个char变量,如下所示:
playerPosition.X = long(buffer[0]) | long(buffer[1])<<8 | long(buffer[2])<<16 | long(buffer[3])<<24;
字节顺序不应该是一个问题,因为按位逻辑总是执行相同的,右边的最低顺序(就像那些位置在右边的十进制数字一样)
编辑:字节顺序可能会成为一个因素,具体取决于发送机器在通过网络发送之前最初将整数分割出来的方式。如果它没有像使用移位重构它那样分解整数,那么你可能得到一个值,其中第一个字节是最后一个,最后一个字节是第一个。像这样的小模糊性促使大多数人使用网络库,啊哈。
使用按位分割整数的示例看起来像这样
buffer[0] = integer&0xFF;
buffer[1] = (integer>>8)&0xFF;
buffer[2] = (integer>>16)&0xFF;
buffer[3] = (integer>>24)&0xFF;
答案 1 :(得分:0)
在典型的消息传递协议中,最直接的方法是使用继承(或组合)以及字节对齐的结构(对于在这种情况下从原始数据指针转换很重要),可以轻松地转换一组消息。 )可以使这相对容易:
struct Header
{
unsigned char message_type_;
unsigned long message_length_;
};
struct HeartBeat : public Header
{
// no data, just a heartbeat
};
struct PlayerData : public Header
{
unsigned long position_x_;
unsigned long position_y_;
};
unsigned char* raw_message; // filled elsewhere
// reinterpret_cast is usually best avoided, however in this particular
// case we are casting two completely unrelated types and is therefore
// necessary
Header* h = reinterpret_cast<Header*>(raw_message);
switch(h)
{
case HeartBeat_MessageType:
break;
case PlayerData_MessageType:
{
PlayerData* data = reinterpret_cast<PlayerData*>(h);
}
break;
}
答案 2 :(得分:0)
在Skype上与我认识的一位程序员交谈,他向我展示了我正在寻找的解决方案。
playerPosition.X = *(int*)(bufferIncoming+3);
我不记得如何让它工作,或者它叫什么。但现在好像都好。
谢谢大家帮忙:)