QTcpSocket 发送数据心得

来源:互联网 发布:mac迅雷下载 编辑:程序博客网 时间:2024/05/22 11:14

遇到不会用的函数前,最好还是看看手册QAQ,今天居然吃了这个大亏!!!
先交代一下背景:
在做TCP客户端的发送数据功能,要和服务器程序进行TCP/IP通信,且根据通信协议要发送数组或者结构体,并且数组的每一个位都是有效数据位。因此不能像大多数人一样加blockSize篡改协议内容。。

网上大多数的例子都是

    //用于暂存要发送的数据      QByteArray block;      //使用数据流写入数据      QDataStream out(&block,QIODevice::ReadWrite);      //设置数据流的版本,客户端和服务器端使用的版本要相同      out.setVersion(QDataStream::Qt_4_6);      //设置发送长度初始值为0      out << (quint16) 0;      //设置发送内容      out<<hash;      //回到字节流起始位置      out.device()->seek(0);      //重置字节流长度      out << (quint16) (block.size()-sizeof(quint16));      //往套接字缓存中写入数据,并发送      tcpSocket->write(block);  

数据流在这次并不能排上用场,因为处开字节流长度 被包含在发送内容不说,字节流还会修改char数组里的值!!!(调试了很久都没办法)

但是如果往字节流里添加int类型就不会被修改,因为是字节流,所以可以忽视数据类型传输,这反而也是一个小优点。

首先先要知道,一个char有八个字节,unsign int有32个字节(去掉第一位的正负判断)

such as:
char数组 char[6]=”\0x00\0x00\0x00\0x01\0x01\0x00”
从qDebug block 得出内容变成了 “\0x00\0x00\0x00\0x01\0x00” (已经是去掉了blockSize)
内容明显变动了,0x00是用十六进制来表示一个8位字节。

如果是unsign int = “\0x00\0x00\0x01\0x01”输入到字节流打印block内容还是一样,但是可惜的是一个int 有4个字节,并不能发送自己想要的6个字节的效果,所以就放弃掉这个方法了。

然后我还尝试了调用sys/socket.h sys/tyopes.h试图使用C底层的socket函数来实现TCP通信的时候(感觉放着汽车不用用单车。。) 客户端连接函数connect()已经被QT用掉了,用来实现信号槽。。。。。(无语啊。。)

最后从网上看到了一个大神的博客QTcpSocket 发送和接收数据的几种方法

主要就是放弃字节流直接使用socket->Write()函数,但是一开始我用的时候频频报错,我以为这种方法并不可取,最后把char数组转成字符串也没用。。

1、char型数组或字符串指针转换成QString
char str_data[512];
QString qs_data;
…………
qs_data = QString::fromLocal8Bit(str_data,512); //当然也可以用强制类型转换QString(str_data)
2、QString类型转换为 char指针类型
const char * str_data; //这里一定要加上const,否则会报错!
QString qs_data;
………..
str_data = qs_data.ascii();

然后又从一个试图发结构体类型的问题的帖子里看到了这句话,

 this->client->write((char *)&stu,sizeof(stu));

因为我的char是数组,所以我这样写(new的名字不一样,原理是一样的)

SMUTcpSocket->write(mc_sendBuf,sizeof(mc_sendBuf));SMUTcpSocket->flush();

成功了!!!!!!!!!!!!

诶,主要自我检讨问题是Write函数的使用上面没有清晰去了解,瞎折腾不少时间。所以下次遇到问题先查查手册,看看Write()函数有几个重载。

感谢感谢前人的努力,让我们少走了弯路。

1、QTcpSocket 继承于QAbstractSocket继承于QIODevice

2、QTcpSocket 提供的几种接收和发送数据方法

write ( const char *, qint64 ) : qint64write ( const char * ) : qint64write ( const QByteArray & ) : qint64writeData ( const char *, qint64 ) : qint64read ( char * data, qint64 maxSize ): qint64 read ( qint64 maxSize ):QByteArrayreadAll ():QByteArrayreadLine ( char * data, qint64 maxSize ):qint64readLine ( qint64 maxSize = 0 ):QByteArray

3、例子1 write ( const QByteArray & ) : qint64

//用于暂存要发送的数据  QByteArray block;  //使用数据流写入数据  QDataStream out(&block,QIODevice::ReadWrite);  //设置数据流的版本,客户端和服务器端使用的版本要相同  out.setVersion(QDataStream::Qt_4_6);  //设置发送长度初始值为0  out << (quint16) 0;  //设置发送内容  out<<hash;  //回到字节流起始位置  out.device()->seek(0);  //重置字节流长度  out << (quint16) (block.size()-sizeof(quint16));  //往套接字缓存中写入数据,并发送  tcpSocket->write(block);  

3、例子2 write ( const char *, qint64 ) : qint64

QString *a=new QString;  tcpSocket->write(a,a->length());  

4、例子3 数据流直接使用QIODevice

QDataStream in(tcpSocket);  in<< quint16(0xFFFF); //此时QIODevice加载了此数据,而且直接发送出去  quint16 length = 0;  QDataStream out(tcpSocket);//如果此时tcpSocket直接有数据发送过来  out >> length;//length获得第一个整型值,并在tcpSocket中清空该数据

PS:最新更新

通过我司某位大神,问题已经找出来了。

之前的问题是为什么把char数组放入字节流里会修改存入字节的内容。

因为指针不是从零开始的(不排除之前有缓存占用了),所以在放入char数组前先

   out.device()->seek(0);

这样子内容就正确了。