QT實現(xiàn)TCP網(wǎng)絡聊天室
更新時間:2022年08月19日 15:47:19 作者:Soaring丶
這篇文章主要為大家詳細介紹了QT實現(xiàn)TCP網(wǎng)絡聊天室,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
本文實例為大家分享了QT實現(xiàn)TCP網(wǎng)絡聊天室的具體代碼,供大家參考,具體內(nèi)容如下
服務器:
serverdialog.h
#ifndef SERVERDIALOG_H #define SERVERDIALOG_H #include <QDialog> #include <QTcpServer> #include <QTcpSocket> #include <QDebug> #include <QTimer> namespace Ui { class ServerDialog; } class ServerDialog : public QDialog { ? ? Q_OBJECT public: ? ? explicit ServerDialog(QWidget *parent = 0); ? ? ~ServerDialog(); private slots: ? ? //創(chuàng)建服務器按鈕對應的槽函數(shù) ? ? void on_pushButton_clicked(); ? ? //響應客戶端連接請求的槽函數(shù) ? ? void onNewConnection(); ? ? //接收客戶端聊天消息的槽函數(shù) ? ? void onReadyRead(); ? ? //轉(zhuǎn)發(fā)聊天消息給其它客戶端的槽函數(shù) ? ? void sendMessage(const QByteArray&); ? ? //定時器檢查客戶端套接字是否為正常連接狀態(tài)的槽函數(shù) ? ? void onTimeout(void); private: ? ? Ui::ServerDialog *ui; ? ? QTcpServer tcpServer;//TCP服務器 ? ? quint16 port;//服務器端口,quint16-->unsigned short ? ? QList<QTcpSocket*> tcpClientList;//容器:保存和客戶端通信的套接字 ? ? QTimer timer;//定時器,定時檢查容器中和客戶端通信的套接字是否為正常連接狀態(tài) }; #endif // SERVERDIALOG_H
serverdialog.cpp
#include "serverdialog.h" #include "ui_serverdialog.h" ServerDialog::ServerDialog(QWidget *parent) : ? ? QDialog(parent), ? ? ui(new Ui::ServerDialog) { ? ? ui->setupUi(this); } ServerDialog::~ServerDialog() { ? ? delete ui; } //創(chuàng)建服務器按鈕對應的槽函數(shù) void ServerDialog::on_pushButton_clicked() { ? ? //獲取服務器端口 ? ? port = ui->lineEdit->text().toShort(); ? ? //設置監(jiān)聽服務器的IP和端口 ? ? //QHostAddress::Any ==> QHostAddress("0.0.0.0"); ? ? if(tcpServer.listen(QHostAddress::Any,port)==false){ ? ? ? ? qDebug() << "創(chuàng)建服務器失敗"; ? ? ? ? return; ? ? } ? ? else{ ? ? ? ? qDebug() << "創(chuàng)建服務器成功"; ? ? ? ? //當有客戶端向服務器發(fā)送連接請求時,發(fā)送信號newConnection ? ? ? ? connect(&tcpServer,SIGNAL(newConnection()), ? ? ? ? ? ? ? ? this,SLOT(onNewConnection())); ? ? ? ? //禁用端口輸入和創(chuàng)建服務器按鈕 ? ? ? ? ui->lineEdit->setEnabled(false); ? ? ? ? ui->pushButton->setEnabled(false); ? ? ? ? //定時器到時發(fā)送信號:timeout ? ? ? ? connect(&timer,SIGNAL(timeout()),this,SLOT(onTimeout())); ? ? ? ? //開啟定時器,每隔3秒檢查一次 ? ? ? ? timer.start(3000); ? ? } } //響應客戶端連接請求的槽函數(shù) void ServerDialog::onNewConnection() { ? ? //獲取和客戶端通信的套接字 ? ? QTcpSocket* tcpClient = ?tcpServer.nextPendingConnection(); ? ? //保存套接字到容器中 ? ? tcpClientList.append(tcpClient); ? ? //當客戶端給服務器發(fā)送消息時,tcpClient發(fā)送信號readyRead ? ? connect(tcpClient,SIGNAL(readyRead()), ? ? ? ? ? ? this,SLOT(onReadyRead())); } //接收客戶端聊天消息的槽函數(shù) void ServerDialog::onReadyRead() { ? ? //遍歷檢查哪個客戶端有消息 ? ? for(int i=0;i<tcpClientList.size();i++){ ? ? ? ? //at(i):獲取容器中第i套接字(QTcpSocket*) ? ? ? ? //bytesAvailable:獲取當前套接字等待讀取消息的字節(jié)數(shù),如果為0表示沒有消息,如果 ? ? ? ? //大于0說明有消息. ? ? ? ? if(tcpClientList.at(i)->bytesAvailable()){ ? ? ? ? ? ? //讀取消息并保存 ? ? ? ? ? ? QByteArray buf = tcpClientList.at(i)->readAll(); ? ? ? ? ? ? //顯示消息 ? ? ? ? ? ? ui->listWidget->addItem(buf); ? ? ? ? ? ? //回滾到最底部(最新消息) ? ? ? ? ? ? ui->listWidget->scrollToBottom(); ? ? ? ? ? ? //轉(zhuǎn)發(fā)消息給其它客戶端 ? ? ? ? ? ? sendMessage(buf); ? ? ? ? } ? ? } } //轉(zhuǎn)發(fā)聊天消息給其它客戶端的槽函數(shù) void ServerDialog::sendMessage(const QByteArray& msg) { ? ? for(int i=0;i<tcpClientList.size();i++){ ? ? ? ? tcpClientList.at(i)->write(msg); ? ? } } //定時器檢查客戶端套接字是否為正常連接狀態(tài)的槽函數(shù) void ServerDialog::onTimeout(void) { ? ? for(int i=0;i<tcpClientList.size();i++){ ? ? ? ? //state():獲取第i個套接字的連接狀態(tài) ? ? ? ? //UnconnectedState:表示未連接(斷開連接) ? ? ? ? if(tcpClientList.at(i)->state() == ? ? ? ? ? ? ? ? QAbstractSocket::UnconnectedState){ ? ? ? ? ? ? //從容器中將斷開連接的套接字移除 ? ? ? ? ? ? tcpClientList.removeAt(i); ? ? ? ? ? ? --i; ? ? ? ? } ? ? } }
main.cpp
#include "serverdialog.h" #include <QApplication> int main(int argc, char *argv[]) { ? ? QApplication a(argc, argv); ? ? ServerDialog w; ? ? w.show(); ? ? return a.exec(); }
客戶端:
clientdialog:
#ifndef CLIENTDIALOG_H #define CLIENTDIALOG_H #include <QDialog> //QT += network #include <QTcpSocket> #include <QHostAddress> #include <QMessageBox> namespace Ui { class ClientDialog; } class ClientDialog : public QDialog { ? ? Q_OBJECT public: ? ? explicit ClientDialog(QWidget *parent = 0); ? ? ~ClientDialog(); private slots: ? ? //發(fā)送按鈕對應的槽函數(shù) ? ? void on_sendButton_clicked(); ? ? //連接服務器按鈕對應的槽函數(shù) ? ? void on_connectButton_clicked(); ? ? //和服務器連接成功時執(zhí)行的槽函數(shù) ? ? void onConnected(void); ? ? //和服務器斷開連接時執(zhí)行的槽函數(shù) ? ? void onDisconnected(void); ? ? //接收服務器轉(zhuǎn)發(fā)聊天消息的槽函數(shù) ? ? void onReadyRead(void); ? ? //網(wǎng)絡通信異常時執(zhí)行的槽函數(shù) ? ? void onError(void); private: ? ? Ui::ClientDialog *ui; ? ? bool status;//客戶端狀態(tài)標記,true:在線,false:離線狀態(tài) ? ? QTcpSocket tcpSocket;//和服務器通信的tcp套接字 ? ? QHostAddress serverIp;//服務器地址 ? ? quint16 serverPort;//服務器端口 ? ? QString username;//聊天室昵稱 }; #endif // CLIENTDIALOG_H
clientdialog.cpp
#include "clientdialog.h" #include "ui_clientdialog.h" ClientDialog::ClientDialog(QWidget *parent) : ? ? QDialog(parent), ? ? ui(new Ui::ClientDialog) { ? ? ui->setupUi(this); ? ? status = false; ? ? //和服務器連接成功時,tcpSocket發(fā)送信號:connected ? ? connect(&tcpSocket,SIGNAL(connected()), ? ? ? ? ? ? this,SLOT(onConnected())); ? ? //和服務器斷開連接時,tcpSocket發(fā)送信號:disconnected ? ? connect(&tcpSocket,SIGNAL(disconnected()), ? ? ? ? ? ? this,SLOT(onDisconnected())); ? ? //收到聊天消息時,tcpSocket發(fā)送信號:readyRead ? ? connect(&tcpSocket,SIGNAL(readyRead()), ? ? ? ? ? ? this,SLOT(onReadyRead())); ? ? //網(wǎng)絡通信異常時,tcpSocket發(fā)送信號:error ? ? connect(&tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)), ? ? ? ? ? ? this,SLOT(onError())); } ClientDialog::~ClientDialog() { ? ? delete ui; } //發(fā)送按鈕對應的槽函數(shù) void ClientDialog::on_sendButton_clicked() { ? ? //獲取用戶輸入的消息 ? ? QString msg = ui->messageEdit->text(); ? ? if(msg == ""){ ? ? ? ? return; ? ? } ? ? msg = username + ":" + msg; ? ? //發(fā)送消息 ? ? tcpSocket.write(msg.toUtf8()); ? ? //清空已輸入的消息 ? ? ui->messageEdit->clear(); } //連接服務器按鈕對應的槽函數(shù) void ClientDialog::on_connectButton_clicked() { ? ? if(status == false){//如果當前是離線狀態(tài),則連接服務器 ? ? ? ? //獲取服務器IP ? ? ? ? if(serverIp.setAddress(ui->serverIpEdit->text())==false){ ? ? ? ? ? ? //critical():表示錯誤的消息提示框 ? ? ? ? ? ? QMessageBox::critical(this,"Error","IP地址錯誤"); ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? //獲取服務器端口 ? ? ? ? serverPort = ui->serverportEdit->text().toShort(); ? ? ? ? if(serverPort < 1024){ ? ? ? ? ? ? QMessageBox::critical(this,"Error","端口格式錯誤"); ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? //獲取聊天室昵稱 ? ? ? ? username = ui->usernameEdit->text(); ? ? ? ? if(username == ""){ ? ? ? ? ? ? QMessageBox::critical(this,"Error","聊天室昵稱不能為空"); ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? //向服務器發(fā)送連接請求: ? ? ? ? //如果成功,發(fā)送信號:connected; ? ? ? ? //如果失敗,發(fā)送信號:error ? ? ? ? tcpSocket.connectToHost(serverIp,serverPort); ? ? } ? ? else{//如果當前是在線狀態(tài),則斷開和服務器連接 ? ? ? ? //向服務器發(fā)送離開聊天室的消息 ? ? ? ? QString msg = username + ":離開了聊天室"; ? ? ? ? //toUtf8():將QString(unicode)轉(zhuǎn)換QByteArray(utf-8) ? ? ? ? tcpSocket.write(msg.toUtf8()); ? ? ? ? //斷開連接 ? ? ? ? //斷開后發(fā)送信號:disconnected ? ? ? ? tcpSocket.disconnectFromHost(); ? ? } } //和服務器連接成功時執(zhí)行的槽函數(shù) void ClientDialog::onConnected(void) { ? ? status = true;//設置狀態(tài)標記:在線 ? ? ui->sendButton->setEnabled(true);//恢復"發(fā)送"按鈕為正??捎脿顟B(tài) ? ? ui->serverIpEdit->setEnabled(false);//禁用ip輸入 ? ? ui->serverportEdit->setEnabled(false);//禁用端口輸入 ? ? ui->usernameEdit->setEnabled(false);//禁用昵稱輸入 ? ? ui->connectButton->setText("離開聊天室");//修改連接服務器按鈕文本 ? ? //向服務器發(fā)送進入聊天室提示消息 ? ? QString msg = username + ":進入了聊天室"; ? ? //toUtf8():將QString(unicode)轉(zhuǎn)換QByteArray(utf-8) ? ? tcpSocket.write(msg.toUtf8()); } //和服務器斷開連接時執(zhí)行的槽函數(shù) void ClientDialog::onDisconnected(void) { ? ? status = false;//設置離線狀態(tài) ? ? ui->sendButton->setEnabled(false);//禁用"發(fā)送"按鈕 ? ? ui->serverIpEdit->setEnabled(true);//恢復ip輸入 ? ? ui->serverportEdit->setEnabled(true);//恢復端口輸入 ? ? ui->usernameEdit->setEnabled(true);//恢復昵稱輸入 ? ? ui->connectButton->setText("連接服務器");//修改離開聊天室按鈕文本 } //接收服務器轉(zhuǎn)發(fā)聊天消息的槽函數(shù) void ClientDialog::onReadyRead(void) { ? ? //bytesAvailable():獲取等待讀取消息的字節(jié)數(shù) ? ? if(tcpSocket.bytesAvailable()){ ? ? ? ? //讀取消息 ? ? ? ? QByteArray buf = tcpSocket.readAll(); ? ? ? ? //顯示消息到界面 ? ? ? ? ui->listWidget->addItem(buf); ? ? ? ? ui->listWidget->scrollToBottom(); ? ? } } //網(wǎng)絡通信異常時執(zhí)行的槽函數(shù) void ClientDialog::onError(void) { ? ? //errorString():獲取網(wǎng)絡通信異常原因的字符串 ? ? QMessageBox::critical(this,"Error",tcpSocket.errorString()); }
main.cpp
#include "clientdialog.h" #include <QApplication> int main(int argc, char *argv[]) { ? ? QApplication a(argc, argv); ? ? ClientDialog w; ? ? w.show(); ? ? return a.exec(); }
最終實現(xiàn)效果:
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
C++類成員構(gòu)造函數(shù)和析構(gòu)函數(shù)順序示例詳細講解
這篇文章主要介紹了C++類成員構(gòu)造和析構(gòu)順序示例,看了這個例子大家就可以明白c++構(gòu)造析構(gòu)的奧秘2013-11-11C++文件關鍵詞快速定位出現(xiàn)的行號實現(xiàn)高效搜索
這篇文章主要為大家介紹了C++文件關鍵詞快速定位出現(xiàn)的行號實現(xiàn)高效搜索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-10-10