Qt實(shí)現(xiàn)簡(jiǎn)單TCP服務(wù)器_第1頁(yè)
Qt實(shí)現(xiàn)簡(jiǎn)單TCP服務(wù)器_第2頁(yè)
Qt實(shí)現(xiàn)簡(jiǎn)單TCP服務(wù)器_第3頁(yè)
Qt實(shí)現(xiàn)簡(jiǎn)單TCP服務(wù)器_第4頁(yè)
Qt實(shí)現(xiàn)簡(jiǎn)單TCP服務(wù)器_第5頁(yè)
已閱讀5頁(yè),還剩13頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第Qt實(shí)現(xiàn)簡(jiǎn)單TCP服務(wù)器本文實(shí)例為大家分享了Qt學(xué)習(xí)記錄之簡(jiǎn)單的TCP服務(wù)器,供大家參考,具體內(nèi)容如下

簡(jiǎn)單的多連接TCP服務(wù)器?

本節(jié)我們使用Qt來(lái)編寫(xiě)一個(gè)簡(jiǎn)單的多連接TCP服務(wù)器程序,涉及到的功能有監(jiān)聽(tīng)本地IP、打印上線(xiàn)客戶(hù)端的IP端口號(hào),接收客戶(hù)端發(fā)來(lái)的文字信息并打印其IP端口號(hào)、單獨(dú)或全部地向客戶(hù)端發(fā)送文字信息、顯示下線(xiàn)客戶(hù)端的IP端口號(hào),并具有踢人的功能。

?該程序使用正點(diǎn)原子的網(wǎng)絡(luò)助手來(lái)驗(yàn)證功能。Qt基于5.9.9版本。

1、創(chuàng)建工程以及配置工作

創(chuàng)建工程的過(guò)程就不再介紹了,這里我選擇的是QWidget,因?yàn)楸容^簡(jiǎn)單。

然后我們?cè)?pro文件中添加網(wǎng)絡(luò)的模塊,否則待會(huì)添加頭文件時(shí)會(huì)提示沒(méi)有這個(gè)頭文件。

其他東西不需要看,只要在這后面加上network即可。

再然后,在widget.h頭文件中包含兩個(gè)頭文件:

#includeQTcpServer

#includeQTcpSocket

使用Qt搭建TCP服務(wù)器需要兩個(gè)套接字:

一個(gè)是QTcpServer套接字,這是是用來(lái)監(jiān)聽(tīng)本地的某個(gè)IP及端口的。監(jiān)聽(tīng)成功后,其他的TCP客戶(hù)端就可以連接這個(gè)服務(wù)器了(當(dāng)然前提是這個(gè)服務(wù)器監(jiān)聽(tīng)的IP是公網(wǎng)IP,或者客戶(hù)端與服務(wù)器在同一局域網(wǎng)下)一個(gè)是QTcpSocket套接字,這個(gè)是服務(wù)器與客戶(hù)端通信用的套接字。每當(dāng)有一臺(tái)客戶(hù)端連接上了這臺(tái)服務(wù)器,都會(huì)產(chǎn)生這樣的一個(gè)套接字??蛻?hù)端可以通過(guò)某個(gè)套接字來(lái)查看某個(gè)客戶(hù)端的IP地址與端口號(hào)等信息,也可以拿著這個(gè)套接字單獨(dú)地與這一個(gè)客戶(hù)端收發(fā)數(shù)據(jù)。理論上來(lái)講,一個(gè)TCP服務(wù)器是可以被無(wú)限個(gè)客戶(hù)端連上的。

這里也插一句,如果使用Qt搭建一個(gè)TCP客戶(hù)端,只需要QTcpSocket套接字。

2、ui界面的設(shè)計(jì)

1、comboBox。下拉列表框,用來(lái)選擇監(jiān)聽(tīng)的IP地址,因?yàn)槟軌虮槐O(jiān)聽(tīng)的地址肯定是本機(jī)擁有的地址,可以是有線(xiàn)、無(wú)線(xiàn)網(wǎng)卡的IP地址(局域網(wǎng)),也可以是寬帶分配到的IP地址(廣域網(wǎng))。下一節(jié)我們?cè)賮?lái)學(xué)習(xí)如何查看本機(jī)支持的IP。

2、portEdit。旁邊的單行文本框是用來(lái)輸入要監(jiān)聽(tīng)的端口號(hào)。有時(shí)候IP的某個(gè)端口號(hào)已經(jīng)被某個(gè)程序占用,此時(shí)再去監(jiān)聽(tīng)就會(huì)監(jiān)聽(tīng)失敗。

