2012-04-30 153 views
1

我正在尝试使用Qt的长度先于TCP消息。我有以下方法:QT套接字读取丢失字节

QByteArray con::read() 
{ 
    QByteArray s; 
    s = _pSocket->read(4); 
    if (s.length() == 4) { 
     int size = char_to_int32(s); 
     s = _pSocket->read(size); 
    } 
    return s; 
} 

嗯,它不起作用。看起来我读完第4个字节后会丢失所有数据:第一次读取正常,但read(size)不返回任何内容。有没有办法解决这个问题?

的char_to_int32是:

int char_to_int32(QByteArray s) 
{ 
    int size = 0; 
    size |= (s.at(0) << 24); 
    size |= (s.at(1) << 16); 
    size |= (s.at(2) << 8); 
    size |= (s.at(3)); 
    return size; 
} 

编辑:

发送功能(纯C):

int send(int connfd, const unsigned char* message, unsigned int size) { 
    int c; 
    unsigned char* bytes = (unsigned char*) malloc(4 + size); 
    int32_to_char(size, bytes); // converts message size to 4 bytes 
    memcpy(bytes + 4, message, size); 
    c = write(connfd, bytes, 4 + size); 
    free(bytes); 
    if (c <= 0) 
     return -1; 
    else 
     return 0; 
} 

顺便说一句,当我打电话_pSocket-> readAll( ),读取整个数据包,包括4字节大小和消息本身。

编辑:

void int32_to_char(uint32_t in, char* bytes) { 
    bytes[0] = (in >> 24) & 0xFF; 
    bytes[1] = (in >> 16) & 0xFF; 
    bytes[2] = (in >> 8) & 0xFF; 
    bytes[3] = in & 0xFF; 
    return; 
} 
+0

你能否提供'char_to_int32'函数定义? – mfontanini

+0

大小是多少?你确定它是32位有符号的int吗? –

+0

尝试在read()中使用它之前打印“大小”值。我敢打赌,问题在那里 – nax83

回答

3

由于您使用的是QByteArray QIODevice::read(qint64 maxSize)功能,您可能无法检测的错误正确:

这个函数没有报告错误的方式;返回一个空的QByteArray()可能意味着当前没有数据可用于读取,或者发生错误。

有些事情尝试:

  • 使用qint64 QIODevice::read(char* data, qint64 maxSize)该报告错误:如果发生错误

    ...这个函数返回-1。

  • 拨打电话QIODevice::errorStringQAbstractSocket::error找出发生了什么问题。

    • 要获得积分,请收听QAbstractSocket::error错误信号。
  • 如果这是您要创建一个新的协议,请尝试使用QDataStream序列化,这会自动处理长度作为前缀和平台无关。如果您将混合使用不同的平台,则char_to_int32会中断,并且可能会在不同的操作系统或编译器之间中断,因为int不能保证为32位(它被定义为at least 16 bits)。

编辑

这里是表示hton/NTOH使用的一些示例代码。注意uint32_t而不是int被使用,因为它保证是32位。我也使用memcpy而不是编码/解码中的指针转换来防止锯齿和对齐问题(为了简洁起见,我刚刚在测试函数中进行了投射)。

#include <stdio.h> 
#include <string.h> 
#include <arpa/inet.h> 

void encode(uint32_t in, char* out) 
{ 
    /* Host to Network long (32 bits) */ 
    const uint32_t t = htonl(in); 
    memcpy(out, &t, sizeof(t)); 
} 

uint32_t decode(char* in) 
{ 
    uint32_t t; 
    memcpy(&t, in, sizeof(t)); 
    /* Network to Host long (32 bits) */ 
    return ntohl(t); 
} 

void test(uint32_t v) 
{ 
    char buffer[4]; 
    printf("Host Input: %08x\n", v); 
    encode(v, buffer); 
    printf("Network:  %08x\n", *((uint32_t*)buffer)); 
    printf("Host Output: %08x\n\n", decode(buffer)); 
} 

int main(int argc, char** argv) 
{ 
    test(0); 
    test(1); 
    test(0x55); 
    test(0x55000000); 
    return 0; 
} 
+0

谢谢你的回答。不幸的是,我不能在服务器端使用QDataStream。我应该如何使用htonl? int32_to_char(htonl(in),char * bytes)或其他方式? – user1256821

+0

我已经添加了一些示例代码。 –

+0

谢谢!这真是一个很好的例子。主要问题也解决了:我试图使用read(char * data,qint64 maxSize),即使没有网络字节顺序,它也能工作。仍然不知道QByteArray QIODevice :: read(qint64 maxSize)有什么问题。 – user1256821