Qt下的Tcp協議練習——客戶端
阿新 • • 發佈:2018-12-20
上一篇文章記錄了本次聊天室專案服務端的實現過程和主要程式碼,本篇文章將記錄客戶端的實現過程和主要程式碼。
至於Tcp的原理,上篇文章已經提到過了,所以在這裡就不多囉嗦了。
還是一樣的套路,上來先初始化控制元件物件和設定佈局,這些都不是重點,可以自己隨意佈局。
//設定視窗標題 setWindowTitle(tr("TCP Client")); //初始化控制元件物件 contentListWidget = new QListWidget; userNameLabel = new QLabel(tr("name:")); userNameLineEdit = new QLineEdit; serverIPLabel = new QLabel(tr("IP:")); serverIPLineEdit = new QLineEdit; portLabel = new QLabel(tr("port:")); portLineEdit = new QLineEdit; enterBtn = new QPushButton(tr("Enter the chat room!")); sendLineEdit = new QLineEdit; sendBtn = new QPushButton(tr("Send!")); mainLayout = new QGridLayout(this); //設定佈局 mainLayout->addWidget(userNameLabel,0,0); mainLayout->addWidget(userNameLineEdit,0,1); mainLayout->addWidget(serverIPLabel,1,0); mainLayout->addWidget(serverIPLineEdit,1,1); mainLayout->addWidget(portLabel,2,0); mainLayout->addWidget(portLineEdit,2,1); mainLayout->addWidget(enterBtn,3,0,1,2); mainLayout->addWidget(contentListWidget,4,0,1,2); mainLayout->addWidget(sendLineEdit,5,0); mainLayout->addWidget(sendBtn,5,1);
至於執行出來的效果呢,就是下面這個樣子,有點醜陋,哈哈。
接下來就是一些關鍵函式的實現了,我會把一些說明寫到程式碼的註釋當中
//記錄當前狀態,true表示已經進入聊天室,false表示不在聊天室中,根據status的值判斷是進入還是離開聊天室 status = false; //指定埠 port = 80; //將埠顯示到控制元件上 portLineEdit->setText(QString::number(port)); //初始化記錄IP地址的物件 serverIP = new QHostAddress(); //將按鈕的點選訊號和想要對應的槽函式連線起來 connect(enterBtn,SIGNAL(clicked(bool)),this,SLOT(slotEnter())); connect(sendBtn,SIGNAL(clicked(bool)),this,SLOT(slotSend())); //將傳送資訊按鈕設定為不可點選狀態 sendBtn->setEnabled(false);
接下來實現兩個槽函式
首先是加入enterBtn對應的加入聊天室的槽函式
這段程式碼有點長,主要還是按照當前是否已經連線到聊天室的兩種情況分別進行處理
slotEnter():
if(!status){//判斷當前狀態,是否已經加入到聊天室中 //獲取控制元件上輸入的IP地址 QString ip = serverIPLineEdit->text(); if(!serverIP->setAddress(ip)){//判斷獲取的IP地址是否能夠正常被解析 //如果不能,則彈出警告 QMessageBox::information(this,tr("error"),tr("ip error!")); return; } if(userNameLineEdit->text()==""){//判斷控制元件中的使用者名稱是否為空 //如果使用者名稱為空,則發出警告 QMessageBox::information(this,tr("error"),tr("userName error!")); return; } //將控制元件中的使用者名稱儲存到之前定義的變數當中 userName = userNameLineEdit->text(); //初始化Tcp套接字,並各個訊號和對應的槽函式連線起來 tcpSocket = new QTcpSocket(this); connect(tcpSocket,SIGNAL(connected()),this,SLOT(slotConnected())); connect(tcpSocket,SIGNAL(disconnected()),this,SLOT(slotDisconnected())); connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived())); //與TCP服務端進行連線,成功的話會發送connected()訊號 tcpSocket->connectToHost(*serverIP,port); //記錄當前連線狀態,記錄為已進入聊天室 status = true; }else{//如果已經連線到了服務端,執行面下的操作 //定義一個變數,用來儲存資訊的長度 int length = 0; //定義一條離開聊天室的資訊,離開聊天室時要傳送這條資訊給服務端 QString msg = userName+tr(":Leave chat Room!"); //通知服務端,我要離開聊天室了,也就是傳送上面那條資訊給服務端 //如果傳送成功,則會返回資訊的長度,通過這種方式來判斷,資訊是否傳送出去了 if((length = tcpSocket->write(msg.toLatin1(),msg.length()))!=msg.length()){ return; } //與服務端斷開連線後,會發出disconnected()訊號 tcpSocket->disconnectFromHost(); //儲存當前狀態,記錄為已經離開聊天室 status = false; }
當要連線服務端的時候傳送connected()訊號,觸發slotConnected()槽函式,下面是槽函式的實現
slotConnected():
//將傳送資訊按鈕設定為可點選狀態
sendBtn->setEnabled(true);
//將加入聊天室按鈕的文字資訊更改為leave
enterBtn->setText(tr("Leave!"));
//傳送訊息給服務端,通知服務端我要加入聊天室了,具體流程跟上面傳送資訊的流程相同,這裡就不重複說明了
int length = 0;
QString msg = userName+tr(":Enter chat Room!");
if((length = tcpSocket->write(msg.toLatin1(),msg.length()))!=msg.length()){
return;
}
當與服務端斷開連線的時候傳送disconnected()訊號,觸發slotDisconnected()槽函式,程式碼如下
slotDisconnected():
//既然已經離開聊天室了,傳送資訊的按鈕當然也就不能點啦
sendBtn->setEnabled(false);
//然後進入聊天室按鈕的資訊也要修改一下
enterBtn->setText(tr("Enter the chat room!"));
當有資料到來時,就會觸發dataReceived()槽函式,從套接字中取出有效資料並顯示出來
dataReceived():
//迴圈條件是等待讀取的位元組數大於0,也就是說還有資料沒有讀出來
while(tcpSocket->bytesAvailable()>0){
QByteArray datagram;
//統一一下長度
datagram.resize(tcpSocket->bytesAvailable());
//開始讀取有效資料
tcpSocket->read(datagram.data(),datagram.size());
//把讀取到的資料轉化為QString型別,方便顯示
QString msg = datagram.data();
//把訊息顯示到控制元件上就ok了
contentListWidget->addItem(msg.left(datagram.size()));
}
最後要實現的是點擊發送訊息按鈕時觸發的槽函式slotSend()
slotSend():
if(sendLineEdit->text()==""){//判斷輸入框中是否輸入了訊息
return;
}
//把你的使用者名稱拼接到訊息前面,讓其他使用者知道是誰傳送的訊息
QString msg = userName+":"+sendLineEdit->text();
//開始向套接字中寫入資料
tcpSocket->write(msg.toLatin1(),msg.length());
//最後,訊息都發送出去了,肯定要把輸入框裡面的文字清空掉啦
sendLineEdit->clear();
就這樣,本次做的練習就結束了,這次練習主要是熟悉Tcp協議連線,斷開連線,讀取訊息,傳送訊息的流程和實現方法。
這次練習之後會進行一段時間的吸收,後續可能會做一個融入更多自己理解的案例,如果有時間的話,哈哈,但是學習的步伐是不會停下來的,希望各位大佬能夠多多指教,多多和我交流。