3、openbtn。點(diǎn)擊開(kāi)啟按鈕,監(jiān)聽(tīng)選定的IP地址及端口號(hào)。監(jiān)聽(tīng)失敗會(huì)在QtCreator的控制臺(tái)打印失敗的信息。監(jiān)聽(tīng)成功,同樣也會(huì)打印信息,并且IP下拉框、端口號(hào)文本框還有本按鈕控件都會(huì)變成不可選中狀態(tài)。

4、comboBox_2。選擇某個(gè)已連接的客戶(hù)端(如果有的話(huà)),或者選擇全部。這個(gè)可以查看連接上服務(wù)器的客戶(hù)端IP及端口號(hào),單獨(dú)或全部地向客戶(hù)端發(fā)送信息,或者強(qiáng)制踢下線(xiàn)。

5、kickbtn。點(diǎn)擊按鈕,強(qiáng)制使選中的客戶(hù)端下線(xiàn)。

6、closebtn。關(guān)閉服務(wù)器。停止監(jiān)聽(tīng)之前選中的IP及端口號(hào),并斷開(kāi)全部的TCP連接。

7、recvEdit。接收文本框。當(dāng)客戶(hù)端發(fā)來(lái)信息,會(huì)打印在上面。

8、clearbtn。清除接收文本框內(nèi)的全部?jī)?nèi)容。

9、pushButton。在控制臺(tái)上打印全部連接的客戶(hù)端IP及端口號(hào)。

10、sendEdit。發(fā)送文本框。

11、sendbtn。點(diǎn)擊發(fā)送按鈕,會(huì)向某個(gè)、全部客戶(hù)端發(fā)送文本框內(nèi)的信息

大體的設(shè)計(jì)就是這樣,目前只滿(mǎn)足了基本的功能,后續(xù)可以增添更多的功能,并對(duì)界面進(jìn)行美化

3、本地IP的獲取

從這一節(jié)開(kāi)始,我們將正式進(jìn)行代碼的編寫(xiě)

首先,打開(kāi)命令行,輸入ipconfig

這四個(gè)IP地址就我我電腦上可以監(jiān)聽(tīng)的IP地址,我的程序就是以此來(lái)搭建TCP服務(wù)器。其他的IP地址,目前是監(jiān)聽(tīng)不了的。

Qt獲取本機(jī)IP

首先在widge.cpp文件中包含一個(gè)頭文件

#includeQtNetwork

然后在Widget類(lèi)的構(gòu)造函數(shù)中添加如下代碼:

/*讀取本機(jī)網(wǎng)卡信息...*/

QStringlocalHostName=QHostInfo::localHostName();

QHostInfoinfo=QHostInfo::fromName(localHostName);

/*將本機(jī)所有的IPV4地址添加到comboBox下.*/

foreach(QHostAddressipAddress,info.addresses())

{

if(ipAtocol()==QAbstractSocket::IPv4Protocol)

{

qDebug()ipAddress.toString();

ui-comboBox-addItem(ipAddress.toString());

}

}

這里解釋幾點(diǎn):

調(diào)用info.addresses()成員函數(shù),返回的是一個(gè)QList容器,里面包含著本機(jī)全部的IP地址所有的IP地址都在一個(gè)容器中,我們需要遍歷這個(gè)容器,將里面的IP地址一一取出,這里用到了foreach去遍歷。和for循環(huán)類(lèi)似,首先定義一個(gè)用于接收的對(duì)象:ipAddress,然后會(huì)一一讀取容器中的內(nèi)容,賦值給這個(gè)對(duì)象。如果暫時(shí)弄不明白也沒(méi)有關(guān)系,看多了自然就懂了。或者學(xué)過(guò)python,這句語(yǔ)句和foripAddrinipAddrList:一樣。if(ipAtocol()==QAbstractSocket::IPv4Protocol)這句用來(lái)判斷遍歷到的IP是不是IPV4的地址。因?yàn)槟壳癐PV6還沒(méi)有完全普及,而且不如IPV4易讀。下拉列表控件使用addItem()成員函數(shù)添加元素。

點(diǎn)擊運(yùn)行,控制臺(tái)就會(huì)打印信息,并且下拉列表也會(huì)顯示信息:

4、開(kāi)啟服務(wù)器

