在C / C ++中处理十六进制值

时间:2011-08-26 15:07:16

标签: c++ hex protobuf-net

我使用网络上另一台计算机上的winsock接收值。它是一个TCP套接字,消息的4个第一个字节带有其大小。服务器使用protobuf(来自谷歌的协议缓冲区)格式化消息的其余部分。

我认为问题在于服务器发送的值似乎是以char形式发送的十六进制值(即只有10个接收到0x10)。要接收这些值,我这样做:

bytesreceived = recv(sock, buffer, msg_size, 0);
for (int i=0;i<bytesreceived;i++) 
{
    data_s << hex << buffer[i];
}

其中data_s是一个字符串流。我可以使用protobuf中的ParseFromIstream(&amp; data_s)方法并恢复我想要的信息。

我遇到的问题是这非常非常长(我使用QSock的另一个实现,我不能用于我的项目,但速度要快得多,所以在服务器端没有问题。)

我尝试了很多东西,我从这里和互联网上的任何地方(使用字节数组,字符串),但没有任何作用。

我还有其他选择吗?

感谢您的时间和意见;)

5 个答案:

答案 0 :(得分:2)

不确定这是否有用,但我之前使用过类似的协议(前4个字节保存一个长度为int的字节,其余是使用protobuf编码)并解码它我做了类似的事情(可能由于附加到字符串而不是最有效的解决方案):

// Once I've got the first 4 bytes, cast it to an int:
int msgLen = ntohl(*reinterpret_cast<const int*>(buffer));

// Check I've got enough bytes for the message, if I have then 
// just parse the buffer directly
MyProtobufObj obj;
if( bytesreceived >= msgLen+4 )
{
  obj.ParseFromArray(buffer+4,msgLen);
}
else
{
  // just keep appending buffer to an STL string until I have 
  // msgLen+4 bytes and then do
  // obj.ParseFromString(myStlString)
}

答案 1 :(得分:0)

我不会使用流操作符。它们用于格式化数据,而这不是您想要的。

您可以使用char类型(字节向量)保持std :: vector中接收的值。这基本上只是一个动态数组。如果要继续使用字符串流,可以使用带有缓冲区和长度的stringstream :: write函数。您应该从调用recv。

中获得缓冲区和字节数

如果要使用vector方法,可以使用std :: copy使其更容易。

#include <algorithm>
#include <iterator>
#include <vector>

char buf[256];
std::vector<char> bytes;
size_t n = recv(sock, buf, 256, 0);
std::copy(buf, buf + n, std::back_inserter(bytes));

答案 2 :(得分:0)

你的问题有点含糊不清。让我们按照你的例子。您收到10个字符,并希望将其作为十六进制数字检索。

假设recv会给你这个字符串,你可以这样做。

首先使其终止:

bytesreceived[msg_size] = '\0';

然后您可以使用标准* scanf函数轻松读取此缓冲区中的值:

int hexValue;
sscanf(bytesreceived, "%x", &hexValue);

你去吧!

编辑:如果您以相反的顺序收到号码(01 10),那么最好的方法就是手动转换它:

int hexValue = 0;
int positionValue = 1;
for (int i = 0; i < msg_size; ++i)
{
    int digit = 0;
    if (bytesreceived[i] >= '0' && bytesreceived[i] <= '9')
        digit = bytesreceived[i]-'0';
    else if (bytesreceived[i] >= 'a' && bytesreceived[i] <= 'f')
        digit = bytesreceived[i]-'a';
    else if (bytesreceived[i] >= 'A' && bytesreceived[i] <= 'F')
        digit = bytesreceived[i]-'A';
    else // Some kind of error!
        return error;
    hexValue += digit*positionValue;
    positionValue *= 16;
}

这只是一个明显的例子。实际上,你可以通过比特移位来实现,而不是相乘。

答案 3 :(得分:0)

好的,黑暗中的一击:假设您的入口流是"71F4E81DA...",并且您想将其转换为字节流{ 0x71, 0xF4, 0xE8, ...}。然后我们可以如下所示组装字符文字中的字节,如下:

char * p = getCurrentPointer();

while (chars_left() >= 2)
{
  unsigned char b;
  b  = get_byte_value(*p++) << 8;
  b += get_byte_value(*p++);

  output_stream.insert(b);
}

这里我们使用一个小辅助函数:

unsigned char get_byte_value(char c)
{
  if ('0' <= c && c <= '9') return c - '0';
  if ('A' <= c && c <= 'F') return 10 + c - 'A';
  if ('a' <= c && c <= 'f') return 10 + c - 'a';

  return 0;  // error
}

答案 4 :(得分:0)

哪种数据类型为buffer

整个事情看起来像一个伟大的大型无操作,因为operator<<(stringstream&, char)忽略了基本说明符。 hex说明符仅影响非字符整数类型的格式。确定你不想将文本数据交给protobuf。

只需将buffer指针移交给protobuf,就完成了。