又大又粗又猛免费视频久久_国产理论在线播放_久久男人av资源网站免费软件_99国产精品无码

如何使用QT5編寫一個(gè)利用TCP協(xié)議的聊天室 (一)

關(guān)于Tcp協(xié)議的知識(shí)點(diǎn)

TCP協(xié)議是一種基于傳輸層的協(xié)議,具有可靠性,需要連接,工作方式為全雙工,傳輸速度相較于UPD更慢的特點(diǎn),一般用于傳輸大量的數(shù)據(jù),傳輸過程不允許丟包的情況.一般情況下聊天類軟件均采用UDP協(xié)議,此處采用TCP是為了了解TCP的特點(diǎn),以及保證實(shí)驗(yàn)過程不因?yàn)?span id="ucw69k0" class="candidate-entity-word" data-gid="20405195">丟包影響實(shí)驗(yàn)結(jié)果.

實(shí)驗(yàn)思路

我將服務(wù)器端分為三個(gè)部分,每個(gè)部分分別實(shí)現(xiàn)不同的功能.

第一部分:服務(wù)器端的外形設(shè)計(jì),服務(wù)器端應(yīng)有一個(gè)對(duì)話框顯示客戶端的登入登出以及在登入期間所發(fā)送的信息,一個(gè)文本框顯示端口號(hào),一個(gè)按鈕來開啟服務(wù)器

第二部分:服務(wù)器功能,服務(wù)器需要監(jiān)聽一個(gè)固定的端口,當(dāng)有客戶端接入該端口時(shí),創(chuàng)建一個(gè)TCP套接字對(duì)象來為該客戶服務(wù)(以便在服務(wù)端實(shí)現(xiàn)與客戶端的通信),服務(wù)器還需要能存儲(chǔ)每一個(gè)接入的客戶端的信息

第三部分:一個(gè)TCP套接字對(duì)象的功能,該對(duì)象需要能讀取套接字中的數(shù)據(jù),將其傳輸給服務(wù)器,

具體實(shí)現(xiàn)

以下代碼為.cpp中的部分代碼,代碼參考<<Qt5開發(fā)及實(shí)例(第三版)>>,若內(nèi)容有錯(cuò)誤理解希望能提出指正

第一部分:

1 Tcpserver::Tcpserver(QWidget *parent,Qt::WindowFlags f)//構(gòu)造函數(shù) 2 : QDialog(parent,f) 3 { 4 setWindowTitle(tr("TCP Server"));//更改名稱 5 ContentListWidget = new QListWidget;//初始化一個(gè)對(duì)話框,顯示相應(yīng)的信息 6 PortLabel = new QLabel(tr("端口"));初始化一個(gè)標(biāo)簽,讓其顯示相應(yīng)的內(nèi)容 7 PortLineEdit = new QLineEdit;//初始化一個(gè)對(duì)話框顯示固定的端口號(hào) 8 CreateBtn = new QPushButton(tr("create chat room"));//初始化一個(gè)按鈕,讓其顯示相應(yīng)的內(nèi)容 9 mainLayout = new QGridLayout(this);//初始化一個(gè)QGridLayout的布局,并將所有部件塞進(jìn)布局10 mainLayout->addWidget(ContentListWidget,0,0,1,2);11 mainLayout->addWidget(PortLabel,1,0);12 mainLayout->addWidget(PortLineEdit,1,1);13 mainLayout->addWidget(CreateBtn,2,0,1,2);14 port = 8010;//監(jiān)聽8010端口15 PortLineEdit->setText(QString::number(port));//將端口號(hào)顯示16 connect(CreateBtn,SIGNAL(clicked()),this,SLOT(slotCreateServer()));//按下按鈕發(fā)送信號(hào),觸發(fā)槽函數(shù),該槽函數(shù)功能為創(chuàng)建一個(gè)服務(wù)器17 }18 TcpServer::~Tcpserver()//析構(gòu)函數(shù)19 {20 }21 void Tcpserver::slotCreateServer()//槽函數(shù)的實(shí)現(xiàn)22 {23 server = new Server(this,port);//創(chuàng)建一個(gè)Server對(duì)象,并將端口號(hào)傳給該對(duì)象,是其對(duì)該端口進(jìn)行監(jiān)聽24 connect(server,SIGNAL(updateServer(QString,int)),this,SLOT(updateServer(QString,int)));//若server發(fā)送updateServer信號(hào),觸發(fā)tcpserver的槽函數(shù)updateServer25 //使其更新對(duì)話框內(nèi)容26 CreateBtn->setEnabled(false);//創(chuàng)建服務(wù)器之后 無法再點(diǎn)擊該按鈕27 }28 void Tcpserver::updateServer(QString msg,int length)//更新內(nèi)容的槽函數(shù)29 {30 ContentListWidget->addItem(msg.left(length));31 }