首先要有一個(gè)QTcpServer套接字對(duì)象,可以直接在Widget類(lèi)中聲明這么一個(gè)對(duì)象;也可以在類(lèi)中聲明一個(gè)對(duì)象指針,然后在構(gòu)造函數(shù)中new一個(gè)對(duì)象,讓這個(gè)指針指向它。這里我選擇第二種方法。

/*在widget.h中類(lèi)定義里添加*/

QTcpServer*server;

/*在widget.cpp中構(gòu)造函數(shù)中添加*/

server=newQTcpServer(this);

然后為開(kāi)啟按鈕添加槽函數(shù),這里我圖方便直接右擊控件并點(diǎn)擊轉(zhuǎn)到槽。

voidWidget::on_openbtn_clicked()

/*監(jiān)聽(tīng)本地IP加端口號(hào).*/

if(server-listen(QHostAddress(ui-comboBox-currentText()),ui-portEdit-text().toInt())==false)

{

/*監(jiān)聽(tīng)失敗,打印信息.*/

qDebug()"listenfalse";

}

else

{

/*監(jiān)聽(tīng)成功,則將一些控件鎖死.*/

ui-openbtn-setDisabled(true);

ui-portEdit-setDisabled(true);

ui-comboBox-setDisabled(true);

qDebug()"監(jiān)聽(tīng)成功";

/*激活關(guān)閉按鈕.*/

ui-closebtn-setEnabled(true);

}

}

解釋?zhuān)?/p>

對(duì)于下拉列表控件(comboBox),使用currentText()成員函數(shù)獲取選中元素的信息,返回QString型。

對(duì)于單行文本控件(portEdit),使用text()成員函數(shù)返回文本,并用toInt()轉(zhuǎn)化為int型

對(duì)于TCP服務(wù)器套接字(server),使用listen(constQHostAddressaddress=QHostAddress::Any,quint16port=0)成員函數(shù)綁定IP及端口。

對(duì)于大部分控件,使用setDisabled(true)成員函數(shù)可使控件變?yōu)椴豢牲c(diǎn)擊狀態(tài)

最后,我們就可以開(kāi)啟服務(wù)器了。如果開(kāi)啟失敗,往往是因?yàn)檫x擇的端口號(hào)被占用,這里推薦使用8081這個(gè)端口號(hào)(8080經(jīng)常會(huì)被占用)。開(kāi)啟成功后,我們就可以使用正點(diǎn)原子的網(wǎng)絡(luò)助手去嘗試連接它。

可以看到,右邊的網(wǎng)絡(luò)助手已經(jīng)處于連接成功的狀態(tài),因此可以證明TCP服務(wù)器已經(jīng)被成功開(kāi)啟。其他的東西暫時(shí)不用看,后面會(huì)一一實(shí)現(xiàn)。

5、服務(wù)器等待客戶(hù)端連接

在構(gòu)造函數(shù)中添加如下代碼:

connect(server,QTcpServer::newConnection,this,[=](){

/*獲取新連接客戶(hù)端的socket*/

QTcpSocket*socket=server-nextPendingConnection();

/*將這個(gè)socket添加到List容器中...*/

sockList.append(socket);

/*獲取客戶(hù)端的IP地址和端口號(hào)信息,并轉(zhuǎn)換為字符串.*/

QStringinfo=socket-peerAddress().toString()\

+':'+QString::number(socket-peerPort());

/*將信息打印到文本框.*/

ui-recvEdit-append("已連接:"+info);

/*將客戶(hù)端的信息添加到comboBox_2下.*/

ui-comboBox_2-addItem(info);

/*將新連接的socket對(duì)象的可以讀取信號(hào)連接到接收槽函數(shù).*/

connect(socket,QTcpSocket::readyRead,this,Widget::on_recv);

/*將新連接的socket對(duì)象的斷開(kāi)連接信號(hào)連接到斷開(kāi)槽函數(shù).*/

connect(socket,QTcpSocket::disconnected,this,Widget::on_disconnect);

});

解釋?zhuān)?/p>

當(dāng)有客戶(hù)端連接到服務(wù)器,服務(wù)器套接字會(huì)觸發(fā)一個(gè)newConnection信號(hào)。服務(wù)器套接字通過(guò)nextPendingConnection()成員函數(shù)獲取到用于和客戶(hù)端通信的socket(QTcpSocket)。QTcpSocket套接字通過(guò)peerAddress()和peerPort()成員函數(shù),得到該客戶(hù)端的IP及端口號(hào)。toString()是為了把IP信息轉(zhuǎn)化為字符串,可以試試打印轉(zhuǎn)化前的樣子。QString::number(longn,intbase=10)用于將數(shù)字轉(zhuǎn)化為字符串。接收文本框(recvEdit)使用append()成員函數(shù)打印文字。最后的兩個(gè)信號(hào)和槽的連接暫時(shí)不用看這里我還使用了一個(gè)QList容器來(lái)保存已連接客戶(hù)端的socket

