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ù)器按鈕對(duì)應(yīng)的槽函數(shù)
? ? void on_pushButton_clicked();
? ? //響應(yīng)客戶端連接請(qǐ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_Hserverdialog.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ù)器按鈕對(duì)應(yīng)的槽函數(shù)
void ServerDialog::on_pushButton_clicked()
{
? ? //獲取服務(wù)器端口
? ? port = ui->lineEdit->text().toShort();
? ? //設(shè)置監(jiān)聽(tīng)服務(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ā)送連接請(qǐng)求時(shí),發(fā)送信號(hào)newConnection
? ? ? ? connect(&tcpServer,SIGNAL(newConnection()),
? ? ? ? ? ? ? ? this,SLOT(onNewConnection()));
? ? ? ? //禁用端口輸入和創(chuàng)建服務(wù)器按鈕
? ? ? ? ui->lineEdit->setEnabled(false);
? ? ? ? ui->pushButton->setEnabled(false);
? ? ? ? //定時(shí)器到時(shí)發(fā)送信號(hào):timeout
? ? ? ? connect(&timer,SIGNAL(timeout()),this,SLOT(onTimeout()));
? ? ? ? //開(kāi)啟定時(shí)器,每隔3秒檢查一次
? ? ? ? timer.start(3000);
? ? }
}
//響應(yīng)客戶端連接請(qǐng)求的槽函數(shù)
void ServerDialog::onNewConnection()
{
? ? //獲取和客戶端通信的套接字
? ? QTcpSocket* tcpClient = ?tcpServer.nextPendingConnection();
? ? //保存套接字到容器中
? ? tcpClientList.append(tcpClient);
? ? //當(dāng)客戶端給服務(wù)器發(fā)送消息時(shí),tcpClient發(fā)送信號(hào)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表示沒(méi)有消息,如果
? ? ? ? //大于0說(shuō)明有消息.
? ? ? ? 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:表示未連接(斷開(kāi)連接)
? ? ? ? if(tcpClientList.at(i)->state() ==
? ? ? ? ? ? ? ? QAbstractSocket::UnconnectedState){
? ? ? ? ? ? //從容器中將斷開(kāi)連接的套接字移除
? ? ? ? ? ? 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ā)送按鈕對(duì)應(yīng)的槽函數(shù)
? ? void on_sendButton_clicked();
? ? //連接服務(wù)器按鈕對(duì)應(yīng)的槽函數(shù)
? ? void on_connectButton_clicked();
? ? //和服務(wù)器連接成功時(shí)執(zhí)行的槽函數(shù)
? ? void onConnected(void);
? ? //和服務(wù)器斷開(kāi)連接時(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_Hclientdialog.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ā)送信號(hào):connected
? ? connect(&tcpSocket,SIGNAL(connected()),
? ? ? ? ? ? this,SLOT(onConnected()));
? ? //和服務(wù)器斷開(kāi)連接時(shí),tcpSocket發(fā)送信號(hào):disconnected
? ? connect(&tcpSocket,SIGNAL(disconnected()),
? ? ? ? ? ? this,SLOT(onDisconnected()));
? ? //收到聊天消息時(shí),tcpSocket發(fā)送信號(hào):readyRead
? ? connect(&tcpSocket,SIGNAL(readyRead()),
? ? ? ? ? ? this,SLOT(onReadyRead()));
? ? //網(wǎng)絡(luò)通信異常時(shí),tcpSocket發(fā)送信號(hào):error
? ? connect(&tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),
? ? ? ? ? ? this,SLOT(onError()));
}
ClientDialog::~ClientDialog()
{
? ? delete ui;
}
//發(fā)送按鈕對(duì)應(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ù)器按鈕對(duì)應(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ā)送連接請(qǐng)求:
? ? ? ? //如果成功,發(fā)送信號(hào):connected;
? ? ? ? //如果失敗,發(fā)送信號(hào):error
? ? ? ? tcpSocket.connectToHost(serverIp,serverPort);
? ? }
? ? else{//如果當(dāng)前是在線狀態(tài),則斷開(kāi)和服務(wù)器連接
? ? ? ? //向服務(wù)器發(fā)送離開(kāi)聊天室的消息
? ? ? ? QString msg = username + ":離開(kāi)了聊天室";
? ? ? ? //toUtf8():將QString(unicode)轉(zhuǎn)換QByteArray(utf-8)
? ? ? ? tcpSocket.write(msg.toUtf8());
? ? ? ? //斷開(kāi)連接
? ? ? ? //斷開(kāi)后發(fā)送信號(hào):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("離開(kāi)聊天室");//修改連接服務(wù)器按鈕文本
? ? //向服務(wù)器發(fā)送進(jìn)入聊天室提示消息
? ? QString msg = username + ":進(jìn)入了聊天室";
? ? //toUtf8():將QString(unicode)轉(zhuǎn)換QByteArray(utf-8)
? ? tcpSocket.write(msg.toUtf8());
}
//和服務(wù)器斷開(kāi)連接時(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ù)器");//修改離開(kāi)聊天室按鈕文本
}
//接收服務(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)效果:

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Assert(斷言實(shí)現(xiàn)機(jī)制深入剖析)
言前后最好空一格[編程風(fēng)格的問(wèn)題,按你自已的喜好,適合自已就最好]。斷言只是用來(lái)檢查程序的邏輯正確性,不能代替條件替換。斷言比printf語(yǔ)句這種形式的打印好使2013-09-09
Qt中簡(jiǎn)單的按鈕槽函數(shù)傳遞參數(shù)方法
這篇文章主要介紹了Qt中簡(jiǎn)單的按鈕槽函數(shù)傳遞參數(shù)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
C++類成員構(gòu)造函數(shù)和析構(gòu)函數(shù)順序示例詳細(xì)講解
這篇文章主要介紹了C++類成員構(gòu)造和析構(gòu)順序示例,看了這個(gè)例子大家就可以明白c++構(gòu)造析構(gòu)的奧秘2013-11-11
C++文件關(guān)鍵詞快速定位出現(xiàn)的行號(hào)實(shí)現(xiàn)高效搜索
這篇文章主要為大家介紹了C++文件關(guān)鍵詞快速定位出現(xiàn)的行號(hào)實(shí)現(xiàn)高效搜索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
C語(yǔ)言實(shí)現(xiàn)賓館管理系統(tǒng)課程設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)賓館管理系統(tǒng)課程設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03

