欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Qt實(shí)現(xiàn)網(wǎng)絡(luò)聊天室的示例代碼

 更新時(shí)間:2021年06月23日 11:53:21   作者:進(jìn)擊的汪sir  
本文主要介紹了Qt實(shí)現(xiàn)網(wǎng)絡(luò)聊天室,實(shí)現(xiàn)一個(gè)在線聊天室, 使用tcp對(duì)客戶端和服務(wù)器端進(jìn)行通訊。具有一定的參考價(jià)值,具有一定的參考價(jià)值,

1. 效果演示

客戶端

服務(wù)器

連接成功之后

2. 預(yù)備知識(shí)

在Qt中,實(shí)現(xiàn)網(wǎng)絡(luò)編程的方式比用C++或C實(shí)現(xiàn)要方便簡(jiǎn)單許多,因?yàn)镼t已經(jīng)替我們封裝好了,我們會(huì)使用就可以了,然后大家還需要了解Qt 的信號(hào)槽機(jī)制,可以參考我這篇文章,Qt信號(hào)槽

2.1 QTcpServer

QTcpServer 類用于監(jiān)聽客戶端連接以及和客戶端建立連接,在使用之前先介紹一下這個(gè)類提供的一些常用 API 函數(shù):

構(gòu)造函數(shù)

QTcpServer::QTcpServer(QObject *parent = Q_NULLPTR);

給監(jiān)聽的套接字設(shè)置監(jiān)聽

bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
// 判斷當(dāng)前對(duì)象是否在監(jiān)聽, 是返回true,沒有監(jiān)聽返回false
bool QTcpServer::isListening() const;
// 如果當(dāng)前對(duì)象正在監(jiān)聽返回監(jiān)聽的服務(wù)器地址信息, 否則返回 QHostAddress::Null
QHostAddress QTcpServer::serverAddress() const;
// 如果服務(wù)器正在監(jiān)聽連接,則返回服務(wù)器的端口; 否則返回0
quint16 QTcpServer::serverPort() const

參數(shù):
address:通過類 QHostAddress 可以封裝 IPv4、IPv6 格式的 IP 地址,QHostAddress::Any 表示自動(dòng)綁定
port:如果指定為 0 表示隨機(jī)綁定一個(gè)可用端口。
返回值:綁定成功返回 true,失敗返回 false

得到和客戶端建立連接之后用于通信的 QTcpSocket 套接字對(duì)象,它是 QTcpServer 的一個(gè)子對(duì)象,當(dāng) QTcpServer 對(duì)象析構(gòu)的時(shí)候會(huì)自動(dòng)析構(gòu)這個(gè)子對(duì)象,當(dāng)然也可自己手動(dòng)析構(gòu),建議用完之后自己手動(dòng)析構(gòu)這個(gè)通信的 QTcpSocket 對(duì)象。

QTcpSocket *QTcpServer::nextPendingConnection();

阻塞等待客戶端發(fā)起的連接請(qǐng)求,不推薦在單線程程序中使用,建議使用非阻塞方式處理新連接,即使用信號(hào) newConnection() 。

bool QTcpServer::waitForNewConnection(int msec = 0, bool *timedOut = Q_NULLPTR);

參數(shù):
msec:指定阻塞的最大時(shí)長(zhǎng),單位為毫秒(ms)
timeout:傳出參數(shù),如果操作超時(shí) timeout 為 true,沒有超時(shí) timeout 為 false

2.2 QTcpServer信號(hào)

當(dāng)接受新連接導(dǎo)致錯(cuò)誤時(shí),將發(fā)射如下信號(hào)。socketError 參數(shù)描述了發(fā)生的錯(cuò)誤相關(guān)的信息

[signal] void QTcpServer::acceptError(QAbstractSocket::SocketError socketError);

每次有新連接可用時(shí)都會(huì)發(fā)出 newConnection () 信號(hào)。

[signal] void QTcpServer::newConnection();

2.3 QTcpSocket

QTcpSocket 是一個(gè)套接字通信類,不管是客戶端還是服務(wù)器端都需要使用。在 Qt 中發(fā)送和接收數(shù)據(jù)也屬于 IO 操作(網(wǎng)絡(luò) IO)

構(gòu)造函數(shù)

QTcpSocket::QTcpSocket(QObject *parent = Q_NULLPTR);

連接服務(wù)器,需要指定服務(wù)器端綁定的IP和端口信息。

[virtual] void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);

[virtual] void QAbstractSocket::connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode = ReadWrite);

在 Qt 中不管調(diào)用讀操作函數(shù)接收數(shù)據(jù),還是調(diào)用寫函數(shù)發(fā)送數(shù)據(jù),操作的對(duì)象都是本地的由 Qt 框架維護(hù)的一塊內(nèi)存。因此,調(diào)用了發(fā)送函數(shù)數(shù)據(jù)不一定會(huì)馬上被發(fā)送到網(wǎng)絡(luò)中,調(diào)用了接收函數(shù)也不是直接從網(wǎng)絡(luò)中接收數(shù)據(jù),關(guān)于底層的相關(guān)操作是不需要使用者來維護(hù)的。

