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)聽服務(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()));
? ? ? ? //開啟定時(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:表示未連接(斷開連接)
? ? ? ? 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ā)送按鈕對(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ù)器斷開連接時(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ù)器斷開連接時(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),則斷開和服務(wù)器連接
? ? ? ? //向服務(wù)器發(fā)送離開聊天室的消息
? ? ? ? QString msg = username + ":離開了聊天室";
? ? ? ? //toUtf8():將QString(unicode)轉(zhuǎn)換QByteArray(utf-8)
? ? ? ? tcpSocket.write(msg.toUtf8());
? ? ? ? //斷開連接
? ? ? ? //斷開后發(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("離開聊天室");//修改連接服務(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)效果:

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
c語(yǔ)言:基于函數(shù)指針的兩個(gè)示例分析
本篇文章是對(duì)c語(yǔ)言中函數(shù)指針的兩個(gè)示例做了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C語(yǔ)言函數(shù)聲明以及函數(shù)原型超詳細(xì)講解示例
這篇文章主要介紹了C語(yǔ)言函數(shù)聲明以及函數(shù)原型超詳細(xì)講解,C語(yǔ)言代碼由上到下依次執(zhí)行,原則上函數(shù)定義要出現(xiàn)在函數(shù)調(diào)用之前,否則就會(huì)報(bào)錯(cuò)。但在實(shí)際開發(fā)中,經(jīng)常會(huì)在函數(shù)定義之前使用它們,這個(gè)時(shí)候就需要提前聲明2023-02-02
記錄一個(gè)C++在條件查詢時(shí)遇到的問(wèn)題(推薦)
這篇文章主要介紹了記錄一個(gè)C++在條件查詢時(shí)遇到的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
詳解C++編程中標(biāo)記語(yǔ)句與復(fù)合語(yǔ)句的寫法
這篇文章主要介紹了C++編程中標(biāo)記語(yǔ)句與復(fù)合語(yǔ)句的寫法,是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2016-01-01
數(shù)據(jù)結(jié)構(gòu)之矩陣行列和相等的實(shí)例
這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu)之矩陣行列和相等的實(shí)例的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家掌握這部分內(nèi)容,需要的朋友可以參考下2017-10-10
Java C++算法題解leetcode1592重新排列單詞間的空格
這篇文章主要為大家介紹了Java C++算法題解leetcode1592重新排列單詞間的空格示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
Mac OS X 10.8 中編譯APUE(Unix環(huán)境高級(jí)編程)的源代碼過(guò)程
這篇文章主要介紹了Mac OS X 10.8 中編譯APUE(Unix環(huán)境高級(jí)編程)的源代碼過(guò)程,對(duì)于用MAC學(xué)習(xí)Unix環(huán)境高級(jí)編程的同學(xué)會(huì)有些作用,需要的朋友可以參考下2014-09-09

