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

发布于 2024-12-01 11:51:50 字数 594 浏览 0 评论 0原文

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

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

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

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

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

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

我还有其他选择吗?

感谢您的时间和评论;)

I receive values using winsock from another computer on the network. It is a TCP socket, with the 4 first bytes of the message carrying its size. The rest of the message is formatted by the server using protobuf (protocol buffers from google).

The problemn, I think, is that it seems that the values sent by the server are hex values sent as char (ie only 10 received for 0x10). To receive the values, I do this :

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

where data_s is a stringstream. Them I can use the ParseFromIstream(&data_s) method from protobuf and recover the information I want.

The problem that I have is that this is VERY VERY long (I got another implementation using QSock taht I can't use for my project but which is much faster, so there is no problem on the server side).

I tried many things that I took from here and everywhere on the internet (using Arrays of bytes, strings), but nothing works.

Do I have any other options ?

Thank you for your time and comments ;)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

风吹雪碎 2024-12-08 11:51:50

不确定这是否有任何用处,但我之前使用过类似的协议(前 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)
}

not sure if this will be of any use, but I've used a similar protocol before (first 4 bytes holds an int with the length, rest is encoded using protobuf) and to decode it I did something like this (probably not the most efficient solution due to appending to strings):

// 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)
}
寻梦旅人 2024-12-08 11:51:50

我不会使用流运算符。它们用于格式化数据,但这不是您想要的。

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

如果你想使用向量方法,你可以使用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));

I wouldn't use the stream operators. They're for formatted data and that's not what you want.

You can keep the values received in a std::vector with the char type (vector of bytes). That would essentially just be a dynamic array. If you want to continue using a string stream, you can use the stringstream::write function which takes a buffer and a length. You should have the buffer and number of bytes received from your call to recv.

If you want to use the vector method, you can use std::copy to make it easier.

#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));
颜漓半夏 2024-12-08 11:51:50

你的问题有点模棱两可。让我们以你的例子为例。您收到字符形式的10,并且希望将其检索为十六进制数字。

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

首先使其以 null 终止:

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

但这只是一个明显的例子。实际上,您可以通过位移来实现,而不是乘法。

Your question is kind of ambiguous. Let's follow your example. You receive 10 as characters and you want to retrieve this as a hex number.

Assuming recv will give you this character string, you can do this.

First of all make it null terminated:

bytesreceived[msg_size] = '\0';

then you can very easily read the value from this buffer using standard *scanf function for strings:

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

There you go!

Edit: If you receive the number in reverse order (so 01 for 10), probably your best shot is to convert it manually:

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

This is just a clear example though. In reality you would do it with bit shifting for example rather than multiplying.

幸福不弃 2024-12-08 11:51:50

buffer 是什么数据类型?

整个事情看起来像是一个很大的空操作,因为 operator<<(stringstream&, char) 忽略了基本说明符。 hex 说明符仅影响非字符整型类型的格式。当然,您不想将文本数据传递给 protobuf。

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

What data type is buffer?

The whole thing looks like a great big no-op, since operator<<(stringstream&, char) ignores the base specifier. The hex specifier only affects formatting of non-character integral types. For certain you don't want to be handing textual data to protobuf.

Just hand the buffer pointer to protobuf, you're done.

眼泪也成诗 2024-12-08 11:51:50

好吧,大胆猜测一下:假设您的入口流是 "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
}

OK, a shot into the dark: Let's say your ingress stream is "71F4E81DA...", and you want to turn this into a byte stream { 0x71, 0xF4, 0xE8, ...}. Then we can just assemble the bytes from the character literals as follows, schematically:

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);
}

Here we use a little helper function:

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文