QT TCPSocket和QTCPServer使用

概述:QTcpSocket和QTcpServer可以实现TCP客户端和服务器端通信,本文介绍基于块的通信方式

基于块的传输协议把数据作为二进制块进行传输。每一个块都由一个大小字段及其包含的数据域组成

程序界面

 一个数服务端socket一个是客户端socket,客户端socket可以从服务器端socket下载文件

运行过程

 客户端精度条显示文件下载进度。

test.rar表示服务器要发送的文件,testreceived.rar表示客户端收到的文件

 因为测试服务器和客户端在同一目录下,所以该程序把收到的test.rar命名为testreceived.rar,以做区分

核心代码

connect(&tcpSocketClient,&QTcpSocket::connected,this,&FileTransferSocket::slotConnected);
connect(&tcpSocketClient,&QTcpSocket::disconnected,this,&FileTransferSocket::slotDisconnected);
connect(&tcpSocketClient,&QTcpSocket::readyRead,this,&FileTransferSocket::slotReadyRead);
connect(&tcpSocketClient,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(slotError(QAbstractSocket::SocketError)));

slotReadyRead当对方socket有数据过来将会调用此槽函数

1、tcpSocketClient.connectToHost("127.0.0.1",8888);

连接到服务器端socket

2、发送数据到连接的socket

QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_1);
out<<quint16(0)<<QString("downrequest");
out.device()->seek(0);
out << quint16(block.size() - sizeof(quint16));
tcpSocketClient.write(block);

每次发送数据都是以块为单位的,上面代码发送一个块的数据

但是需要注意的地方是,数据在网络传输中并不是以块为单位,也就是发送一整块数据,接收的socket可能不是一次正好接收一整个块

可能收到一个完整的块或者一个块的一部分、一个块和另一个块的一部分、若干个块或者亦可能是所有的块,在接收端socket需要判断。

先看看块的结构形式

一个块包含两部分,一部分表示数据区域的大小,一部分表示数据区域

out<<quint16(0)<<QString("downrequest");

这段代码的quint16(0)用来存放数据区域的大小,QString("downrequest")表示数据区域

out.device()->seek(0);
out << quint16(block.size() - sizeof(quint16));

这两行代码,分别是移到首位置,即数据数据区域大小

然后给数据区域填充数据的实际大小值.

3、我们来看看接收端socket如何接收数据

在这里定义一个nextBlockSize变量

用来存放每个块的大小。

bytesAvailable()表示网络里面传过来的可用字节数,如果可用字节数已经大于或者等于sizeof(quint16)

还记得quint16表示什么吗?这个区域存放的就是块的数据区域大小。

如果可用字节数已经大于或者等于sizeof(quint16),这样我们就可以取出这个块的数据区域大小

in >> nextBlockSize;

然后再判断bytesAvailable()是否大于等于nextBlockSize如果不是说明这个块的数据还未完全传过来,等待网络数据传输(千万不要取已接收的数据,因为是不完整的)

如果大于等于nextBlockSize,说明这一块的数据区域已经完全传过来了。

//数据块完整可以接收
QString clientrequest;
in >> clientrequest;

然后把数据区域的数据放到clientrequest里面。

到此通过块的形式发送数据就完成了

4、下面开始文件的传输

 先获取本地文件,打文件大小文件名称等信息传到客户端socket,当然上面代码是写死的文件名,你可以通过file直接获取文件名。

上面的代码还未正式发送文件,只是把文件的一些信息发送给客户端socket。

5、

connect(this, SIGNAL(bytesWritten(qint64)), this, SLOT(slotBytesWritten(qint64)));

bytesWritten(qint64))这个信号每次数据写入设备后会激发

在此槽函数里面读取文件并发送文件到客户端

文件分多次发送,每当有数据写入的设备改槽函数都执行,直到文件发送完毕

6.我们再看看文件接收端

 这里就不做详细讲解了,主要就是从sokcet读取说有数据,然后文件写入

猜你喜欢

转载自www.cnblogs.com/tianmochou/p/12851663.html