接收數(shù)據(jù)

// 指定可接收的最大字節(jié)數(shù) maxSize 的數(shù)據(jù)到指針 data 指向的內(nèi)存中
qint64 QIODevice::read(char *data, qint64 maxSize);
// 指定可接收的最大字節(jié)數(shù) maxSize,返回接收的字符串
QByteArray QIODevice::read(qint64 maxSize);
// 將當(dāng)前可用操作數(shù)據(jù)全部讀出,通過返回值返回讀出的字符串
QByteArray QIODevice::readAll();

2.4 QTcpSocket信號(hào)

在使用 QTcpSocket 進(jìn)行套接字通信的過程中,如果該類對(duì)象發(fā)射出 readyRead() 信號(hào),說明對(duì)端發(fā)送的數(shù)據(jù)達(dá)到了,之后就可以調(diào)用 read 函數(shù)接收數(shù)據(jù)了。

[signal] void QIODevice::readyRead();

調(diào)用 connectToHost() 函數(shù)并成功建立連接之后發(fā)出 connected() 信號(hào)。
在套接字?jǐn)嚅_連接時(shí)發(fā)出 disconnected() 信號(hào)。

調(diào)用 connectToHost() 函數(shù)并成功建立連接之后發(fā)出 connected() 信號(hào)。
[signal] void QAbstractSocket::disconnected();

3. 通信流程

3.1 服務(wù)器端

  • 創(chuàng)建套接字服務(wù)器 QTcpServer 對(duì)象
  • 通過 QTcpServer 對(duì)象設(shè)置監(jiān)聽,即:QTcpServer::listen()
  • 基于 QTcpServer::newConnection() 信號(hào)檢測(cè)是否有新的客戶端連接
  • 如果有新的客戶端連接調(diào)用 QTcpSocket *QTcpServer::nextPendingConnection() 得到通信的套接字對(duì)象
  • 使用通信的套接字對(duì)象 QTcpSocket 和客戶端進(jìn)行通信

頭文件

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_startServer_clicked();

    void on_sendMsg_clicked();

private:
    Ui::MainWindow *ui;
    QTcpServer* m_server;
    QTcpSocket* m_tcp;
};

