




版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 醫(yī)療實(shí)驗(yàn)室的智能管理系統(tǒng)設(shè)計(jì)與實(shí)施
- 醫(yī)療AI的倫理審查機(jī)制國(guó)際經(jīng)驗(yàn)與本土實(shí)踐
- 競(jìng)選小組長(zhǎng)發(fā)言稿模版
- Axure RP 互聯(lián)網(wǎng)產(chǎn)品原型設(shè)計(jì)課件 第7章 變量與表達(dá)式
- 以患者為中心用數(shù)字技術(shù)提高醫(yī)院服務(wù)質(zhì)量與患者滿(mǎn)意度
- 大學(xué)生校園生活總結(jié)模版
- 司機(jī)班長(zhǎng)年終總結(jié)工作總結(jié)模版
- 2025年第三季度年應(yīng)急管理工作總結(jié)模版
- 信息安全管理在企業(yè)的核心地位
- 公眾號(hào)委托代理合同范例
- 70歲以上老人考駕照,三力測(cè)試題庫(kù)答案
- 2023年副主任醫(yī)師(副高)-中醫(yī)婦科學(xué)(副高)考試上岸歷年考點(diǎn)真題演練含答案
- 醫(yī)院預(yù)算業(yè)務(wù)流程圖
- ALeader 阿立得 ALD515使用手冊(cè)
- 政教主任國(guó)旗下的講話(huà)稿-講話(huà)稿
- 國(guó)學(xué)文化古典中國(guó)風(fēng)模板
- 傷口評(píng)估與護(hù)理記錄
- 國(guó)民經(jīng)濟(jì)核算司精講GDP核算
- 畢業(yè)論文PLC在機(jī)械手控制系統(tǒng)中的應(yīng)用
- 國(guó)家開(kāi)放大學(xué)《人文英語(yǔ)4》邊學(xué)邊練參考答案
- HY/T 0331-2022綠潮生態(tài)調(diào)查與監(jiān)測(cè)技術(shù)規(guī)范
評(píng)論
0/150
提交評(píng)論