参见TL的底部; DR
背景信息(透视)
我正在实现一个客户端服务器,客户端请求数据,通过set char缓冲区发送,设置大小为char [256]
服务器以2阶段响应进行实物响应, 首先发送一个'标头包'使用头缓冲区(在客户端和服务器上都有大小为char [20]),包含要遵循的数据包数量和要发送的最大数据包的大小(以分配"数据"缓冲区),
假设从服务器发送的文本如下
QString text = QString("TOKEN=1SOMETOKENSTRING123;");
//length of text = 26 char
这个"标头包"通过使用:
成功接收,解析和实现,无需转换为QString//header
char header_buffer[20];
bzero(header_buffer, sizeof (header_buffer));
//assign header_buffer using socket.recv()
QString header = QString(header_buffer);
这已成功完成
问题信息:
解析标头并输出属性大小(最大数据包大小)和计数('数据'要跟随的数据包的数量)
这就是问题所在:
//data packet section
//returns the size of largest packet using the received "header packet" - done successfully
int maxSize = getMaxPacketSize(header_buffer);
//maxSize = 27 char, which is the length of the 'text' String sent from the server, thus
char data_buffer[maxSize]; //char[27]
bzero(data_buffer, sizeof (data_buffer));
//assign data_buffer using socket.recv()
QString data = QString(data_buffer);
qDebug() << data_buffer; CORRECT //displays "TOKEN=1SOMETOKENSTRING123;"
qDebug() << data; ERROR //displays "TOKEN=1SOMETOKENSTRING123;UUU"
确切问题:
从char []创建新的QString会增加3&#39; U&#39;字符串结尾的字符:
基本示例:
char cArray[27] //assume it has contents to fill all, size/count = 27
QString str = QString(cArray);
int len = str.length();
//len = 30, last 3 char of str = "UUU"
数据示例(**实际数据):
int packetSize = getMaxPacketSize(buffer); buffer[20] = "COUNT=2;SIZE=27;\000\000\000\000"
char packet[packetSize]; // = 27
size_t size = sizeof (packet); // = 27
bzero(packet, sizeof (packet));
if (recv(sockfd,packet,sizeof (packet),0) < 0) {
qDebug() << "ERROR netman: reading data from socket";
//more code here
}
//Add packet to packet_data list
//NOTE : QList<QString> packet_data = QList<QString>();
//NOTE: packet[27] = "TOKEN=a7nCrDbaycWx2JzMir4m;"
packet_data.insert(packetSize-packetNum,QString(packet));
QString d = packet_data.first(); d = "TOKEN=a7nCrDbaycWx2JzMir4m;UUU"
调试器数据的详细程度
Locals
d "TOKEN=a7nCrDbaycWx2JzMir4m;UUU" QString
[0] 'T' 84 0x0054 QChar
[1] 'O' 79 0x004f QChar
[2] 'K' 75 0x004b QChar
[3] 'E' 69 0x0045 QChar
[4] 'N' 78 0x004e QChar
[5] '=' 61 0x003d QChar
[6] 'a' 97 0x0061 QChar
[7] '7' 55 0x0037 QChar
[8] 'n' 110 0x006e QChar
[9] 'C' 67 0x0043 QChar
[10] 'r' 114 0x0072 QChar
[11] 'D' 68 0x0044 QChar
[12] 'b' 98 0x0062 QChar
[13] 'a' 97 0x0061 QChar
[14] 'y' 121 0x0079 QChar
[15] 'c' 99 0x0063 QChar
[16] 'W' 87 0x0057 QChar
[17] 'x' 120 0x0078 QChar
[18] '2' 50 0x0032 QChar
[19] 'J' 74 0x004a QChar
[20] 'z' 122 0x007a QChar
[21] 'M' 77 0x004d QChar
[22] 'i' 105 0x0069 QChar
[23] 'r' 114 0x0072 QChar
[24] '4' 52 0x0034 QChar
[25] 'm' 109 0x006d QChar
[26] ';' 59 0x003b QChar
[27] 'U' 85 0x0055 QChar
[28] 'U' 85 0x0055 QChar
[29] 'U' 85 0x0055 QChar
message "AUTH;U=user@example;P=Pass;" char *
packet "TOKEN=a7nCrDbaycWx2JzMir4m;" char [27]
packetNum 1 int
packetSize 27 int
s "COUNT=2;SIZE=27;" QString
size 27 size_t
this @0x7fffffffd190 netman
buffer "COUNT=2;SIZE=27;\000\000\000\000" char [20]
cli_addr @0x7fffffffd1c0 sockaddr_in
clilen 1431695692 socklen_t
n 1436538608 int
newsockfd 32767 int
packet_data <1 items> QList<QString>
serv_addr @0x7fffffffd1b0 sockaddr_in
server @0x7ffff5f071c0 hostent
sockfd 13 int
我不知道这三个额外的字母来自哪里!
任何建议/想法?
答案 0 :(得分:2)
这里的主要问题是你将char*
传递给期望c字符串的函数。也就是说,最后是一个零值的字符串。但是来自套接字的输入不包含这样的字节。
读取数组的末尾是未定义的行为,但在这种情况下,很容易推断出发生了什么:读取字节直到找不到空值,并且很快就会找到它(在3个字节之后)< SUP> 1
你可以通过使用那些采用从数组中读取的确切字节数的函数来轻松修复它。
最简单的方法是使用QString
的{{3}}或fromUtf8
或fromLatin1
成员函数来提供您想要读取的字节数:
QString str = QString::fromUtf8(cArray, number_of_bytes);
话虽如此,考虑使用fromLocal8Bit
从网络读取数据:
QByteArray data(cArray, number_of_bytes);
1 推理未定义行为会发生什么,应该用盐,因为编译器可以自由地做任何事情,如果他们可以探测它发生。
答案 1 :(得分:1)
您使用什么编译器(版本和cppflags)?
//returns the size of largest packet using the received "header packet" - done successfully
int maxSize = getMaxPacketSize(header_buffer);
//maxSize = 27 char, etc
char data_buffer[maxSize]; //char[27]
// ^
// really?-------+ Variable Length Array on standard C++?
// does this even compile?
cppreference.com上的数组声明:
noptr-declarator [ expr(optional) ] attr(optional)
...
expr
- 一个integral constant expression
(直到C ++ 14)转换后的constant expression of type std::size_t
(自C ++ 14开始),其值为大于零
以上相关:如果代码编译(假设有警告而不是错误),这可能会导致未定义的行为 - 例如其中后续函数调用(例如QString构造函数)覆盖VLA的一部分(在堆栈上),在这种情况下擦除nul终止字符,在其他情况下可能是其他效果。
如果发生这种情况,检查(在调试时)缓冲区的内容(在最后一个示例中,packet
var而不是d
var)应该显示更改。