網站首頁 編程語言 正文
本文實例為大家分享了QT實現TCP網絡聊天室的具體代碼,供大家參考,具體內容如下
服務器:
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:
? ? //創建服務器按鈕對應的槽函數
? ? void on_pushButton_clicked();
? ? //響應客戶端連接請求的槽函數
? ? void onNewConnection();
? ? //接收客戶端聊天消息的槽函數
? ? void onReadyRead();
? ? //轉發聊天消息給其它客戶端的槽函數
? ? void sendMessage(const QByteArray&);
? ? //定時器檢查客戶端套接字是否為正常連接狀態的槽函數
? ? void onTimeout(void);
private:
? ? Ui::ServerDialog *ui;
? ? QTcpServer tcpServer;//TCP服務器
? ? quint16 port;//服務器端口,quint16-->unsigned short
? ? QList<QTcpSocket*> tcpClientList;//容器:保存和客戶端通信的套接字
? ? QTimer timer;//定時器,定時檢查容器中和客戶端通信的套接字是否為正常連接狀態
};
#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;
}
//創建服務器按鈕對應的槽函數
void ServerDialog::on_pushButton_clicked()
{
? ? //獲取服務器端口
? ? port = ui->lineEdit->text().toShort();
? ? //設置監聽服務器的IP和端口
? ? //QHostAddress::Any ==> QHostAddress("0.0.0.0");
? ? if(tcpServer.listen(QHostAddress::Any,port)==false){
? ? ? ? qDebug() << "創建服務器失敗";
? ? ? ? return;
? ? }
? ? else{
? ? ? ? qDebug() << "創建服務器成功";
? ? ? ? //當有客戶端向服務器發送連接請求時,發送信號newConnection
? ? ? ? connect(&tcpServer,SIGNAL(newConnection()),
? ? ? ? ? ? ? ? this,SLOT(onNewConnection()));
? ? ? ? //禁用端口輸入和創建服務器按鈕
? ? ? ? ui->lineEdit->setEnabled(false);
? ? ? ? ui->pushButton->setEnabled(false);
? ? ? ? //定時器到時發送信號:timeout
? ? ? ? connect(&timer,SIGNAL(timeout()),this,SLOT(onTimeout()));
? ? ? ? //開啟定時器,每隔3秒檢查一次
? ? ? ? timer.start(3000);
? ? }
}
//響應客戶端連接請求的槽函數
void ServerDialog::onNewConnection()
{
? ? //獲取和客戶端通信的套接字
? ? QTcpSocket* tcpClient = ?tcpServer.nextPendingConnection();
? ? //保存套接字到容器中
? ? tcpClientList.append(tcpClient);
? ? //當客戶端給服務器發送消息時,tcpClient發送信號readyRead
? ? connect(tcpClient,SIGNAL(readyRead()),
? ? ? ? ? ? this,SLOT(onReadyRead()));
}
//接收客戶端聊天消息的槽函數
void ServerDialog::onReadyRead()
{
? ? //遍歷檢查哪個客戶端有消息
? ? for(int i=0;i<tcpClientList.size();i++){
? ? ? ? //at(i):獲取容器中第i套接字(QTcpSocket*)
? ? ? ? //bytesAvailable:獲取當前套接字等待讀取消息的字節數,如果為0表示沒有消息,如果
? ? ? ? //大于0說明有消息.
? ? ? ? if(tcpClientList.at(i)->bytesAvailable()){
? ? ? ? ? ? //讀取消息并保存
? ? ? ? ? ? QByteArray buf = tcpClientList.at(i)->readAll();
? ? ? ? ? ? //顯示消息
? ? ? ? ? ? ui->listWidget->addItem(buf);
? ? ? ? ? ? //回滾到最底部(最新消息)
? ? ? ? ? ? ui->listWidget->scrollToBottom();
? ? ? ? ? ? //轉發消息給其它客戶端
? ? ? ? ? ? sendMessage(buf);
? ? ? ? }
? ? }
}
//轉發聊天消息給其它客戶端的槽函數
void ServerDialog::sendMessage(const QByteArray& msg)
{
? ? for(int i=0;i<tcpClientList.size();i++){
? ? ? ? tcpClientList.at(i)->write(msg);
? ? }
}
//定時器檢查客戶端套接字是否為正常連接狀態的槽函數
void ServerDialog::onTimeout(void)
{
? ? for(int i=0;i<tcpClientList.size();i++){
? ? ? ? //state():獲取第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:
? ? //發送按鈕對應的槽函數
? ? void on_sendButton_clicked();
? ? //連接服務器按鈕對應的槽函數
? ? void on_connectButton_clicked();
? ? //和服務器連接成功時執行的槽函數
? ? void onConnected(void);
? ? //和服務器斷開連接時執行的槽函數
? ? void onDisconnected(void);
? ? //接收服務器轉發聊天消息的槽函數
? ? void onReadyRead(void);
? ? //網絡通信異常時執行的槽函數
? ? void onError(void);
private:
? ? Ui::ClientDialog *ui;
? ? bool status;//客戶端狀態標記,true:在線,false:離線狀態
? ? 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發送信號:connected
? ? connect(&tcpSocket,SIGNAL(connected()),
? ? ? ? ? ? this,SLOT(onConnected()));
? ? //和服務器斷開連接時,tcpSocket發送信號:disconnected
? ? connect(&tcpSocket,SIGNAL(disconnected()),
? ? ? ? ? ? this,SLOT(onDisconnected()));
? ? //收到聊天消息時,tcpSocket發送信號:readyRead
? ? connect(&tcpSocket,SIGNAL(readyRead()),
? ? ? ? ? ? this,SLOT(onReadyRead()));
? ? //網絡通信異常時,tcpSocket發送信號:error
? ? connect(&tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),
? ? ? ? ? ? this,SLOT(onError()));
}
ClientDialog::~ClientDialog()
{
? ? delete ui;
}
//發送按鈕對應的槽函數
void ClientDialog::on_sendButton_clicked()
{
? ? //獲取用戶輸入的消息
? ? QString msg = ui->messageEdit->text();
? ? if(msg == ""){
? ? ? ? return;
? ? }
? ? msg = username + ":" + msg;
? ? //發送消息
? ? tcpSocket.write(msg.toUtf8());
? ? //清空已輸入的消息
? ? ui->messageEdit->clear();
}
//連接服務器按鈕對應的槽函數
void ClientDialog::on_connectButton_clicked()
{
? ? if(status == false){//如果當前是離線狀態,則連接服務器
? ? ? ? //獲取服務器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;
? ? ? ? }
? ? ? ? //向服務器發送連接請求:
? ? ? ? //如果成功,發送信號:connected;
? ? ? ? //如果失敗,發送信號:error
? ? ? ? tcpSocket.connectToHost(serverIp,serverPort);
? ? }
? ? else{//如果當前是在線狀態,則斷開和服務器連接
? ? ? ? //向服務器發送離開聊天室的消息
? ? ? ? QString msg = username + ":離開了聊天室";
? ? ? ? //toUtf8():將QString(unicode)轉換QByteArray(utf-8)
? ? ? ? tcpSocket.write(msg.toUtf8());
? ? ? ? //斷開連接
? ? ? ? //斷開后發送信號:disconnected
? ? ? ? tcpSocket.disconnectFromHost();
? ? }
}
//和服務器連接成功時執行的槽函數
void ClientDialog::onConnected(void)
{
? ? status = true;//設置狀態標記:在線
? ? ui->sendButton->setEnabled(true);//恢復"發送"按鈕為正常可用狀態
? ? ui->serverIpEdit->setEnabled(false);//禁用ip輸入
? ? ui->serverportEdit->setEnabled(false);//禁用端口輸入
? ? ui->usernameEdit->setEnabled(false);//禁用昵稱輸入
? ? ui->connectButton->setText("離開聊天室");//修改連接服務器按鈕文本
? ? //向服務器發送進入聊天室提示消息
? ? QString msg = username + ":進入了聊天室";
? ? //toUtf8():將QString(unicode)轉換QByteArray(utf-8)
? ? tcpSocket.write(msg.toUtf8());
}
//和服務器斷開連接時執行的槽函數
void ClientDialog::onDisconnected(void)
{
? ? status = false;//設置離線狀態
? ? ui->sendButton->setEnabled(false);//禁用"發送"按鈕
? ? ui->serverIpEdit->setEnabled(true);//恢復ip輸入
? ? ui->serverportEdit->setEnabled(true);//恢復端口輸入
? ? ui->usernameEdit->setEnabled(true);//恢復昵稱輸入
? ? ui->connectButton->setText("連接服務器");//修改離開聊天室按鈕文本
}
//接收服務器轉發聊天消息的槽函數
void ClientDialog::onReadyRead(void)
{
? ? //bytesAvailable():獲取等待讀取消息的字節數
? ? if(tcpSocket.bytesAvailable()){
? ? ? ? //讀取消息
? ? ? ? QByteArray buf = tcpSocket.readAll();
? ? ? ? //顯示消息到界面
? ? ? ? ui->listWidget->addItem(buf);
? ? ? ? ui->listWidget->scrollToBottom();
? ? }
}
//網絡通信異常時執行的槽函數
void ClientDialog::onError(void)
{
? ? //errorString():獲取網絡通信異常原因的字符串
? ? 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();
}
最終實現效果:
原文鏈接:https://blog.csdn.net/weixin_44264668/article/details/118879694
相關推薦
- 2023-03-28 Golang使用gzip壓縮字符減少redis等存儲占用的實現_Golang
- 2022-08-26 Python?Opencv中基礎的知識點_python
- 2022-10-20 Kotlin作用域函數應用詳細介紹_Android
- 2022-03-24 C語言make和Makefile介紹及使用_C 語言
- 2022-09-08 Go語言中并發的工作原理_Golang
- 2022-09-03 Python實現求解最大公約數的五種方法總結_python
- 2022-04-20 Python設計模式行為型責任鏈模式_python
- 2022-08-02 Android自定義Dialog的方法實例_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支