/*在widget.h中類(lèi)定義里添加*/

QListQTcpSocket*sockList;

最后,我們就可以檢驗(yàn)一下多連接時(shí)的狀態(tài)了

6、實(shí)現(xiàn)接收數(shù)據(jù)

如果用于通信的socket(QTcpSocket)接收到數(shù)據(jù),就會(huì)觸發(fā)QTcpSocket::readyRead信號(hào),我這里寫(xiě)了一個(gè)槽函數(shù),專(zhuān)門(mén)用來(lái)接收數(shù)據(jù):

voidWidget::on_recv()

/*找到觸發(fā)信號(hào)的那個(gè)socket對(duì)象.*/

QTcpSocket*sock=qobject_castQTcpSocket*(sender());

/*讀取信息并轉(zhuǎn)化為字符串.*/

QStringinfo="來(lái)自"+sock-peerAddress().toString()\

+':'+QString::number(sock-peerPort());

/*將客戶(hù)端的信息打印到文本框.*/

ui-recvEdit-append(info);

/*將接收到的數(shù)據(jù)也打印到文本框.*/

ui-recvEdit-append(sock-readAll());

}

解釋?zhuān)?/p>

第一句是用來(lái)找到觸發(fā)信號(hào)的那個(gè)對(duì)象(QTcpSocket)。因?yàn)檫@個(gè)程序允許多個(gè)客戶(hù)端連接,每個(gè)客戶(hù)端在連接后,server都會(huì)獲取到與之相對(duì)應(yīng)的QTcpSocket套接字對(duì)象,意思就是說(shuō)套接字是與客戶(hù)端一一對(duì)應(yīng)的。因此找到觸發(fā)信號(hào)的QTcpSocket對(duì)象,就等于找到了發(fā)送消息的那個(gè)客戶(hù)端。同樣的,將客戶(hù)端的信息打包成字符串,并且顯示到接收文本框QTcpSocket對(duì)象,調(diào)用readAll()成員函數(shù),來(lái)獲取接收到的信息。

現(xiàn)在也可以解釋上一節(jié)中的connect(socket,QTcpSocket::readyRead,this,Widget::on_recv);了??赡苡腥藭?huì)疑惑,這里的socket是局部變量,調(diào)用完會(huì)被釋放掉,那么這個(gè)連接是不是傳了個(gè)野指針進(jìn)去?其實(shí)并不是的,socket是個(gè)指針,指向server-nextPendingConnection()返回的QTcpSocket對(duì)象,真正的對(duì)象應(yīng)該是存在內(nèi)部堆內(nèi)存中的,這里只是用了一個(gè)局部指針變量去接收它。而connect函數(shù),傳進(jìn)去的是地址,地址自然就是內(nèi)部QTcpSocket對(duì)象的地址了。

最后,演示一下:

注意:Qt使用utf-8編碼格式,而原子的軟件默認(rèn)是GBk格式,所以發(fā)送中文之前,先把原子的軟件全部改成utf-8格式。

實(shí)現(xiàn)清除數(shù)據(jù)

這個(gè)非常簡(jiǎn)單,就沒(méi)有必要多說(shuō)了:

voidWidget::on_clearbtn_clicked()

/*點(diǎn)擊清除按鈕則清除接收文本框.*/

ui-recvEdit-clear();

}

7、實(shí)現(xiàn)客戶(hù)端的選擇

對(duì)客戶(hù)端的選擇無(wú)非就兩種情況:一種情況是選擇全部連接上的客戶(hù)端,一種是選擇單獨(dú)的某個(gè)客戶(hù)端。

我為Widget類(lèi)添加了一個(gè)屬性來(lái)解決這兩類(lèi)問(wèn)題:

QTcpSocket*currSock;

如果第二個(gè)下拉列表框選擇了All,那么這個(gè)指針就會(huì)指向NULL。如果選擇的是某個(gè)特定的IP及端口,那么這個(gè)指針就會(huì)指向?qū)?yīng)的那個(gè)QTcpSocket對(duì)象了。

