《最新qt下的udp、tcp网络编程.doc》由会员分享,可在线阅读,更多相关《最新qt下的udp、tcp网络编程.doc(35页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、精品资料qt下的udp、tcp网络编程.QT网络编程TCP一TCP即Transmission Control Protocol,传输控制协议。与UDP不同,它是面向连接和数据流的可靠传输协议。也就是说,它能使一台计算机上的数据无差错的发往网络上的其他计算机,所以当要传输大量数据时,我们选用TCP协议。TCP协议的程序使用的是客户端/服务器模式,在Qt中提供了QTcpSocket类来编写客户端程序,使用QTcpServer类编写服务器端程序。我们在服务器端进行端口的监听,一旦发现客户端的连接请求,就会发出newConnection()信号,我们可以关联这个信号到我们自己的槽函数,进行数据的发送。
2、而在客户端,一旦有数据到来就会发出readyRead()信号,我们可以关联此信号,进行数据的接收。其实,在程序中最难理解的地方就是程序的发送和接收了,为了让大家更好的理解,我们在这一节只是讲述一个传输简单的字符串的例子,在下一节再进行扩展,实现任意文件的传输。一、服务器端。在服务器端的程序中,我们监听本地主机的一个端口,这里使用6666,然后我们关联newConnection()信号与自己写的sendMessage()槽函数。就是说一旦有客户端的连接请求,就会执行sendMessage()函数,在这个函数里我们发送一个简单的字符串。1.我们新建Qt4 Gui Application,工程名为“
3、tcpServer”,选中QtNetwork模块,Base class选择QWidget。(说明:如果一些Qt Creator版本没有添加模块一项,我们就需要在工程文件tcpServer.pro中添加一行代码:QT += network)2.我们在widget.ui的设计区添加一个Label,更改其objectName为statusLabel,用于显示一些状态信息。如下:3.在widget.h文件中做以下更改。添加头文件:#include 添加private对象:QTcpServer *tcpServer;添加私有槽函数:private slots:void sendMessage();4.在
4、widget.cpp文件中进行更改。在其构造函数中添加代码:tcpServer = new QTcpServer(this); if(!tcpServer-listen(QHostAddress:LocalHost,6666) /监听本地主机的6666端口,如果出错就输出错误信息,并关闭 qDebug() errorString(); close(); connect(tcpServer,SIGNAL(newConnection(),this,SLOT(sendMessage();/连接信号和相应槽函数我们在构造函数中使用tcpServer的listen()函数进行监听,然后关联了newCon
5、nection()和我们自己的sendMessage()函数。下面我们实现sendMessage()函数。void Widget:sendMessage()QByteArray block; /用于暂存我们要发送的数据 QDataStream out(&block,QIODevice:WriteOnly); /使用数据流写入数据 out.setVersion(QDataStream:Qt_4_6); /设置数据流的版本,客户端和服务器端使用的版本要相同 out(quint16) 0; outseek(0); outnextPendingConnection(); /我们获取已经建立的连接的子套
6、接字 connect(clientConnection,SIGNAL(disconnected(),clientConnection, SLOT(deleteLater(); clientConnection-write(block); clientConnection-disconnectFromHost(); ui-statusLabel-setText(“send message successful!”); /发送数据成功后,显示提示这个是数据发送函数,我们主要介绍两点:(1)为了保证在客户端能接收到完整的文件,我们都在数据流的最开始写入完整文件的大小信息,这样客户端就可以根据大小信息
7、来判断是否接受到了完整的文件。而在服务器端,我们在发送数据时就要首先发送实际文件的大小信息,但是,文件的大小一开始是无法预知的,所以我们先使用了out(quint16) 0;在block的开始添加了一个quint16大小的空间,也就是两字节的空间,它用于后面放置文件的大小信息。然后outseek(0);返回到block的开始,加入实际的文件大小信息,也就是后面的代码,它是实际文件的大小:outwrite(block);然后是clientConnection-disconnectFromHost();它表示当发送完成时就会断开连接,这时就会发出disconnected()信号,而最后调用dele
8、teLater()函数保证在关闭连接后删除该套接字clientConnection。5.这样服务器的程序就完成了,我们先运行一下程序。二、客户端。我们在客户端程序中向服务器发送连接请求,当连接成功时接收服务器发送的数据。1. .我们新建Qt4 Gui Application,工程名为“tcpClient”,选中QtNetwork模块,Base class选择QWidget。2,我们在widget.ui中添加几个标签Label和两个Line Edit以及一个按钮Push Button。其中“主机”后的Line Edit的objectName为hostLineEdit,“端口号”后的为portLi
9、neEdit。“收到的信息”标签的objectName为messageLabel messageLabel 。3.在widget.h文件中做更改。添加头文件:#include 添加private变量:QTcpSocket *tcpSocket;QString message; /存放从服务器接收到的字符串quint16 blockSize; /存放文件的大小信息添加私有槽函数:private slots: void newConnect(); /连接服务器 void readMessage(); /接收数据void displayError(QAbstractSocket:SocketErro
10、r); /显示错误4.在widget.cpp文件中做更改。(1)在构造函数中添加代码:tcpSocket = new QTcpSocket(this);connect(tcpSocket,SIGNAL(readyRead(),this,SLOT(readMessage();connect(tcpSocket,SIGNAL(error(QAbstractSocket:SocketError), this,SLOT(displayError(QAbstractSocket:SocketError);这里关联了tcpSocket的两个信号,当有数据到来时发出readyRead()信号,我们执行读取数
11、据的readMessage()函数。当出现错误时发出error()信号,我们执行displayError()槽函数。(2)实现newConnect()函数。void Widget:newConnect() blockSize = 0; /初始化其为0 tcpSocket-abort(); /取消已有的连接 tcpSocket-connectToHost(ui-hostLineEdit-text(), ui-portLineEdit-text().toInt(); /连接到主机,这里从界面获取主机地址和端口号这个函数实现了连接到服务器,下面会在“连接”按钮的单击事件槽函数中调用这个函数。(3)实
12、现readMessage()函数。void Widget:readMessage() QDataStream in(tcpSocket); in.setVersion(QDataStream:Qt_4_6); /设置数据流版本,这里要和服务器端相同 if(blockSize=0) /如果是刚开始接收数据 /判断接收的数据是否有两字节,也就是文件的大小信息 /如果有则保存到blockSize变量中,没有则返回,继续接收数据 if(tcpSocket-bytesAvailable() blockSize; if(tcpSocket-bytesAvailable() message; /将接收到的数
13、据存放到变量中 ui-messageLabel-setText(message); /显示接收到的数据这个函数实现了数据的接收,它与服务器端的发送函数相对应。首先我们要获取文件的大小信息,然后根据文件的大小来判断是否接收到了完整的文件。(4)实现displayError()函数。void Widget:displayError(QAbstractSocket:SocketError) qDebug() errorString(); /输出错误信息这里简单的实现了错误信息的输出。(5)我们在widget.ui中进入“连接”按钮的单击事件槽函数,然后更改如下。void Widget:on_push
14、Button_clicked() /连接按钮 newConnect(); /请求连接这里直接调用了newConnect()函数。5.我们运行程序,同时运行服务器程序,然后在“主机”后填入“localhost”,在“端口号”后填入“6666”,点击“连接”按钮,效果如下。可以看到我们正确地接收到了数据。因为服务器端和客户端是在同一台机子上运行的,所以我这里填写了“主机”为“localhost”,如果你在不同的机子上运行,需要在“主机”后填写其正确的IP地址。 到这里我们最简单的TCP应用程序就完成了,在下一节我们将会对它进行扩展,实现任意文件的传输。QT网络编程TCP二在上一节里我们使用TCP服
15、务器发送一个字符串,然后在TCP客户端进行接收。在这一节我们重新写一个客户端程序和一个服务器程序,这次我们让客户端进行文件的发送,服务器进行文件的接收。有了上一节的基础,这一节的内容就很好理解了,注意一下几个信号和槽的关联即可。当然,我们这次要更深入了解一下数据的发送和接收的处理方法。一、客户端这次我们先讲解客户端,在客户端里我们与服务器进行连接,一旦连接成功,就会发出connected()信号,这时我们就进行文件的发送。在上一节我们已经看到,发送数据时我们先发送了数据的大小信息。这一次,我们要先发送文件的总大小,然后文件名长度,然后是文件名,这三部分我们合称为文件头结构,最后再发送文件数据。
16、所以在发送函数里我们就要进行相应的处理,当然,在服务器的接收函数里我们也要进行相应的处理。对于文件大小,这次我们使用了qint64,它是64位的,可以表示一个很大的文件了。1.同前一节,我们新建工程,将工程命名为“tcpSender”。注意添加network模块。2.我们在widget.ui文件中将界面设计如下。这里“主机”后的Line Edit的objectName为hostLineEdit;“端口”后的Line Edit的objectName为portLineEdit;下面的Progress Bar的objectName为clientProgressBar,其value属性设为0;“状态”
17、Label的objetName为clientStatusLabel;“打开”按钮的objectName为openButton;“发送”按钮的objectName为sendButton;3.在widget.h 文件中进行更改。(1)添加头文件#include (2)添加private变量:QTcpSocket *tcpClient; QFile *localFile; /要发送的文件 qint64 totalBytes; /数据总大小 qint64 bytesWritten; /已经发送数据大小 qint64 bytesToWrite; /剩余数据大小 qint64 loadSize; /每次发
18、送数据的大小 QString fileName; /保存文件路径QByteArray outBlock; /数据缓冲区,即存放每次要发送的数据(3)添加私有槽函数:private slots: void send(); /连接服务器 void startTransfer(); /发送文件大小等信息 void updateClientProgress(qint64); /发送数据,更新进度条 void displayError(QAbstractSocket:SocketError); /显示错误void openFile(); /打开文件4.在widget.cpp文件中进行更改。添加头文件:#
19、include (1)在构造函数中添加代码:loadSize = 4*1024; totalBytes = 0; bytesWritten = 0; bytesToWrite = 0; tcpClient = new QTcpSocket(this); connect(tcpClient,SIGNAL(connected(),this,SLOT(startTransfer(); /当连接服务器成功时,发出connected()信号,我们开始传送文件 connect(tcpClient,SIGNAL(bytesWritten(qint64),this,SLOT(updateClientProgr
20、ess(qint64); /当有数据发送成功时,我们更新进度条 connect(tcpClient,SIGNAL(error(QAbstractSocket:SocketError),this, SLOT(displayError(QAbstractSocket:SocketError); ui-sendButton-setEnabled(false); /开始使”发送“按钮不可用我们主要是进行了变量的初始化和几个信号和槽函数的关联。(2)实现打开文件函数。void Widget:openFile() /打开文件 fileName = QFileDialog:getOpenFileName(t
21、his); if(!fileName.isEmpty() ui-sendButton-setEnabled(true); ui-clientStatusLabel-setText(tr(“打开文件 %1 成功!”) .arg(fileName); 该函数将在下面的“打开”按钮单击事件槽函数中调用。(3)实现连接函数。void Widget:send() /连接到服务器,执行发送 ui-sendButton-setEnabled(false); bytesWritten = 0; /初始化已发送字节为0 ui-clientStatusLabel-setText(tr(“连接中”); tcpCli
22、ent-connectToHost(ui-hostLineEdit-text(), ui-portLineEdit-text().toInt();/连接该函数将在“发送”按钮的单击事件槽函数中调用。(4)实现文件头结构的发送。void Widget:startTransfer() /实现文件大小等信息的发送 localFile = new QFile(fileName); if(!localFile-open(QFile:ReadOnly) qDebug() size(); /文件总大小 QDataStream sendOut(&outBlock,QIODevice:WriteOnly); s
23、endOut.setVersion(QDataStream:Qt_4_6); QString currentFileName = fileName.right(fileName.size() - fileName.lastIndexOf(/)-1); sendOut qint64(0) qint64(0) seek(0); sendOuttotalByteswrite(outBlock); /发送完头数据后剩余数据的大小 ui-clientStatusLabel-setText(tr(已连接); outBlock.resize(0);(5)下面是更新进度条,也就是发送文件数据。void Wid
24、get:updateClientProgress(qint64 numBytes) /更新进度条,实现文件的传送 bytesWritten += (int)numBytes; /已经发送数据的大小 if(bytesToWrite 0) /如果已经发送了数据 outBlock = localFile-read(qMin(bytesToWrite,loadSize); /每次发送loadSize大小的数据,这里设置为4KB,如果剩余的数据不足4KB, /就发送剩余数据的大小 bytesToWrite -= (int)tcpClient-write(outBlock); /发送完一次数据后还剩余数据
25、的大小 outBlock.resize(0); /清空发送缓冲区 else localFile-close(); /如果没有发送任何数据,则关闭文件 ui-clientProgressBar-setMaximum(totalBytes); ui-clientProgressBar-setValue(bytesWritten); /更新进度条 if(bytesWritten = totalBytes) /发送完毕 ui-clientStatusLabel-setText(tr(“传送文件 %1 成功”).arg(fileName); localFile-close(); tcpClient-cl
26、ose(); (6)实现错误处理函数。void Widget:displayError(QAbstractSocket:SocketError) /显示错误 qDebug() errorString(); tcpClient-close(); ui-clientProgressBar-reset(); ui-clientStatusLabel-setText(tr(“客户端就绪”); ui-sendButton-setEnabled(true);(7)我们从widget.ui中分别进行“打开”按钮和“发送”按钮的单击事件槽函数,然后更改如下。void Widget:on_openButton_
27、clicked() /打开按钮 openFile();void Widget:on_sendButton_clicked() /发送按钮 send();5.我们为了使程序中的中文不显示乱码,在main.cpp文件中更改。添加头文件:#include 在main函数中添加代码:QTextCodec:setCodecForTr(QTextCodec:codecForLocale();6.运行程序,效果如下。7.程序整体思路分析。我们设计好界面,然后按下“打开”按钮,选择我们要发送的文件,这时调用了openFile()函数。然后我们点击“发送”按钮,调用send()函数,与服务器进行连接。当连接成功
28、时就会发出connected()信号,这时就会执行startTransfer()函数,进行文件头结构的发送,当发送成功时就会发出bytesWritten(qint64)信号,这时我们执行updateClientProgress(qint64 numBytes)进行文件数据的传输和进度条的更新。这里使用了一个loadSize变量,我们在构造函数中将其初始化为4*1024即4字节,它的作用是,我们将整个大的文件分成很多小的部分进行发送,每部分为4字节。而当连接出现问题时就会发出error(QAbstractSocket:SocketError)信号,这时就会执行displayError()函数。对
29、于程序中其他细节我们就不再分析,希望大家能自己编程研究一下。二、服务器端。我们在服务器端进行数据的接收。服务器端程序是很简单的,我们开始进行监听,一旦发现有连接请求就发出newConnection()信号,然后我们便接受连接,开始接收数据。1.新建工程,名字为“tcpReceiver”。2.我们更改widget.ui文件,设计界面如下。其中“服务器端”Label的objectName为serverStatusLabel;进度条Progress Bar的objectName为serverProgressBar,设置其value属性为0;“开始监听”按钮的objectName为startButto
30、n。效果如下。3.更改widget.h文件的内容。(1)添加头文件:#include (2)添加私有变量: QTcpServer tcpServer; QTcpSocket *tcpServerConnection; qint64 totalBytes; /存放总大小信息 qint64 bytesReceived; /已收到数据的大小 qint64 fileNameSize; /文件名的大小信息 QString fileName; /存放文件名 QFile *localFile; /本地文件QByteArray inBlock; /数据缓冲区(3)添加私有槽函数:private slots:
31、void on_startButton_clicked(); void start(); /开始监听 void acceptConnection(); /建立连接 void updateServerProgress(); /更新进度条,接收数据void displayError(QAbstractSocket:SocketError socketError);/显示错误4.更改widget.cpp文件。(1)在构造函数中添加代码:totalBytes = 0; bytesReceived = 0; fileNameSize = 0; connect(&tcpServer,SIGNAL(newC
32、onnection(),this,SLOT(acceptConnection();/当发现新连接时发出newConnection()信号(2)实现start()函数。void Widget:start() /开始监听 ui-startButton-setEnabled(false); bytesReceived =0; if(!tcpServer.listen(QHostAddress:LocalHost,6666) qDebug() serverStatusLabel-setText(tr(“监听”);(3)实现接受连接函数。void Widget:acceptConnection() /接
33、受连接 tcpServerConnection = tcpServer.nextPendingConnection();connect(tcpServerConnection,SIGNAL(readyRead(),this,SLOT(updateServerProgress(); connect(tcpServerConnection,SIGNAL(error(QAbstractSocket:SocketError),this, SLOT(displayError(QAbstractSocket:SocketError); ui-serverStatusLabel-setText(tr(“接受
34、连接”); tcpServer.close();(4)实现更新进度条函数。void Widget:updateServerProgress() /更新进度条,接收数据 QDataStream in(tcpServerConnection); in.setVersion(QDataStream:Qt_4_6); if(bytesReceived bytesAvailable() = sizeof(qint64)*2) & (fileNameSize = 0) /接收数据总大小信息和文件名大小信息 in totalBytes fileNameSize; bytesReceived += sizeo
35、f(qint64) * 2; if(tcpServerConnection-bytesAvailable() = fileNameSize) & (fileNameSize != 0) /接收文件名,并建立文件 in fileName; ui-serverStatusLabel-setText(tr(“接收文件 %1 ”) .arg(fileName); bytesReceived += fileNameSize; localFile = new QFile(fileName); if(!localFile-open(QFile:WriteOnly) qDebug() “open file e
36、rror!”; return; else return; if(bytesReceived bytesAvailable(); inBlock = tcpServerConnection-readAll(); localFile-write(inBlock); inBlock.resize(0); ui-serverProgressBar-setMaximum(totalBytes); ui-serverProgressBar-setValue(bytesReceived); /更新进度条 if(bytesReceived = totalBytes) /接收数据完成时 tcpServerCon
37、nection-close(); localFile-close(); ui-startButton-setEnabled(true);ui-serverStatusLabel-setText(tr(“接收文件 %1 成功!”).arg(fileName); (5)错误处理函数。void Widget:displayError(QAbstractSocket:SocketError) /错误处理 qDebug() errorString(); tcpServerConnection-close(); ui-serverProgressBar-reset(); ui-serverStatusLa
38、bel-setText(tr(“服务端就绪”); ui-startButton-setEnabled(true);(6)我们在widget.ui中进入“开始监听”按钮的单击事件槽函数,更改如下。void Widget:on_startButton_clicked() /开始监听按钮 start();5.我们为了使程序中的中文不显示乱码,在main.cpp文件中更改。添加头文件:#include 在main函数中添加代码:QTextCodec:setCodecForTr(QTextCodec:codecForLocale();6.运行程序,并同时运行tcpSender程序,效果如下。我们先在服务器端按下“开始监听”按钮,然后在客户端输入主机地址和端口号,然后打开要发送的文件,点击“发送”按钮进行发送。在这两节里我们介绍了TCP的应用,可以看到服务器端和客户度端都可以当做发送端或者接收端,而且数据的发送与接收只要使用相对应的协议即可,它是可以根据用户的需要来进行