第二部分:

1 Server::Server(QObject *parent,int port) : QTcpServer(parent) 2 { 3 listen(QHostAddress::Any,port);//在指定的端口對(duì)任意地址監(jiān)聽 4 } 5 void Server::incomingConnection(qintptr socketDescriptor)//當(dāng)出現(xiàn)一個(gè)新的連接的時(shí)候,TcpServer便會(huì)觸發(fā)incomingConnection()函數(shù),每有一個(gè)新的連接都會(huì)觸發(fā)一次,即都創(chuàng)建一個(gè)新的對(duì)象 6 { 7 TcpClientSocket *tcpClientSocket = new TcpClientSocket(this);//創(chuàng)建一個(gè)新的TcpClientSocket與客戶端通信 8 //出現(xiàn)一個(gè)新連接才會(huì)創(chuàng)建一個(gè) TcpClientSocket 的對(duì)象,如果連接后有數(shù)據(jù)傳入,該對(duì)象將其讀下來 通過updateClient信號(hào)來發(fā)送 9 connect(tcpClientSocket,SIGNAL(updateClients(QString,int)),this,SLOT(updateClients(QString,int)));//連接TcpClientSocket的updateClients信號(hào)10 //當(dāng)有新數(shù)據(jù)傳入后,TcpClientSocket便會(huì)發(fā)出updateClients的信號(hào),此時(shí)觸發(fā)Server中的updateClients的槽函數(shù),將信號(hào)中的msg與length傳入該槽函數(shù)11 connect(tcpClientSocket,SIGNAL(disconnected(int)),this,SLOT(slotDisconnected(int)));//連接TcpClientSocket中的disconnected信號(hào)12 //當(dāng)TcpClientSocket的對(duì)象斷開連接后,發(fā)出disconnected的信號(hào),此時(shí)觸發(fā)Server中的slotDisconnected的槽函數(shù)13 tcpClientSocket->setSocketDescriptor(socketDescriptor);//將新創(chuàng)建的TcpClientSocket的套接字描述符指定為參數(shù)socketDescriptor14 tcpClientSocketList.append(tcpClientSocket);//將tcpClientSocket這個(gè)對(duì)象添加入tcpClientSocketList這個(gè)列表中15 }16 void Server::updateClients(QString msg,int length)17 {18 emit updateServer(msg,length);//發(fā)出updateServer的信號(hào),通知服務(wù)器對(duì)話框更新相應(yīng)的顯示狀態(tài)19 for(int i = 0;i<tcpClientSocketList.count();i )//實(shí)現(xiàn)廣播,即將新發(fā)送到服務(wù)器中的數(shù)據(jù)進(jìn)行廣播,發(fā)送到每一個(gè)連接的對(duì)象,進(jìn)行同步更新對(duì)話框20 {21 QTcpSocket *item = tcpClientSocketList.at(i);//22 if(item->write(msg.toLatin1(),length)!=length)23 {24 continue;25 }26 }27 }28 void Server::slotDisconnected(int descriptor)//從tcpClientSocketList列表中將斷開連接的TcpClientSocket對(duì)象刪除29 {30 for (int i = 0;i<tcpClientSocketList.count();i ) {31 QTcpSocket *item = tcpClientSocketList.at(i);32 if(item->socketDescriptor()==descriptor)33 {34 tcpClientSocketList.removeAt(i);35 return;36 }37 }38 return;39 }

第三部分:

1 TcpClientSocket::TcpClientSocket(QObject *parent) 2 { 3 connect(this,SIGNAL(readyRead()),this,SLOT(dateReceived()));//readyRead()是QIODevice的一個(gè)信號(hào)函數(shù),由QTcpSocket繼承而來,在有數(shù)據(jù)來時(shí)發(fā)出信號(hào) 4 connect(this,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));//disconnected()是QIODevice的一個(gè)信號(hào)函數(shù),由QTcpSocket,斷開連接時(shí)發(fā)出信號(hào) 5 } 6 void TcpClientSocket::dateReceived() 7 { 8 while(bytesAvailable()>0)//當(dāng)有數(shù)據(jù)來時(shí),bytesAvailable()從套接字中檢測所來的數(shù)據(jù),返回等待讀取的傳入字節(jié)數(shù) 9 {10 int length = bytesAvailable();11 char buf[1024];12 read(buf,length);//將套接字中的數(shù)據(jù)讀取到buf中,讀取長度為length13 QString msg = buf;14 emit updateClients(msg,length);//發(fā)出信號(hào)15 }16 }17 void TcpClientSocket::slotDisconnected()18 {19 emit disconnected(this->socketDescriptor());//發(fā)出disconnected信號(hào)20 }

部分代碼詳細(xì)解析

1.監(jiān)聽

監(jiān)聽主要依托l(wèi)isten()函數(shù)實(shí)現(xiàn),listen()函數(shù)由QTcpServer的對(duì)象調(diào)用,接受兩個(gè)參數(shù),第一個(gè)參數(shù)為QHostAddress的枚舉,上文中的QHostAddress::Any為任意地址的意思,包括IPv4IPv6.而第二個(gè)參數(shù)為整型的類型,用來代表端口,listen()函數(shù)返回一個(gè)布爾類型來表示監(jiān)聽是否成功.

2.連接

當(dāng)客戶端連接到端口時(shí)(如何連接將在客戶端實(shí)驗(yàn)在闡述),由于已經(jīng)建立了監(jiān)聽的關(guān)系,我們便可以利用一個(gè)QTcpServer中一個(gè)虛函數(shù)–incomingConnection(),該函數(shù)當(dāng)有服務(wù)器端連入時(shí)便會(huì)觸發(fā),我們可以通過重寫該函數(shù)來完成客戶端接入的信息傳遞,該函數(shù)接受一個(gè)qintstr 類型的參數(shù),該參數(shù)代表了接受連接的本機(jī)套接字描述符,該參數(shù)的作用將在讀取數(shù)據(jù)時(shí)體現(xiàn)

3.讀取數(shù)據(jù)

我們想要接受客戶端發(fā)送的信息,除了監(jiān)聽相應(yīng)的端口,與之建立連接還需要一個(gè)服務(wù)器端的套接字來接受客戶端發(fā)送的數(shù)據(jù),創(chuàng)建一個(gè)套接字我們可以使用QTcpSocket 的對(duì)象來使用一個(gè)setSocketDescriptor()函數(shù),該函數(shù)的作用為初始化套接字,接受一個(gè)qintstr的參數(shù)(就是在在上文中提到的那個(gè))來指明該套接字接受哪個(gè)的數(shù)據(jù),當(dāng)成功創(chuàng)建了一個(gè)套接字時(shí),我們便可以采用readyRead()函數(shù)來發(fā)出信號(hào),該函數(shù)當(dāng)有新的可讀數(shù)據(jù)在套接字時(shí),便可以發(fā)出信號(hào),為之我們建立相應(yīng)的槽函數(shù).在槽函數(shù)中可以使用byteAvailable()函數(shù)來獲取可讀取數(shù)據(jù)的字節(jié)數(shù),而正式讀取數(shù)據(jù)時(shí)使用read()函數(shù)便可以了,read()函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)為讀取數(shù)據(jù)的存儲(chǔ)位置,第二個(gè)參數(shù)為讀取多少數(shù)據(jù),我們可以使用byteAvailable()返回的值來完成全部讀取.

相關(guān)新聞

聯(lián)系我們
聯(lián)系我們
在線咨詢
分享本頁
返回頂部