那么對(duì)象從哪里找?從前幾節(jié)說(shuō)過(guò)的容器中去找。這個(gè)容器用于保存當(dāng)前連接上的客戶(hù)端的socket。每當(dāng)有客戶(hù)端連上,這個(gè)容器就會(huì)將它的socket保存進(jìn)來(lái)。每當(dāng)有客戶(hù)端下線(xiàn),這個(gè)容器同樣會(huì)把下線(xiàn)客戶(hù)端的socket刪掉。

QListQTcpSocket*sockList;

QList表示這是一個(gè)QList類(lèi)型的容器,還有其他類(lèi)型的容器尖括號(hào)內(nèi)的東西,表示這個(gè)一個(gè)裝QTcpSocket對(duì)象指針的容器。因?yàn)檫@是一個(gè)模板類(lèi),還可以是int型的容器,取決于自己的定義。最后的sockList則代表這個(gè)容器的名字

下拉列表框的信號(hào)和槽

這里我同樣是以右擊控件再點(diǎn)轉(zhuǎn)到槽的方式來(lái)自動(dòng)生成槽函數(shù):

這里的信號(hào)不要選錯(cuò)了,當(dāng)這個(gè)控件選擇的選項(xiàng)發(fā)送變化時(shí),會(huì)觸發(fā)這個(gè)信號(hào)。下面是槽函數(shù):

voidWidget::on_comboBox_2_currentIndexChanged(constQStringarg1)

/*如果當(dāng)前選擇的是All,當(dāng)前sock指針就指向空.*/

if(arg1=="All")

{

currSock=NULL;

return;

}

/*不然就讀取選中的信息,將其拆分為IP地址和端口號(hào).*/

QStringListinfo=arg1.split(':');

QStringip=info[0];

intport=info[1].toInt();

/*遍歷容器,找到對(duì)應(yīng)的那個(gè)socket.*/

foreach(QTcpSocket*sock,sockList)

{

if(sock-peerAddress().toString()==ipsock-peerPort()==port)

{

/*當(dāng)前sock指針指向找到的那個(gè)socket.*/

currSock=sock;

break;

}

}

}

解釋?zhuān)?/p>

這個(gè)槽函數(shù)是帶有參數(shù)的,參數(shù)就是選中選項(xiàng)的字符串。后面的代碼通過(guò)冒號(hào)用來(lái)拆分字符串。比如某個(gè)選項(xiàng)上面的內(nèi)容是:8080,調(diào)用這些代碼后,就會(huì)被拆分成IP地址和端口號(hào)。最后遍歷容器內(nèi)的所有socket,找到IP與端口與選項(xiàng)中一樣的那個(gè)socket。

這個(gè)功能暫時(shí)不太好演示,大家可以自己弄個(gè)按鈕控件,點(diǎn)擊按鈕則打印currSock指向socket的信息,來(lái)檢驗(yàn)一下。

8、實(shí)現(xiàn)發(fā)送功能

到了這一步,程序就開(kāi)始越寫(xiě)越簡(jiǎn)單了

為發(fā)送按鈕添加一個(gè)槽函數(shù):

voidWidget::on_sendbtn_clicked()

/*如果是為開(kāi)啟服務(wù)器、未連接或者選擇All的時(shí)候,currSock才會(huì)指向空

前兩種情況容器是空的,所以也不會(huì)出錯(cuò)。如果是選中All時(shí)候,

且多個(gè)客戶(hù)端連接,則會(huì)遍歷容器中所有的socket,并且一一發(fā)送出去.*/

if(currSock==NULL)

{

foreach(QTcpSocket*sock,sockList)

{

sock-write(ui-sendEdit-toPlainText().toUtf8());

}

}

else

{

/*如果選擇的是一個(gè)特定的客戶(hù)端,則只向它發(fā)送.*/

currSock-write(ui-sendEdit-toPlainText().toUtf8());

}

}

解釋?zhuān)?/p>

當(dāng)currSock指針指向空的時(shí)候,可能有以下幾種狀態(tài):

程序剛剛初始化完成,此時(shí)還沒(méi)有監(jiān)聽(tīng)

程序已經(jīng)開(kāi)始監(jiān)聽(tīng),且有一個(gè)或多個(gè)客戶(hù)端上線(xiàn)

程序開(kāi)始監(jiān)聽(tīng),還沒(méi)有客戶(hù)端連接,或者之前連接的客戶(hù)端全部下線(xiàn)

