




已閱讀5頁(yè),還剩31頁(yè)未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
QT網(wǎng)絡(luò)編程TCP一TCP即Transmission Control Protocol,傳輸控制協(xié)議。與UDP不同,它是面向連接和數(shù)據(jù)流的可靠傳輸協(xié)議。也就是說(shuō),它能使一臺(tái)計(jì)算機(jī)上的數(shù)據(jù)無(wú)差錯(cuò)的發(fā)往網(wǎng)絡(luò)上的其他計(jì)算機(jī),所以當(dāng)要傳輸大量數(shù)據(jù)時(shí),我們選用TCP協(xié)議。TCP協(xié)議的程序使用的是客戶端/服務(wù)器模式,在Qt中提供了QTcpSocket類來(lái)編寫客戶端程序,使用QTcpServer類編寫服務(wù)器端程序。我們?cè)诜?wù)器端進(jìn)行端口的監(jiān)聽,一旦發(fā)現(xiàn)客戶端的連接請(qǐng)求,就會(huì)發(fā)出newConnection()信號(hào),我們可以關(guān)聯(lián)這個(gè)信號(hào)到我們自己的槽函數(shù),進(jìn)行數(shù)據(jù)的發(fā)送。而在客戶端,一旦有數(shù)據(jù)到來(lái)就會(huì)發(fā)出readyRead()信號(hào),我們可以關(guān)聯(lián)此信號(hào),進(jìn)行數(shù)據(jù)的接收。其實(shí),在程序中最難理解的地方就是程序的發(fā)送和接收了,為了讓大家更好的理解,我們?cè)谶@一節(jié)只是講述一個(gè)傳輸簡(jiǎn)單的字符串的例子,在下一節(jié)再進(jìn)行擴(kuò)展,實(shí)現(xiàn)任意文件的傳輸。一、服務(wù)器端。在服務(wù)器端的程序中,我們監(jiān)聽本地主機(jī)的一個(gè)端口,這里使用6666,然后我們關(guān)聯(lián)newConnection()信號(hào)與自己寫的sendMessage()槽函數(shù)。就是說(shuō)一旦有客戶端的連接請(qǐng)求,就會(huì)執(zhí)行sendMessage()函數(shù),在這個(gè)函數(shù)里我們發(fā)送一個(gè)簡(jiǎn)單的字符串。1.我們新建Qt4 Gui Application,工程名為“tcpServer”,選中QtNetwork模塊,Base class選擇QWidget。(說(shuō)明:如果一些Qt Creator版本沒有添加模塊一項(xiàng),我們就需要在工程文件tcpS中添加一行代碼:QT += network)2.我們?cè)趙idget.ui的設(shè)計(jì)區(qū)添加一個(gè)Label,更改其objectName為statusLabel,用于顯示一些狀態(tài)信息。如下:3.在widget.h文件中做以下更改。添加頭文件:#include 添加private對(duì)象:QTcpServer *tcpServer;添加私有槽函數(shù):private slots:void sendMessage();4.在widget.cpp文件中進(jìn)行更改。在其構(gòu)造函數(shù)中添加代碼:tcpServer = new QTcpServer(this); if(!tcpServer-listen(QHostAddress:LocalHost,6666) /監(jiān)聽本地主機(jī)的6666端口,如果出錯(cuò)就輸出錯(cuò)誤信息,并關(guān)閉 qDebug() errorString(); close(); connect(tcpServer,SIGNAL(newConnection(),this,SLOT(sendMessage();/連接信號(hào)和相應(yīng)槽函數(shù)我們?cè)跇?gòu)造函數(shù)中使用tcpServer的listen()函數(shù)進(jìn)行監(jiān)聽,然后關(guān)聯(lián)了newConnection()和我們自己的sendMessage()函數(shù)。下面我們實(shí)現(xiàn)sendMessage()函數(shù)。void Widget:sendMessage() QByteArray block; /用于暫存我們要發(fā)送的數(shù)據(jù) QDataStream out(&block,QIODevice:WriteOnly); /使用數(shù)據(jù)流寫入數(shù)據(jù) out.setVersion(QDataStream:Qt_4_6); /設(shè)置數(shù)據(jù)流的版本,客戶端和服務(wù)器端使用的版本要相同 out(quint16) 0; outseek(0); outnextPendingConnection(); /我們獲取已經(jīng)建立的連接的子套接字 connect(clientConnection,SIGNAL(disconnected(),clientConnection, SLOT(deleteLater(); clientConnection-write(block); clientConnection-disconnectFromHost(); ui-statusLabel-setText(“send message successful!”); /發(fā)送數(shù)據(jù)成功后,顯示提示這個(gè)是數(shù)據(jù)發(fā)送函數(shù),我們主要介紹兩點(diǎn):(1)為了保證在客戶端能接收到完整的文件,我們都在數(shù)據(jù)流的最開始寫入完整文件的大小信息,這樣客戶端就可以根據(jù)大小信息來(lái)判斷是否接受到了完整的文件。而在服務(wù)器端,我們?cè)诎l(fā)送數(shù)據(jù)時(shí)就要首先發(fā)送實(shí)際文件的大小信息,但是,文件的大小一開始是無(wú)法預(yù)知的,所以我們先使用了out(quint16) 0;在block的開始添加了一個(gè)quint16大小的空間,也就是兩字節(jié)的空間,它用于后面放置文件的大小信息。然后outseek(0);返回到block的開始,加入實(shí)際的文件大小信息,也就是后面的代碼,它是實(shí)際文件的大小:outwrite(block);然后是clientConnection-disconnectFromHost();它表示當(dāng)發(fā)送完成時(shí)就會(huì)斷開連接,這時(shí)就會(huì)發(fā)出disconnected()信號(hào),而最后調(diào)用deleteLater()函數(shù)保證在關(guān)閉連接后刪除該套接字clientConnection。5.這樣服務(wù)器的程序就完成了,我們先運(yùn)行一下程序。二、客戶端。我們?cè)诳蛻舳顺绦蛑邢蚍?wù)器發(fā)送連接請(qǐng)求,當(dāng)連接成功時(shí)接收服務(wù)器發(fā)送的數(shù)據(jù)。1. .我們新建Qt4 Gui Application,工程名為“tcpClient”,選中QtNetwork模塊,Base class選擇QWidget。2,我們?cè)趙idget.ui中添加幾個(gè)標(biāo)簽Label和兩個(gè)Line Edit以及一個(gè)按鈕Push Button。其中“主機(jī)”后的Line Edit的objectName為hostLineEdit,“端口號(hào)”后的為portLineEdit?!笆盏降男畔ⅰ睒?biāo)簽的objectName為messageLabel 。3.在widget.h文件中做更改。添加頭文件:#include 添加private變量:QTcpSocket *tcpSocket;QString message; /存放從服務(wù)器接收到的字符串quint16 blockSize; /存放文件的大小信息添加私有槽函數(shù):private slots: void newConnect(); /連接服務(wù)器 void readMessage(); /接收數(shù)據(jù)void displayError(QAbstractSocket:SocketError); /顯示錯(cuò)誤4.在widget.cpp文件中做更改。(1)在構(gòu)造函數(shù)中添加代碼:tcpSocket = new QTcpSocket(this);connect(tcpSocket,SIGNAL(readyRead(),this,SLOT(readMessage();connect(tcpSocket,SIGNAL(error(QAbstractSocket:SocketError), this,SLOT(displayError(QAbstractSocket:SocketError);這里關(guān)聯(lián)了tcpSocket的兩個(gè)信號(hào),當(dāng)有數(shù)據(jù)到來(lái)時(shí)發(fā)出readyRead()信號(hào),我們執(zhí)行讀取數(shù)據(jù)的readMessage()函數(shù)。當(dāng)出現(xiàn)錯(cuò)誤時(shí)發(fā)出error()信號(hào),我們執(zhí)行displayError()槽函數(shù)。(2)實(shí)現(xiàn)newConnect()函數(shù)。void Widget:newConnect() blockSize = 0; /初始化其為0 tcpSocket-abort(); /取消已有的連接 tcpSocket-connectToHost(ui-hostLineEdit-text(), ui-portLineEdit-text().toInt(); /連接到主機(jī),這里從界面獲取主機(jī)地址和端口號(hào)這個(gè)函數(shù)實(shí)現(xiàn)了連接到服務(wù)器,下面會(huì)在“連接”按鈕的單擊事件槽函數(shù)中調(diào)用這個(gè)函數(shù)。(3)實(shí)現(xiàn)readMessage()函數(shù)。void Widget:readMessage() QDataStream in(tcpSocket); in.setVersion(QDataStream:Qt_4_6); /設(shè)置數(shù)據(jù)流版本,這里要和服務(wù)器端相同 if(blockSize=0) /如果是剛開始接收數(shù)據(jù) /判斷接收的數(shù)據(jù)是否有兩字節(jié),也就是文件的大小信息 /如果有則保存到blockSize變量中,沒有則返回,繼續(xù)接收數(shù)據(jù) if(tcpSocket-bytesAvailable() blockSize; if(tcpSocket-bytesAvailable() message; /將接收到的數(shù)據(jù)存放到變量中 ui-messageLabel-setText(message); /顯示接收到的數(shù)據(jù)這個(gè)函數(shù)實(shí)現(xiàn)了數(shù)據(jù)的接收,它與服務(wù)器端的發(fā)送函數(shù)相對(duì)應(yīng)。首先我們要獲取文件的大小信息,然后根據(jù)文件的大小來(lái)判斷是否接收到了完整的文件。(4)實(shí)現(xiàn)displayError()函數(shù)。void Widget:displayError(QAbstractSocket:SocketError) qDebug() errorString(); /輸出錯(cuò)誤信息這里簡(jiǎn)單的實(shí)現(xiàn)了錯(cuò)誤信息的輸出。(5)我們?cè)趙idget.ui中進(jìn)入“連接”按鈕的單擊事件槽函數(shù),然后更改如下。void Widget:on_pushButton_clicked() /連接按鈕 newConnect(); /請(qǐng)求連接這里直接調(diào)用了newConnect()函數(shù)。5.我們運(yùn)行程序,同時(shí)運(yùn)行服務(wù)器程序,然后在“主機(jī)”后填入“l(fā)ocalhost”,在“端口號(hào)”后填入“6666”,點(diǎn)擊“連接”按鈕,效果如下??梢钥吹轿覀冋_地接收到了數(shù)據(jù)。因?yàn)榉?wù)器端和客戶端是在同一臺(tái)機(jī)子上運(yùn)行的,所以我這里填寫了“主機(jī)”為“l(fā)ocalhost”,如果你在不同的機(jī)子上運(yùn)行,需要在“主機(jī)”后填寫其正確的IP地址。 到這里我們最簡(jiǎn)單的TCP應(yīng)用程序就完成了,在下一節(jié)我們將會(huì)對(duì)它進(jìn)行擴(kuò)展,實(shí)現(xiàn)任意文件的傳輸。QT網(wǎng)絡(luò)編程TCP二在上一節(jié)里我們使用TCP服務(wù)器發(fā)送一個(gè)字符串,然后在TCP客戶端進(jìn)行接收。在這一節(jié)我們重新寫一個(gè)客戶端程序和一個(gè)服務(wù)器程序,這次我們讓客戶端進(jìn)行文件的發(fā)送,服務(wù)器進(jìn)行文件的接收。有了上一節(jié)的基礎(chǔ),這一節(jié)的內(nèi)容就很好理解了,注意一下幾個(gè)信號(hào)和槽的關(guān)聯(lián)即可。當(dāng)然,我們這次要更深入了解一下數(shù)據(jù)的發(fā)送和接收的處理方法。一、客戶端這次我們先講解客戶端,在客戶端里我們與服務(wù)器進(jìn)行連接,一旦連接成功,就會(huì)發(fā)出connected()信號(hào),這時(shí)我們就進(jìn)行文件的發(fā)送。在上一節(jié)我們已經(jīng)看到,發(fā)送數(shù)據(jù)時(shí)我們先發(fā)送了數(shù)據(jù)的大小信息。這一次,我們要先發(fā)送文件的總大小,然后文件名長(zhǎng)度,然后是文件名,這三部分我們合稱為文件頭結(jié)構(gòu),最后再發(fā)送文件數(shù)據(jù)。所以在發(fā)送函數(shù)里我們就要進(jìn)行相應(yīng)的處理,當(dāng)然,在服務(wù)器的接收函數(shù)里我們也要進(jìn)行相應(yīng)的處理。對(duì)于文件大小,這次我們使用了qint64,它是64位的,可以表示一個(gè)很大的文件了。1.同前一節(jié),我們新建工程,將工程命名為“tcpSender”。注意添加network模塊。2.我們?cè)趙idget.ui文件中將界面設(shè)計(jì)如下。這里“主機(jī)”后的Line Edit的objectName為hostLineEdit;“端口”后的Line Edit的objectName為portLineEdit;下面的Progress Bar的objectName為clientProgressBar,其value屬性設(shè)為0;“狀態(tài)”Label的objetName為clientStatusLabel;“打開”按鈕的objectName為openButton;“發(fā)送”按鈕的objectName為sendButton;3.在widget.h 文件中進(jìn)行更改。(1)添加頭文件#include (2)添加private變量:QTcpSocket *tcpClient; QFile *localFile; /要發(fā)送的文件 qint64 totalBytes; /數(shù)據(jù)總大小 qint64 bytesWritten; /已經(jīng)發(fā)送數(shù)據(jù)大小 qint64 bytesToWrite; /剩余數(shù)據(jù)大小 qint64 loadSize; /每次發(fā)送數(shù)據(jù)的大小 QString fileName; /保存文件路徑QByteArray outBlock; /數(shù)據(jù)緩沖區(qū),即存放每次要發(fā)送的數(shù)據(jù)(3)添加私有槽函數(shù):private slots: void send(); /連接服務(wù)器 void startTransfer(); /發(fā)送文件大小等信息 void updateClientProgress(qint64); /發(fā)送數(shù)據(jù),更新進(jìn)度條 void displayError(QAbstractSocket:SocketError); /顯示錯(cuò)誤void openFile(); /打開文件4.在widget.cpp文件中進(jìn)行更改。添加頭文件:#include (1)在構(gòu)造函數(shù)中添加代碼:loadSize = 4*1024; totalBytes = 0; bytesWritten = 0; bytesToWrite = 0; tcpClient = new QTcpSocket(this); connect(tcpClient,SIGNAL(connected(),this,SLOT(startTransfer(); /當(dāng)連接服務(wù)器成功時(shí),發(fā)出connected()信號(hào),我們開始傳送文件 connect(tcpClient,SIGNAL(bytesWritten(qint64),this,SLOT(updateClientProgress(qint64); /當(dāng)有數(shù)據(jù)發(fā)送成功時(shí),我們更新進(jìn)度條 connect(tcpClient,SIGNAL(error(QAbstractSocket:SocketError),this, SLOT(displayError(QAbstractSocket:SocketError); ui-sendButton-setEnabled(false); /開始使”發(fā)送“按鈕不可用我們主要是進(jìn)行了變量的初始化和幾個(gè)信號(hào)和槽函數(shù)的關(guān)聯(lián)。(2)實(shí)現(xiàn)打開文件函數(shù)。void Widget:openFile() /打開文件 fileName = QFileDialog:getOpenFileName(this); if(!fileName.isEmpty() ui-sendButton-setEnabled(true); ui-clientStatusLabel-setText(tr(“打開文件 %1 成功!”) .arg(fileName); 該函數(shù)將在下面的“打開”按鈕單擊事件槽函數(shù)中調(diào)用。(3)實(shí)現(xiàn)連接函數(shù)。void Widget:send() /連接到服務(wù)器,執(zhí)行發(fā)送 ui-sendButton-setEnabled(false); bytesWritten = 0; /初始化已發(fā)送字節(jié)為0 ui-clientStatusLabel-setText(tr(“連接中”); tcpClient-connectToHost(ui-hostLineEdit-text(), ui-portLineEdit-text().toInt();/連接該函數(shù)將在“發(fā)送”按鈕的單擊事件槽函數(shù)中調(diào)用。(4)實(shí)現(xiàn)文件頭結(jié)構(gòu)的發(fā)送。void Widget:startTransfer() /實(shí)現(xiàn)文件大小等信息的發(fā)送 localFile = new QFile(fileName); if(!localFile-open(QFile:ReadOnly) qDebug() size(); /文件總大小 QDataStream sendOut(&outBlock,QIODevice:WriteOnly); sendOut.setVersion(QDataStream:Qt_4_6); QString currentFileName = fileName.right(fileName.size() - fileName.lastIndexOf(/)-1); sendOut qint64(0) qint64(0) seek(0); sendOuttotalByteswrite(outBlock); /發(fā)送完頭數(shù)據(jù)后剩余數(shù)據(jù)的大小 ui-clientStatusLabel-setText(tr(已連接); outBlock.resize(0);(5)下面是更新進(jìn)度條,也就是發(fā)送文件數(shù)據(jù)。void Widget:updateClientProgress(qint64 numBytes) /更新進(jìn)度條,實(shí)現(xiàn)文件的傳送 bytesWritten += (int)numBytes; /已經(jīng)發(fā)送數(shù)據(jù)的大小 if(bytesToWrite 0) /如果已經(jīng)發(fā)送了數(shù)據(jù) outBlock = localFile-read(qMin(bytesToWrite,loadSize); /每次發(fā)送loadSize大小的數(shù)據(jù),這里設(shè)置為4KB,如果剩余的數(shù)據(jù)不足4KB, /就發(fā)送剩余數(shù)據(jù)的大小 bytesToWrite -= (int)tcpClient-write(outBlock); /發(fā)送完一次數(shù)據(jù)后還剩余數(shù)據(jù)的大小 outBlock.resize(0); /清空發(fā)送緩沖區(qū) else localFile-close(); /如果沒有發(fā)送任何數(shù)據(jù),則關(guān)閉文件 ui-clientProgressBar-setMaximum(totalBytes); ui-clientProgressBar-setValue(bytesWritten); /更新進(jìn)度條 if(bytesWritten = totalBytes) /發(fā)送完畢 ui-clientStatusLabel-setText(tr(“傳送文件 %1 成功”).arg(fileName); localFile-close(); tcpClient-close(); (6)實(shí)現(xiàn)錯(cuò)誤處理函數(shù)。void Widget:displayError(QAbstractSocket:SocketError) /顯示錯(cuò)誤 qDebug() errorString(); tcpClient-close(); ui-clientProgressBar-reset(); ui-clientStatusLabel-setText(tr(“客戶端就緒”); ui-sendButton-setEnabled(true);(7)我們從widget.ui中分別進(jìn)行“打開”按鈕和“發(fā)送”按鈕的單擊事件槽函數(shù),然后更改如下。void Widget:on_openButton_clicked() /打開按鈕 openFile();void Widget:on_sendButton_clicked() /發(fā)送按鈕 send();5.我們?yōu)榱耸钩绦蛑械闹形牟伙@示亂碼,在main.cpp文件中更改。添加頭文件:#include 在main函數(shù)中添加代碼:QTextCodec:setCodecForTr(QTextCodec:codecForLocale();6.運(yùn)行程序,效果如下。7.程序整體思路分析。我們?cè)O(shè)計(jì)好界面,然后按下“打開”按鈕,選擇我們要發(fā)送的文件,這時(shí)調(diào)用了openFile()函數(shù)。然后我們點(diǎn)擊“發(fā)送”按鈕,調(diào)用send()函數(shù),與服務(wù)器進(jìn)行連接。當(dāng)連接成功時(shí)就會(huì)發(fā)出connected()信號(hào),這時(shí)就會(huì)執(zhí)行startTransfer()函數(shù),進(jìn)行文件頭結(jié)構(gòu)的發(fā)送,當(dāng)發(fā)送成功時(shí)就會(huì)發(fā)出bytesWritten(qint64)信號(hào),這時(shí)我們執(zhí)行updateClientProgress(qint64 numBytes)進(jìn)行文件數(shù)據(jù)的傳輸和進(jìn)度條的更新。這里使用了一個(gè)loadSize變量,我們?cè)跇?gòu)造函數(shù)中將其初始化為4*1024即4字節(jié),它的作用是,我們將整個(gè)大的文件分成很多小的部分進(jìn)行發(fā)送,每部分為4字節(jié)。而當(dāng)連接出現(xiàn)問(wèn)題時(shí)就會(huì)發(fā)出error(QAbstractSocket:SocketError)信號(hào),這時(shí)就會(huì)執(zhí)行displayError()函數(shù)。對(duì)于程序中其他細(xì)節(jié)我們就不再分析,希望大家能自己編程研究一下。二、服務(wù)器端。我們?cè)诜?wù)器端進(jìn)行數(shù)據(jù)的接收。服務(wù)器端程序是很簡(jiǎn)單的,我們開始進(jìn)行監(jiān)聽,一旦發(fā)現(xiàn)有連接請(qǐng)求就發(fā)出newConnection()信號(hào),然后我們便接受連接,開始接收數(shù)據(jù)。1.新建工程,名字為“tcpReceiver”。2.我們更改widget.ui文件,設(shè)計(jì)界面如下。其中“服務(wù)器端”Label的objectName為serverStatusLabel;進(jìn)度條Progress Bar的objectName為serverProgressBar,設(shè)置其value屬性為0;“開始監(jiān)聽”按鈕的objectName為startButton。效果如下。3.更改widget.h文件的內(nèi)容。(1)添加頭文件:#include (2)添加私有變量: QTcpServer tcpServer; QTcpSocket *tcpServerConnection; qint64 totalBytes; /存放總大小信息 qint64 bytesReceived; /已收到數(shù)據(jù)的大小 qint64 fileNameSize; /文件名的大小信息 QString fileName; /存放文件名 QFile *localFile; /本地文件QByteArray inBlock; /數(shù)據(jù)緩沖區(qū)(3)添加私有槽函數(shù):private slots: void on_startButton_clicked(); void start(); /開始監(jiān)聽 void acceptConnection(); /建立連接 void updateServerProgress(); /更新進(jìn)度條,接收數(shù)據(jù)void displayError(QAbstractSocket:SocketError socketError);/顯示錯(cuò)誤4.更改widget.cpp文件。(1)在構(gòu)造函數(shù)中添加代碼:totalBytes = 0; bytesReceived = 0; fileNameSize = 0; connect(&tcpServer,SIGNAL(newConnection(),this,SLOT(acceptConnection();/當(dāng)發(fā)現(xiàn)新連接時(shí)發(fā)出newConnection()信號(hào)(2)實(shí)現(xiàn)start()函數(shù)。void Widget:start() /開始監(jiān)聽 ui-startButton-setEnabled(false); bytesReceived =0; if(!tcpServer.listen(QHostAddress:LocalHost,6666) qDebug() serverStatusLabel-setText(tr(“監(jiān)聽”);(3)實(shí)現(xiàn)接受連接函數(shù)。void Widget:acceptConnection() /接受連接 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(“接受連接”); tcpServer.close();(4)實(shí)現(xiàn)更新進(jìn)度條函數(shù)。void Widget:updateServerProgress() /更新進(jìn)度條,接收數(shù)據(jù) QDataStream in(tcpServerConnection); in.setVersion(QDataStream:Qt_4_6); if(bytesReceived bytesAvailable() = sizeof(qint64)*2) & (fileNameSize = 0) /接收數(shù)據(jù)總大小信息和文件名大小信息 in totalBytes fileNameSize; bytesReceived += sizeof(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 error!”; return; else return; if(bytesReceived bytesAvailable(); inBlock = tcpServerConnection-readAll(); localFile-write(inBlock); inBlock.resize(0); ui-serverProgressBar-setMaximum(totalBytes); ui-serverProgressBar-setValue(bytesReceived); /更新進(jìn)度條 if(bytesReceived = totalBytes) /接收數(shù)據(jù)完成時(shí) tcpServerConnection-close(); localFile-close(); ui-startButton-setEnabled(true);ui-serverStatusLabel-setText(tr(“接收文件 %1 成功!”).arg(fileName); (5)錯(cuò)誤處理函數(shù)。void Widget:displayError(QAbstractSocket:SocketError) /錯(cuò)誤處理 qDebug() errorString(); tcpServerConnection-close(); ui-serverProgressBar-reset(); ui-serverStatusLabel-setText(tr(“服務(wù)端就緒”); ui-startButton-setEnabled(true);(6)我們?cè)趙idget.ui中進(jìn)入“開始監(jiān)聽”按鈕的單擊事件槽函數(shù),更改如下。void Widget:on_startButton_clicked() /開始監(jiān)聽按鈕 start();5.我們?yōu)榱耸钩绦蛑械闹形牟伙@示亂碼,在main.cpp文件中更改。添加頭文件:#include 在main函數(shù)中添加代碼:QTextCodec:setCodecForTr(QTextCodec:codecForLocale();6.運(yùn)行程序,并同時(shí)運(yùn)行tcpSender程序,效果如下。我們先在服務(wù)器端按下“開始監(jiān)聽”按鈕,然后在客戶端輸入主機(jī)地址和端口號(hào),然后打開要發(fā)送的文件,點(diǎn)擊“發(fā)送”按鈕進(jìn)行發(fā)送。在這兩節(jié)里我們介紹了TCP的應(yīng)用,可以看到服務(wù)器端和客戶度端都可以當(dāng)做發(fā)送端或者接收端,而且數(shù)據(jù)的發(fā)送與接收只要使用相對(duì)應(yīng)的協(xié)議即可,它是可以根據(jù)用戶的需要來(lái)進(jìn)行編程的,沒有固定的格式。QT網(wǎng)絡(luò)編程-UDP這一節(jié)講述UDP編程的知識(shí)。UDP(User Datagram Protocol即用戶數(shù)據(jù)報(bào)協(xié)議)是一個(gè)輕量級(jí)的,不可靠的,面向數(shù)據(jù)報(bào)的無(wú)連接協(xié)議。對(duì)于UDP我們不再進(jìn)行過(guò)多介紹,如果你對(duì)UDP不是很了解,而且不知道它有什么用,那么我們這里就舉個(gè)簡(jiǎn)單的例子:我們現(xiàn)在幾乎每個(gè)人都使用的騰訊QQ,其聊天時(shí)就是使用UDP協(xié)議進(jìn)行消息發(fā)送的。就像QQ那樣,當(dāng)有很多用戶,發(fā)送的大部分都是短消息,要求能及時(shí)響應(yīng),并且對(duì)安全性要求不是很高的情況下使用UDP協(xié)議。 在Qt中提供了QUdpSocket 類來(lái)進(jìn)行UDP數(shù)據(jù)報(bào)(datagrams)的發(fā)送和接收。這里我們還要了解一個(gè)名詞Socket,也就是常說(shuō)的“套接字”。 Socket簡(jiǎn)單地說(shuō),就是一個(gè)IP地址加一個(gè)port端口。因?yàn)槲覀円獋鬏敂?shù)據(jù),就要知道往哪個(gè)機(jī)子上傳送,而IP地址確定了一臺(tái)主機(jī),但是這臺(tái)機(jī)子上可能運(yùn)行著各種各樣的網(wǎng)絡(luò)程序,我們要往哪個(gè)程序中發(fā)送呢?這時(shí)就要使用一個(gè)端口來(lái)指定UDP程序。所以說(shuō),Socket指明了數(shù)據(jù)報(bào)傳輸?shù)穆窂?。下面我們將編寫兩個(gè)程序,一個(gè)用來(lái)發(fā)送數(shù)據(jù)報(bào),可以叫做客戶端;另一個(gè)用來(lái)接收數(shù)據(jù)報(bào),可以叫做服務(wù)器端,它們均應(yīng)用UDP協(xié)議。這樣也就構(gòu)成了所謂的C/S(客戶端/服務(wù)器)編程模型。我們會(huì)在編寫程序的過(guò)程中講解一些相關(guān)的網(wǎng)絡(luò)知識(shí)。(一)發(fā)送端(客戶端)1.我們新建Qt4 Gui Application,工程名為“udpSender”,選中QtNetwork模塊,Base class選擇QWidget。2.我們?cè)趙idget.ui文件中,往界面上添加一個(gè)Push Button,更改其顯示文本為“開始廣播”,然后進(jìn)入其單擊事件槽函數(shù)。3.我們?cè)趙idget.h文件中更改。添加頭文件:#include 添加private私有對(duì)象:QUdpSocket *sender;4.我們?cè)趙idget.cpp中進(jìn)行更改。在構(gòu)造函數(shù)中添加:sender = new QUdpSocket(this);更改“開始廣播”按鈕的單擊事件槽函數(shù):void Widget:on_pushButton_clicked() /發(fā)送廣播 QByteArray datagram = “hello world!”; sender-writeDatagram(datagram.data(),datagram.size(), QHostAddress:Broadcast,45454);這里我們定義了一個(gè)QByteArray類型的數(shù)據(jù)報(bào)datagram,其內(nèi)容為“hello world!”。然后我們使用QUdpSocket類的writeDatagram()函數(shù)來(lái)發(fā)送數(shù)據(jù)報(bào),這個(gè)函數(shù)有四個(gè)參數(shù),分別是數(shù)據(jù)報(bào)的內(nèi)容,數(shù)據(jù)報(bào)的大小,主機(jī)地址和端口號(hào)。對(duì)于數(shù)據(jù)報(bào)的大小,它根據(jù)平臺(tái)的不同而不同,但是這里建議不要超過(guò)512字節(jié)。這里我們使用了廣播地址QHostAddress:Broadcast,這樣就可以同時(shí)給網(wǎng)絡(luò)中所有的主機(jī)發(fā)送數(shù)據(jù)報(bào)了。對(duì)于端口號(hào),它是可以隨意指定的,但是一般1024以下的端口號(hào)通常屬于保留端口號(hào),所以我們最好使用大于1024的端口,最大為65535。我們這里使用了45454這個(gè)端口號(hào),一定要注意,在下面要講的服務(wù)器程序中,也要使用相同的端口號(hào)。5.發(fā)送端就這么簡(jiǎn)單,我們運(yùn)行程序,效果如下。(二)接收端(服務(wù)器端)1.我們新建Qt4 Gui Application,工程名為“udpReceiver”,選中QtNetwork模塊,Base class選擇QWidget。此時(shí)工程文件列表中應(yīng)包含兩個(gè)工程,如下圖。2.我們?cè)趗dpReceiver工程中的widget.ui文件中,向界面上添加一個(gè)Label部件,更改其顯示文本為“等待接收數(shù)據(jù)!”,效果如下。3.我們?cè)趗dpReceiver工程中的widget.h文件中更改。添加頭文件:#include 添加private私有對(duì)象:QUdpSocket *receiver;添加私有槽函數(shù):private slots:void processPendingDatagram();4.我們?cè)趗dpReceiver工程中的widget.cpp文件中更改。在構(gòu)造函數(shù)中:receiver = new QUdpSocket(this);receiver-bind(45454,QUdpSocket:ShareAddress);connect(receiver,SIGNAL(readyRead(),this,SLOT(processPendingDatagram();我們?cè)跇?gòu)造函數(shù)中將receiver綁定到45454端口,這個(gè)端口就是上面發(fā)送端設(shè)置的端口,二者必須一樣才能保證接收到數(shù)據(jù)報(bào)。我們這里使用了綁定模式QUdpSocket:ShareAddress,它表明其他服務(wù)也可以綁定到這個(gè)端口上。因?yàn)楫?dāng)receiver發(fā)現(xiàn)有數(shù)據(jù)報(bào)到達(dá)時(shí)就會(huì)發(fā)出readyRead()信號(hào),所以我們將其和我們的數(shù)據(jù)報(bào)處理函數(shù)相關(guān)聯(lián)。數(shù)據(jù)報(bào)處理槽函數(shù)實(shí)現(xiàn)如下:void Widget:processPendingDatagram() /處理等待的數(shù)據(jù)報(bào) while(receiver-hasPendingDatagrams() /擁有等待的數(shù)據(jù)報(bào) QByteArray datagram; /擁于存放接收的數(shù)據(jù)報(bào) datagram.resize(receiver-pendingDatagramSize(); /讓datagram的大小為等待處理的數(shù)據(jù)報(bào)的大小,這樣才能接收到完整的數(shù)據(jù) receiver-readDatagram(datagram.data(),datagram.size(); /接收數(shù)據(jù)報(bào),將其存放到datagram中 ui-label-setText(datagram); /將數(shù)據(jù)報(bào)內(nèi)容顯示出來(lái) 5.我們?cè)诠こ塘斜碇衭dpReceiver工程上點(diǎn)擊鼠標(biāo)右鍵,在彈出的菜單上選擇run菜單來(lái)運(yùn)行該工程。6.第一次運(yùn)行該程序時(shí),系統(tǒng)可能會(huì)提示警告,我們選擇“解除阻止”。如果是在linux下,你可能還需要關(guān)閉防火墻。7.我們同時(shí)再運(yùn)行udpSender程序。然后點(diǎn)擊其上的“發(fā)送廣播”按鈕,這時(shí)會(huì)在udpReceiver上顯示數(shù)據(jù)報(bào)的內(nèi)容。效果如下。可以看到,UDP的應(yīng)用是很簡(jiǎn)單的。我們只需要在發(fā)送端執(zhí)行writeDatagram()函數(shù)進(jìn)行數(shù)據(jù)報(bào)的發(fā)送,然后在接收端綁定端口,并關(guān)聯(lián)readyRead()信號(hào)和數(shù)據(jù)報(bào)處理函數(shù)即可。QT網(wǎng)絡(luò)編程-獲取本機(jī)IP對(duì)于IP地址,其實(shí),會(huì)上網(wǎng)的人都應(yīng)該聽說(shuō)過(guò)它。如果你實(shí)在很不了解它,那么我們簡(jiǎn)單的說(shuō):IP即Internet Protocol (網(wǎng)絡(luò)之間互聯(lián)的協(xié)議),協(xié)議就是規(guī)則,地球人都用一樣的規(guī)則,所以我們可以訪問(wèn)全球任何的網(wǎng)站;而IP地址就是你聯(lián)網(wǎng)時(shí)分配給你機(jī)子的一個(gè)地址。如果把網(wǎng)絡(luò)比喻成地圖,那IP地址就像地圖上的經(jīng)緯度一樣,它確定了你的主機(jī)在網(wǎng)絡(luò)中的位置。其實(shí)知道我們以后要用IP地址來(lái)代表網(wǎng)絡(luò)中的一臺(tái)計(jì)算機(jī)就夠了。(_不一定科學(xué)但是很直白的表述)下面我們就講解如何獲取自己電腦的IP地址以及其他網(wǎng)絡(luò)信息。這一節(jié)中,我們會(huì)涉及到網(wǎng)絡(luò)模塊(QtNetwork Modul
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 微處理器與接口技術(shù) 課件 第5章 接口及標(biāo)準(zhǔn)化
- 2025年心理測(cè)量與評(píng)估方法學(xué)的綜合能力考試卷及答案
- 2025年教育法與教育政策的綜合能力考核試卷及答案
- 2025年健康行為與心理介入的實(shí)務(wù)能力考試試卷及答案
- 2025年化學(xué)工程師考核試卷及答案
- 2025年中國(guó)郵政集團(tuán)有限公司廣西壯族自治區(qū)分公司校園招聘筆試模擬試題及完整答案詳解1套
- 特定場(chǎng)所安全管理制度
- 特殊學(xué)校學(xué)生管理制度
- 特殊工時(shí)休假管理制度
- 特殊患者安全管理制度
- GB 12995-2006機(jī)動(dòng)輪椅車
- 40篇短文搞定高考英語(yǔ)3500詞
- 【山東】國(guó)際足球運(yùn)動(dòng)小鎮(zhèn)概念規(guī)劃方案
- 海氏(hay)職位分析法-介紹、實(shí)踐與評(píng)價(jià)合集課件
- 煤礦安全規(guī)程露天部分參考題庫(kù)(含答案)
- 有趣的英漢互譯-課件
- (參考)菲達(dá)公司國(guó)內(nèi)電除塵器業(yè)績(jī)表
- 步進(jìn)式加熱爐耐材砌筑施工方案
- GB-T12232-2005- 通用閥門 法蘭連接鐵制閘閥
- 2022年中國(guó)電信店長(zhǎng)技能四級(jí)認(rèn)證教材
- 常見散料堆積密度匯總-共10
評(píng)論
0/150
提交評(píng)論