天天看點

Qt實作網絡聊天室(用戶端,服務端)1. 效果示範2. 預備知識3. 通信流程

1. 效果示範

  • 用戶端
    Qt實作網絡聊天室(用戶端,服務端)1. 效果示範2. 預備知識3. 通信流程
  • 伺服器
    Qt實作網絡聊天室(用戶端,服務端)1. 效果示範2. 預備知識3. 通信流程

連接配接成功之後

Qt實作網絡聊天室(用戶端,服務端)1. 效果示範2. 預備知識3. 通信流程

2. 預備知識

如果不知道網絡程式設計的可以去看我的上一篇文章C++網絡程式設計

在Qt中,實作網絡程式設計的方式比用C++或C實作要友善簡單許多,因為Qt已經替我們封裝好了,我們會使用就可以了,然後大家還需要了解Qt 的信号槽機制,可以參考我這篇文章,Qt信号槽

2.1 QTcpServer

QTcpServer 類用于監聽用戶端連接配接以及和用戶端建立連接配接,在使用之前先介紹一下這個類提供的一些常用 API 函數:

構造函數
給監聽的套接字設定監聽
bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
// 判斷目前對象是否在監聽, 是傳回true,沒有監聽傳回false
bool QTcpServer::isListening() const;
// 如果目前對象正在監聽傳回監聽的伺服器位址資訊, 否則傳回 QHostAddress::Null
QHostAddress QTcpServer::serverAddress() const;
// 如果伺服器正在監聽連接配接,則傳回伺服器的端口; 否則傳回0
quint16 QTcpServer::serverPort() const
           

參數:

address:通過類 QHostAddress 可以封裝 IPv4、IPv6 格式的 IP 位址,QHostAddress::Any 表示自動綁定

port:如果指定為 0 表示随機綁定一個可用端口。

傳回值:綁定成功傳回 true,失敗傳回 false

得到和用戶端建立連接配接之後用于通信的 QTcpSocket 套接字對象,它是 QTcpServer 的一個子對象,當 QTcpServer 對象析構的時候會自動析構這個子對象,當然也可自己手動析構,建議用完之後自己手動析構這個通信的 QTcpSocket 對象。
阻塞等待用戶端發起的連接配接請求,不推薦在單線程程式中使用,建議使用非阻塞方式處理新連接配接,即使用信号 newConnection() 。

參數:

msec:指定阻塞的最大時長,機關為毫秒(ms)

timeout:傳出參數,如果操作逾時 timeout 為 true,沒有逾時 timeout 為 false

2.2 QTcpServer信号

當接受新連接配接導緻錯誤時,将發射如下信号。socketError 參數描述了發生的錯誤相關的資訊
每次有新連接配接可用時都會發出 newConnection () 信号。

2.3 QTcpSocket

QTcpSocket 是一個套接字通信類,不管是用戶端還是伺服器端都需要使用。在 Qt 中發送和接收資料也屬于 IO 操作(網絡 IO)

構造函數
連接配接伺服器,需要指定伺服器端綁定的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 中不管調用讀操作函數接收資料,還是調用寫函數發送資料,操作的對象都是本地的由 Qt 架構維護的一塊記憶體。是以,調用了發送函數資料不一定會馬上被發送到網絡中,調用了接收函數也不是直接從網絡中接收資料,關于底層的相關操作是不需要使用者來維護的。

接收資料
// 指定可接收的最大位元組數 maxSize 的資料到指針 data 指向的記憶體中
qint64 QIODevice::read(char *data, qint64 maxSize);
// 指定可接收的最大位元組數 maxSize,傳回接收的字元串
QByteArray QIODevice::read(qint64 maxSize);
// 将目前可用操作資料全部讀出,通過傳回值傳回讀出的字元串
QByteArray QIODevice::readAll();
           

2.4 QTcpSocket信号

在使用 QTcpSocket 進行套接字通信的過程中,如果該類對象發射出 readyRead() 信号,說明對端發送的資料達到了,之後就可以調用 read 函數接收資料了。

調用 connectToHost() 函數并成功建立連接配接之後發出 connected() 信号。

在套接字斷開連接配接時發出 disconnected() 信号。

調用 connectToHost() 函數并成功建立連接配接之後發出 connected() 信号。
[signal] void QAbstractSocket::disconnected();
           

3. 通信流程

3.1 伺服器端

  • 建立套接字伺服器 QTcpServer 對象
  • 通過 QTcpServer 對象設定監聽,即:QTcpServer::listen()
  • 基于 QTcpServer::newConnection() 信号檢測是否有新的用戶端連接配接
  • 如果有新的用戶端連接配接調用 QTcpSocket *QTcpServer::nextPendingConnection() 得到通信的套接字對象
  • 使用通信的套接字對象 QTcpSocket 和用戶端進行通信

頭檔案

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;
};

           

3.2 用戶端

通信流程

  • 建立通信的套接字類 QTcpSocket 對象
  • 使用伺服器端綁定的 IP 和端口連接配接伺服器 QAbstractSocket::connectToHost()
  • 使用 QTcpSocket 對象和伺服器進行通信

頭檔案

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;
};