對(duì)于1、3兩種情況,sockList容器中是空的,因此即使遍歷也遍歷不到任何東西,自然也就不會(huì)給不存在的socket發(fā)送信息。對(duì)于第二種情況,也就不用多解釋了。當(dāng)然,這樣的程序可能是存在問(wèn)題的??梢远嘧鲆恍┡袛?,并且彈出警告提示框,提醒用戶(hù)做了錯(cuò)誤的操作。

最后,演示一下。服務(wù)器先給1號(hào)客戶(hù)端發(fā)送你好1,接著分別給2、3號(hào)客戶(hù)端發(fā)送你好2、3,最后給所有的客戶(hù)端發(fā)送你好123:

9、實(shí)現(xiàn)客戶(hù)端下線(xiàn)

之前我們?cè)跇?gòu)造函數(shù)中添加了這一句代碼:

connect(socket,QTcpSocket::disconnected,this,Widget::on_disconnect);

把套接字的斷開(kāi)連接信號(hào)連接到了斷開(kāi)連接槽函數(shù),槽函數(shù)內(nèi)容如下:

voidWidget::on_disconnect()

/*找到觸發(fā)信號(hào)的那個(gè)socket對(duì)象.*/

QTcpSocket*sock=qobject_castQTcpSocket*(sender());

/*將斷開(kāi)連接的那個(gè)socket從List容器中移除.*/

sockList.removeOne(sock);

/*將客戶(hù)端信息轉(zhuǎn)化為字符串.*/

QStringinfo=sock-peerAddress().toString()\

+':'+QString::number(sock-peerPort());

/*將斷開(kāi)連接的消息打印到文本框.*/

ui-recvEdit-append(info+"已斷開(kāi)");

/*根據(jù)字符串找到comboBox_2中的對(duì)應(yīng)元素的索引號(hào)*/

intindex=ui-comboBox_2-findText(info);

/*刪除那個(gè)元素.*/

ui-comboBox_2-removeItem(index);

/*將新連接的socket對(duì)象的可以讀取信號(hào)與接收槽函數(shù)斷開(kāi).*/

disconnect(sock,QTcpSocket::readyRead,this,Widget::on_recv);

/*將新連接的socket對(duì)象的斷開(kāi)連接信號(hào)與斷開(kāi)槽函數(shù)斷開(kāi).*/

disconnect(sock,QTcpSocket::disconnected,this,Widget::on_disconnect);

}

解釋?zhuān)?/p>

同樣先找到觸發(fā)信號(hào)的那一個(gè)套接字。使用removeOne成員函數(shù)將它從容器中刪除將對(duì)應(yīng)客戶(hù)端的信息打包成字符串,并且將離線(xiàn)的消息打印到接收文本框?qū)⑾吕斜砜蛑械膶?duì)應(yīng)項(xiàng)也給刪除斷開(kāi)信號(hào)和槽的連接

最后,演示一下客戶(hù)端主動(dòng)下線(xiàn)會(huì)有什么現(xiàn)象:

10、實(shí)現(xiàn)踢人功能

剛才是客戶(hù)端自己下線(xiàn),現(xiàn)在是服務(wù)器主動(dòng)踢人下線(xiàn)。但無(wú)論是哪一種,在斷開(kāi)連接的時(shí)候都會(huì)觸發(fā)QTcpSocket::disconnected信號(hào)

為踢人按鈕添加槽函數(shù):

voidWidget::on_kickbtn_clicked()

/*將全部的客戶(hù)端踢下線(xiàn).*/

if(currSock==NULL)

{

foreach(QTcpSocket*sock,sockList)

{

sock-close();

}

}

else

{

/*將選中的那一個(gè)客戶(hù)端踢下線(xiàn).*/

currSock-close();

}

}

到了這里,我感覺(jué)已經(jīng)沒(méi)有什么好說(shuō)的了,只需知道調(diào)用close()函數(shù)可以斷開(kāi)連接。

這里也不做演示了。

11、實(shí)現(xiàn)關(guān)閉服務(wù)器

關(guān)閉服務(wù)器主要需要做兩件事:

1、停止監(jiān)聽(tīng)I(yíng)P及端口。

2、關(guān)閉所有與客戶(hù)端之間的連接。因?yàn)橥V贡O(jiān)聽(tīng)是不夠的,之前的連接還是存在的,甚至還能繼續(xù)收發(fā)數(shù)據(jù)。

voidWidget::on_closebtn_clicked()

currSock=NULL;

/*關(guān)閉監(jiān)聽(tīng).*/

server-close();

/*將一些控件恢復(fù).*/

ui-closebtn-setDisabled(true);

ui-openbtn-set

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論