Qt笔记-QTcpSocket中调用readAll要注意的地方(Java中RestTemplate和Qt配合要注意的地方)

x33g5p2x  于2021-12-14 转载在 Java  
字(1.6k)|赞(0)|评价(0)|浏览(388)

直接说明下我遇到的问题吧,客户端发送http协议,服务器是Qt写的,用QTcpSocket直接解析,如下HTTP

POST http://192.1.xxx.xxx:18888/XXXXX HTTP/1.1
Content-Type: application/json;charset=UTF-8
User-Agent: Java/1.8.0_181
Host: 192.1.101.189:18888
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-Length: 99999

{"xxxx":xxx,"xxx":"xxx","xxx":"xxx"}

这里使用的是Java的RestTemplate。

服务端是这样调用的

if(tcpSocket->waitForReadyRead(10 * 1000)){
        QString msg = QString::fromUtf8(tcpSocket->readAll());
        ......
        ......
        ......
    }

这样问题就来了,差不多每5次,就有1次,msg会收到:

POST http://192.1.xxx.xxx:18888/XXXXX HTTP/1.1
Content-Type: application/json;charset=UTF-8
User-Agent: Java/1.8.0_181
Host: 192.1.101.189:18888
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-Length: 99999

没有body部分,这就坑了。

后面通过抓包(这里要用wireshark,使用Fiddler等web抓包是看不到现象的)等一系列测试。Java中RestTemplate这个类,有时会把http包拆分成两个(postman和一些tcp调试工具不会)。先发header以及最后的\r\n。再发body。

注意:这里经过大量测试不管你的数据包是多大还是多小,比如就200字节的数据包,他也会差分成2个包发,10000字节的数据,他有时只会发1个包(这里只指应用层,不讨论网卡里面的MTU和路由器包分组)。所以这里应该算是一个RestTemplate的坑。Get方法正常。

并且这个body的大小(UTF-8编码)等于Content-Length,这个是http协议规定的。所以面对这样的情况,得修改下post方法的解析。增加这样的内容:

int contentLength = DataAnaylsisTool::getHttpHeaderValue(msg, "Content-Length").toInt();
QString body = DataAnaylsisTool::getHttpBody(msg);
while(body.size() != contentLength){

	tcpSocket->waitForReadyRead();
    qint64 available = tcpSocket->bytesAvailable();
    QString bodyMsg = tcpSocket->read(available);
    body += bodyMsg;
}

这个getHttpHeaderValue获取了Content-Length的大小。

这个getHttpBody获取了body的内容。

通过这种方式,不管他body里面分了多少个包,都可以获取到。

相关文章