源文件

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowTitle("TCP - 服務(wù)器");
    // 創(chuàng)建 QTcpServer 對(duì)象
    m_server = new QTcpServer(this);
    // 檢測(cè)是否有新的客戶端連接
    connect(m_server, &QTcpServer::newConnection, this, [=]()
    {
        m_tcp = m_server->nextPendingConnection();
        ui->record->append("成功和客戶端建立了新的連接...");
        m_status->setPixmap(QPixmap(":/connect.png").scaled(20, 20));
        // 檢測(cè)是否有客戶端數(shù)據(jù)
        connect(m_tcp, &QTcpSocket::readyRead, this, [=]()
        {
            // 接收數(shù)據(jù)
            QString recvMsg = m_tcp->readAll();
            ui->record->append("客戶端Say: " + recvMsg);
        });
        // 客戶端斷開了連接
        connect(m_tcp, &QTcpSocket::disconnected, this, [=]()
        {
            ui->record->append("客戶端已經(jīng)斷開了連接...");
            m_tcp->deleteLater();
            m_status->setPixmap(QPixmap(":/disconnect.png").scaled(20, 20));
        });
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

// 啟動(dòng)服務(wù)器端的服務(wù)按鈕
void MainWindow::on_startServer_clicked()
{
    unsigned short port = ui->port->text().toInt();
    // 設(shè)置服務(wù)器監(jiān)聽
    m_server->listen(QHostAddress::Any, port);
    ui->startServer->setEnabled(false);
}

// 點(diǎn)擊發(fā)送數(shù)據(jù)按鈕
void MainWindow::on_sendMsg_clicked()
{
    QString sendMsg = ui->msg->toPlainText();
    m_tcp->write(sendMsg.toUtf8());
    ui->record->append("服務(wù)器Say: " + sendMsg);
    ui->msg->clear();

3.2 客戶端

通信流程

  • 創(chuàng)建通信的套接字類 QTcpSocket 對(duì)象
  • 使用服務(wù)器端綁定的 IP 和端口連接服務(wù)器 QAbstractSocket::connectToHost()
  • 使用 QTcpSocket 對(duì)象和服務(wù)器進(jìn)行通信

頭文件

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_connectServer_clicked();

    void on_sendMsg_clicked();

    void on_disconnect_clicked();

private:
    Ui::MainWindow *ui;
    QTcpSocket* m_tcp;
};

源文件

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowTitle("TCP - 客戶端");

    // 創(chuàng)建通信的套接字對(duì)象
    m_tcp = new QTcpSocket(this);
    // 檢測(cè)服務(wù)器是否回復(fù)了數(shù)據(jù)
    connect(m_tcp, &QTcpSocket::readyRead, [=]()
    {
        // 接收服務(wù)器發(fā)送的數(shù)據(jù)
        QByteArray recvMsg = m_tcp->readAll();
        ui->record->append("服務(wù)器Say: " + recvMsg);
    });
        
    // 檢測(cè)是否和服務(wù)器是否連接成功了
    connect(m_tcp, &QTcpSocket::connected, this, [=]()
    {
        ui->record->append("恭喜, 連接服務(wù)器成功!!!");
        m_status->setPixmap(QPixmap(":/connect.png").scaled(20, 20));
    });
        
    // 檢測(cè)服務(wù)器是否和客戶端斷開了連接
    connect(m_tcp, &QTcpSocket::disconnected, this, [=]()
    {
        ui->record->append("服務(wù)器已經(jīng)斷開了連接, ...");
        ui->connectServer->setEnabled(true);
        ui->disconnect->setEnabled(false);
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

// 連接服務(wù)器按鈕按下之后的處理動(dòng)作
void MainWindow::on_connectServer_clicked()
{
    QString ip = ui->ip->text();
    unsigned short port = ui->port->text().toInt();
    // 連接服務(wù)器
    m_tcp->connectToHost(QHostAddress(ip), port);
    ui->connectServer->setEnabled(false);
    ui->disconnect->setEnabled(true);
}

// 發(fā)送數(shù)據(jù)按鈕按下之后的處理動(dòng)作
void MainWindow::on_sendMsg_clicked()
{
    QString sendMsg = ui->msg->toPlainText();
    m_tcp->write(sendMsg.toUtf8());
    ui->record->append("客戶端Say: " + sendMsg);
    ui->msg->clear();
}

// 斷開連接按鈕被按下之后的處理動(dòng)作
void MainWindow::on_disconnect_clicked()
{
    m_tcp->close();
    ui->connectServer->setEnabled(true);
    ui->disconnect->setEnabled(false);
}

到此這篇關(guān)于Qt實(shí)現(xiàn)網(wǎng)絡(luò)聊天室的示例代碼的文章就介紹到這了,更多相關(guān)Qt 聊天室內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言中的字符串?dāng)?shù)據(jù)在C中的存儲(chǔ)方式

    C語言中的字符串?dāng)?shù)據(jù)在C中的存儲(chǔ)方式

    這篇文章主要介紹了C語言中的字符串?dāng)?shù)據(jù)在C中的存儲(chǔ)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C++中delete和delete[]的區(qū)別

    C++中delete和delete[]的區(qū)別

    這篇文章主要介紹了C++中delete和delete[]的區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2016-03-03
  • C語言實(shí)現(xiàn)任何文件的加密解密功能

    C語言實(shí)現(xiàn)任何文件的加密解密功能

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)任何文件的加密解密功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • C++ 打開選擇文件夾對(duì)話框選擇目錄的操作

    C++ 打開選擇文件夾對(duì)話框選擇目錄的操作

    這篇文章主要介紹了C++ 打開選擇文件夾對(duì)話框選擇目錄的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 使用C語言實(shí)現(xiàn)貪吃蛇小游戲

    使用C語言實(shí)現(xiàn)貪吃蛇小游戲

    這篇文章主要為大家詳細(xì)介紹了使用C語言實(shí)現(xiàn)貪吃蛇小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • 關(guān)于vector迭代器失效的幾種情況總結(jié)

    關(guān)于vector迭代器失效的幾種情況總結(jié)

    下面小編就為大家?guī)硪黄P(guān)于vector迭代器失效的幾種情況總結(jié)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-12-12
  • C++ Boost實(shí)現(xiàn)數(shù)字與字符串轉(zhuǎn)化詳解

    C++ Boost實(shí)現(xiàn)數(shù)字與字符串轉(zhuǎn)化詳解

    Boost是為C++語言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱
    2022-11-11
  • VSCode配置C++環(huán)境的方法步驟(MSVC)

    VSCode配置C++環(huán)境的方法步驟(MSVC)

    這篇文章主要介紹了VSCode配置C++環(huán)境的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • C語言初識(shí)變量常量字符串轉(zhuǎn)義符及注釋方式簡(jiǎn)介

    C語言初識(shí)變量常量字符串轉(zhuǎn)義符及注釋方式簡(jiǎn)介

    最強(qiáng)的C語言筆記,此處對(duì)于C語言的基礎(chǔ)部分做一個(gè)簡(jiǎn)要的介紹,作者實(shí)屬初學(xué),寫博客也是作者學(xué)習(xí)的一個(gè)過程,若文中內(nèi)容有理解不到位或者有不當(dāng)之處,還請(qǐng)朋友們不吝指正
    2021-11-11
  • C++Node類Cartographer開始軌跡的處理深度詳解

    C++Node類Cartographer開始軌跡的處理深度詳解

    這篇文章主要介紹了C++Node類Cartographer開始軌跡的處理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-03-03

最新評(píng)論