QT實(shí)現(xiàn)TCP網(wǎng)絡(luò)聊天室
本文實(shí)例為大家分享了QT實(shí)現(xiàn)TCP網(wǎng)絡(luò)聊天室的具體代碼,供大家參考,具體內(nèi)容如下
服務(wù)器:
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)建服務(wù)器按鈕對應(yīng)的槽函數(shù) ? ? void on_pushButton_clicked(); ? ? //響應(yīng)客戶端連接請求的槽函數(shù) ? ? void onNewConnection(); ? ? //接收客戶端聊天消息的槽函數(shù) ? ? void onReadyRead(); ? ? //轉(zhuǎn)發(fā)聊天消息給其它客戶端的槽函數(shù) ? ? void sendMessage(const QByteArray&); ? ? //定時(shí)器檢查客戶端套接字是否為正常連接狀態(tài)的槽函數(shù) ? ? void onTimeout(void); private: ? ? Ui::ServerDialog *ui; ? ? QTcpServer tcpServer;//TCP服務(wù)器 ? ? quint16 port;//服務(wù)器端口,quint16-->unsigned short ? ? QList<QTcpSocket*> tcpClientList;//容器:保存和客戶端通信的套接字 ? ? QTimer timer;//定時(shí)器,定時(shí)檢查容器中和客戶端通信的套接字是否為正常連接狀態(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)建服務(wù)器按鈕對應(yīng)的槽函數(shù) void ServerDialog::on_pushButton_clicked() { ? ? //獲取服務(wù)器端口 ? ? port = ui->lineEdit->text().toShort(); ? ? //設(shè)置監(jiān)聽服務(wù)器的IP和端口 ? ? //QHostAddress::Any ==> QHostAddress("0.0.0.0"); ? ? if(tcpServer.listen(QHostAddress::Any,port)==false){ ? ? ? ? qDebug() << "創(chuàng)建服務(wù)器失敗"; ? ? ? ? return; ? ? } ? ? else{ ? ? ? ? qDebug() << "創(chuàng)建服務(wù)器成功"; ? ? ? ? //當(dāng)有客戶端向服務(wù)器發(fā)送連接請求時(shí),發(fā)送信號newConnection ? ? ? ? connect(&tcpServer,SIGNAL(newConnection()), ? ? ? ? ? ? ? ? this,SLOT(onNewConnection())); ? ? ? ? //禁用端口輸入和創(chuàng)建服務(wù)器按鈕 ? ? ? ? ui->lineEdit->setEnabled(false); ? ? ? ? ui->pushButton->setEnabled(false); ? ? ? ? //定時(shí)器到時(shí)發(fā)送信號:timeout ? ? ? ? connect(&timer,SIGNAL(timeout()),this,SLOT(onTimeout())); ? ? ? ? //開啟定時(shí)器,每隔3秒檢查一次 ? ? ? ? timer.start(3000); ? ? } } //響應(yīng)客戶端連接請求的槽函數(shù) void ServerDialog::onNewConnection() { ? ? //獲取和客戶端通信的套接字 ? ? QTcpSocket* tcpClient = ?tcpServer.nextPendingConnection(); ? ? //保存套接字到容器中 ? ? tcpClientList.append(tcpClient); ? ? //當(dāng)客戶端給服務(wù)器發(fā)送消息時(shí),tcpClient發(fā)送信號readyRead ? ? connect(tcpClient,SIGNAL(readyRead()), ? ? ? ? ? ? this,SLOT(onReadyRead())); } //接收客戶端聊天消息的槽函數(shù) void ServerDialog::onReadyRead() { ? ? //遍歷檢查哪個(gè)客戶端有消息 ? ? for(int i=0;i<tcpClientList.size();i++){ ? ? ? ? //at(i):獲取容器中第i套接字(QTcpSocket*) ? ? ? ? //bytesAvailable:獲取當(dāng)前套接字等待讀取消息的字節(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); ? ? } } //定時(shí)器檢查客戶端套接字是否為正常連接狀態(tài)的槽函數(shù) void ServerDialog::onTimeout(void) { ? ? for(int i=0;i<tcpClientList.size();i++){ ? ? ? ? //state():獲取第i個(gè)套接字的連接狀態(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ā)送按鈕對應(yīng)的槽函數(shù) ? ? void on_sendButton_clicked(); ? ? //連接服務(wù)器按鈕對應(yīng)的槽函數(shù) ? ? void on_connectButton_clicked(); ? ? //和服務(wù)器連接成功時(shí)執(zhí)行的槽函數(shù) ? ? void onConnected(void); ? ? //和服務(wù)器斷開連接時(shí)執(zhí)行的槽函數(shù) ? ? void onDisconnected(void); ? ? //接收服務(wù)器轉(zhuǎn)發(fā)聊天消息的槽函數(shù) ? ? void onReadyRead(void); ? ? //網(wǎng)絡(luò)通信異常時(shí)執(zhí)行的槽函數(shù) ? ? void onError(void); private: ? ? Ui::ClientDialog *ui; ? ? bool status;//客戶端狀態(tài)標(biāo)記,true:在線,false:離線狀態(tài) ? ? QTcpSocket tcpSocket;//和服務(wù)器通信的tcp套接字 ? ? QHostAddress serverIp;//服務(wù)器地址 ? ? quint16 serverPort;//服務(wù)器端口 ? ? 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; ? ? //和服務(wù)器連接成功時(shí),tcpSocket發(fā)送信號:connected ? ? connect(&tcpSocket,SIGNAL(connected()), ? ? ? ? ? ? this,SLOT(onConnected())); ? ? //和服務(wù)器斷開連接時(shí),tcpSocket發(fā)送信號:disconnected ? ? connect(&tcpSocket,SIGNAL(disconnected()), ? ? ? ? ? ? this,SLOT(onDisconnected())); ? ? //收到聊天消息時(shí),tcpSocket發(fā)送信號:readyRead ? ? connect(&tcpSocket,SIGNAL(readyRead()), ? ? ? ? ? ? this,SLOT(onReadyRead())); ? ? //網(wǎng)絡(luò)通信異常時(shí),tcpSocket發(fā)送信號:error ? ? connect(&tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)), ? ? ? ? ? ? this,SLOT(onError())); } ClientDialog::~ClientDialog() { ? ? delete ui; } //發(fā)送按鈕對應(yīng)的槽函數(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(); } //連接服務(wù)器按鈕對應(yīng)的槽函數(shù) void ClientDialog::on_connectButton_clicked() { ? ? if(status == false){//如果當(dāng)前是離線狀態(tài),則連接服務(wù)器 ? ? ? ? //獲取服務(wù)器IP ? ? ? ? if(serverIp.setAddress(ui->serverIpEdit->text())==false){ ? ? ? ? ? ? //critical():表示錯(cuò)誤的消息提示框 ? ? ? ? ? ? QMessageBox::critical(this,"Error","IP地址錯(cuò)誤"); ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? //獲取服務(wù)器端口 ? ? ? ? serverPort = ui->serverportEdit->text().toShort(); ? ? ? ? if(serverPort < 1024){ ? ? ? ? ? ? QMessageBox::critical(this,"Error","端口格式錯(cuò)誤"); ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? //獲取聊天室昵稱 ? ? ? ? username = ui->usernameEdit->text(); ? ? ? ? if(username == ""){ ? ? ? ? ? ? QMessageBox::critical(this,"Error","聊天室昵稱不能為空"); ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? //向服務(wù)器發(fā)送連接請求: ? ? ? ? //如果成功,發(fā)送信號:connected; ? ? ? ? //如果失敗,發(fā)送信號:error ? ? ? ? tcpSocket.connectToHost(serverIp,serverPort); ? ? } ? ? else{//如果當(dāng)前是在線狀態(tài),則斷開和服務(wù)器連接 ? ? ? ? //向服務(wù)器發(fā)送離開聊天室的消息 ? ? ? ? QString msg = username + ":離開了聊天室"; ? ? ? ? //toUtf8():將QString(unicode)轉(zhuǎn)換QByteArray(utf-8) ? ? ? ? tcpSocket.write(msg.toUtf8()); ? ? ? ? //斷開連接 ? ? ? ? //斷開后發(fā)送信號:disconnected ? ? ? ? tcpSocket.disconnectFromHost(); ? ? } } //和服務(wù)器連接成功時(shí)執(zhí)行的槽函數(shù) void ClientDialog::onConnected(void) { ? ? status = true;//設(shè)置狀態(tài)標(biāo)記:在線 ? ? ui->sendButton->setEnabled(true);//恢復(fù)"發(fā)送"按鈕為正??捎脿顟B(tài) ? ? ui->serverIpEdit->setEnabled(false);//禁用ip輸入 ? ? ui->serverportEdit->setEnabled(false);//禁用端口輸入 ? ? ui->usernameEdit->setEnabled(false);//禁用昵稱輸入 ? ? ui->connectButton->setText("離開聊天室");//修改連接服務(wù)器按鈕文本 ? ? //向服務(wù)器發(fā)送進(jìn)入聊天室提示消息 ? ? QString msg = username + ":進(jìn)入了聊天室"; ? ? //toUtf8():將QString(unicode)轉(zhuǎn)換QByteArray(utf-8) ? ? tcpSocket.write(msg.toUtf8()); } //和服務(wù)器斷開連接時(shí)執(zhí)行的槽函數(shù) void ClientDialog::onDisconnected(void) { ? ? status = false;//設(shè)置離線狀態(tài) ? ? ui->sendButton->setEnabled(false);//禁用"發(fā)送"按鈕 ? ? ui->serverIpEdit->setEnabled(true);//恢復(fù)ip輸入 ? ? ui->serverportEdit->setEnabled(true);//恢復(fù)端口輸入 ? ? ui->usernameEdit->setEnabled(true);//恢復(fù)昵稱輸入 ? ? ui->connectButton->setText("連接服務(wù)器");//修改離開聊天室按鈕文本 } //接收服務(wù)器轉(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)絡(luò)通信異常時(shí)執(zhí)行的槽函數(shù) void ClientDialog::onError(void) { ? ? //errorString():獲取網(wǎng)絡(luò)通信異常原因的字符串 ? ? 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(); }
最終實(shí)現(xiàn)效果:
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Assert(斷言實(shí)現(xiàn)機(jī)制深入剖析)
言前后最好空一格[編程風(fēng)格的問題,按你自已的喜好,適合自已就最好]。斷言只是用來檢查程序的邏輯正確性,不能代替條件替換。斷言比printf語句這種形式的打印好使2013-09-09C++類成員構(gòu)造函數(shù)和析構(gòu)函數(shù)順序示例詳細(xì)講解
這篇文章主要介紹了C++類成員構(gòu)造和析構(gòu)順序示例,看了這個(gè)例子大家就可以明白c++構(gòu)造析構(gòu)的奧秘2013-11-11C++文件關(guān)鍵詞快速定位出現(xiàn)的行號實(shí)現(xiàn)高效搜索
這篇文章主要為大家介紹了C++文件關(guān)鍵詞快速定位出現(xiàn)的行號實(shí)現(xiàn)高效搜索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10C語言實(shí)現(xiàn)賓館管理系統(tǒng)課程設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)賓館管理系統(tǒng)課程設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03