Qt 套接字和字节顺序
我正在编写一个使用 QUdpSocket 通过网络传输数据的程序。这是我的第一个套接字程序,我遇到了一个有趣的问题,称为字节序。
我的实际问题是,当我使用 QNetwork 作为套接字库时,我是否需要担心字节顺序?如果我确实需要担心,我需要做什么才能正确避免字节序问题?
I'm writing a program that uses QUdpSocket for transmitting data over the network. This is my first socket program, and I've come across an interesting problem called Endianness.
My actual question in, do I have to worry about Endianness when I'm using QNetwork as my sockets library? If I do have to worry, what do I have to do to properly avoid Endianness problems?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
通常,当您将大于单个字节的整数从一台计算机传输到另一台计算机时,您需要担心字节顺序。在 C/C++ 中,这意味着如果您要发送 16 位、32 位或 64 位整数之类的内容,则需要首先将整数转换为网络字节顺序,(也称为大端字节序)。然后,接收端的计算机必须将传入的整数转换为主机字节顺序,这是主机本机使用的任何字节顺序。这通常使用
htons
和ntohs
系列库函数来完成,但使用 Qt 库,您还可以使用qToBigEndian
和qFromBigEndian
函数。请注意,发送 ASCII 或 UTF-8 文本时无需担心字节顺序,因为这些格式由单个字节序列组成,而不是多字节数据类型。
Generally, you need to worry about endianness (byte-order) when you transfer integers larger than a single byte from one computer to another. In C/C++, this means that if you're sending something like a 16-bit, 32-bit or 64-bit integer, you need to first convert the integer to network byte order, (also known as Big-Endian). The computer on the receiving end must then convert the incoming integers to host byte order, which is whatever byte-order the host-machine uses natively. This is usually done using the
htons
andntohs
series of library functions, but with the Qt library you can also use theqToBigEndian
andqFromBigEndian
functions.Note that you don't need to worry about endianness when sending ASCII or UTF-8 text, because these formats are composed of sequences of individual bytes, rather than multi-byte data types.
如果您在两台具有不同字节顺序的机器之间传输二进制数据,您可能需要担心。
网络套接字将仅发送未更改的数据。如果其他机器假设它发送的字节是按特定顺序排列的,那么您必须对此进行管理。
如果您以已知格式(例如图像)传输数据,则图像格式通常在标头中包含一些内容来显示其写入顺序,并且读取器/写入器库将处理它。
如果您正在发明自己的二进制格式 - 那么这取决于您。您可能还必须考虑大小,另一台机器上的 int 有多少字节?
好消息是,大多数机器都是 Intel 的,对于大多数应用程序来说,以 ASCII 格式传输少量数据是可行的。
If you are transferring binary data between two machines with a different endianess you may have to worry.
The network socket will just ship the data unchanged. If the other machines assumes that the bytes it was sent are in a particular order you have to manage that.
If you are transferring data in a known format, like an image then image format generally has something in the header to show what order it was written in and the reader/writer library will handle it.
If you are inventing your own binary format - then it's upto you. You may also have to consider size, how many bytes is an int on the other machine?
The good news, most machines are Intel and for most applications shipping smaller amounts of data in ascii format will work.
如果您需要的话,这里有一个针对大字节序的简单测试:
// This test Shoulds an int size of at least 2.
static const int testValue = 1;
#define is_bigendian() ( ((char)&testValue) == 0 )
bool CD_is_bigendian(void)
{
返回 is_bigendian();
}
Here's a simple test for big endianness, in case you want it:
// This test assumes an int size of at least 2.
static const int testValue = 1;
#define is_bigendian() ( ((char)&testValue) == 0 )
bool CD_is_bigendian(void)
{
return is_bigendian();
}
我知道这个问题很久以前就得到了回答,但我只是想补充一下。
您可以使用 QDataStream 功能,而不是使用字节序转换函数(使用任何 QIODevice),在我看来,这更容易更直观。当然,这会限制您在发送方和接收方上使用 QDataStream,但对于这种情况来说这是值得的。
示例用法,对于其他人发送图像的示例:
QDataStream &运算符<< (QDataStream&流,const QImage&图像);
QDataStream &运算符>> (QDataStream&流、QImage&图像);
(这两者都已在 Qt 中实现。)
QTcpSocket *tcp = ...;
QImage img = ...;
QDataStream(tcp)<<图像;
I know this was answered a long time ago, but I just thought I'd add to it.
Instead of using the endian conversion functions, you could use the QDataStream functionality (with any QIODevice), which is much easier and more intuitive in my opinion. Of course, that would lock you into using the QDataStream on both the sender and receiver, but it's worth it for that case.
Example usage, for someone else's sample of sending an image:
QDataStream & operator<< (QDataStream& stream, const QImage& image);
QDataStream & operator>> (QDataStream& stream, QImage& image);
(Both of those are already implemented within Qt.)
QTcpSocket *tcp = ...;
QImage img = ...;
QDataStream(tcp) << img;
Intel CPU 使用小端字节序。大多数其他内容都是大端。默认的网络字节顺序是大端字节序。
要测试字节顺序是否有问题,请发送值 0x12345678 并检查它是否与 0x78563412 相同。如果接收计算机上的值是较晚的值,则两个系统之间的字节顺序不同。
有关字节顺序的信息,请查看这篇维基百科文章。
Intel CPUs use little endian. Most everything else is big endian. The default network byte order is big endian.
To test if endianness is a problem, send the value 0x12345678 and check if it makes it as the same or 0x78563412. If the value on the receiving computer is the later value, then the endianness is not the same between the two systems.
Check this wikipedia article for info on endianness.