zoukankan      html  css  js  c++  java
  • Qt NetWork即时通讯网络聊天室(基于TCP)

    本文使用QT的网络模块来创建一个网络聊天室程序,主要包括以下功能:

    1、基于TCP的可靠连接(QTcpServer、QTcpSocket)

    2、一个服务器,多个客户端

    3、服务器接收到某个客户端的请求以及发送信息,经该信息重定向发给其它客户端

    最终实现一个共享聊天内容的聊天室!

    开发测试环境:QT5.12.0 + Qt Creator 4.8.0 + MinGW7.3

    代码如下:

    1、服务器 QtInstantMessagingServer

    基于Console的应用程序,因为这里不需要界面。

    QT += core network
    QT -= gui

     Server.h
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    #ifndef SERVER_H
    #define SERVER_H

    #include <QObject>
    #include <QTcpServer>
    #include <QTcpSocket>
    #include <QDebug>
    #include <QVector>

    class Server : public QObject
    {
        Q_OBJECT
    public:
        
    explicit Server(QObject *parent = nullptr);

        
    void startServer();
        
    void sendMessageToClients(QString message);

    signals:

    public slots:
        
    void newClientConnection();
        
    void socketDisconnected();
        
    void socketReadyRead();
        
    void socketStateChanged(QAbstractSocket::SocketState state);

    private:
        QTcpServer*             chatServer;
        QVector<QTcpSocket*>*   allClients;
    };

    #endif // SERVER_H
     Server.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
     
    #include "Server.h"

    Server::Server(QObject *parent) : QObject(parent)
    {

    }

    void Server::startServer()
    {
        
    // store all the connected clients
        allClients = new QVector<QTcpSocket*>;
        
    // created a QTcpServer object called chatServer
        chatServer = new QTcpServer();
        
    // limit the maximum pending connections to 10 clients.
        chatServer->setMaxPendingConnections(10);
        
    // The chatServer will trigger the newConnection() signal whenever a client has connected to the server.
        connect(chatServer, SIGNAL(newConnection()), this, SLOT(newClientConnection()));
        
    // made it constantly listen to port 8001.
        if (chatServer->listen(QHostAddress::Any, 8001))
        {
            qDebug() << 
    "Server has started. Listening to port 8001.";
        }
        
    else
        {
            qDebug() << 
    "Server failed to start. Error: " + chatServer->errorString();
        }

    }

    void Server::sendMessageToClients(QString message)
    {
        
    if (allClients->size() > 0)
        {
            
    // we simply loop through the allClients array and pass the message data to all the connected clients.
            for (int i = 0; i < allClients->size(); i++)
            {
                
    if (allClients->at(i)->isOpen() && allClients->at(i)->isWritable())
                {
                    allClients->at(i)->write(message.toUtf8());
                }
            }
        }

    }

    void Server::newClientConnection()
    {
        
    // Every new client connected to the server is a QTcpSocket object,
        // which can be obtained from the QTcpServer object by calling nextPendingConnection().
        QTcpSocket* client = chatServer->nextPendingConnection();
        
    // You can obtain information about the client
        // such as its IP address and port number by calling peerAddress() and peerPort(), respectively.
        QString ipAddress = client->peerAddress().toString();
        
    int port = client->peerPort();
        
    // connect the client's disconnected(),readyRead() and stateChanged() signals to its respective slot function.
        // 1、When a client is disconnected from the server, the disconnected() signal will be triggered
        connect(client, &QTcpSocket::disconnected, this, &Server::socketDisconnected);
        
    // 2、whenever a client is sending in a message to the server, the readyRead() signal will be triggered.
        connect(client, &QTcpSocket::readyRead, this, &Server::socketReadyRead);
        
    // 3、 connected another signal called stateChanged() to the socketStateChanged() slot function.
        connect(client, &QTcpSocket::stateChanged, this, &Server::socketStateChanged);
        
    // store each new client into the allClients array for future use.
        allClients->push_back(client);
        qDebug() << 
    "Socket connected from " + ipAddress + ":" + QString::number(port);
    }

    // When a client is disconnected from the server, the disconnected() signal will be triggered
    void Server::socketDisconnected()
    {
        
    // displaying the message on the server console whenever it happens, and nothing more.
        QTcpSocket* client = qobject_cast<QTcpSocket*>(QObject::sender());
        QString socketIpAddress = client->peerAddress().toString();
        
    int port = client->peerPort();
        qDebug() << 
    "Socket disconnected from " + socketIpAddress + ":" + QString::number(port);
    }

    // whenever a client is sending in a message to the server, the readyRead() signal will be triggered.
    void Server::socketReadyRead()
    {
        
    // use QObject::sender() to get the pointer of the object that emitted the readyRead signal
        // and convert it to the QTcpSocket class so that we can access its readAll() function.
        QTcpSocket* client = qobject_cast<QTcpSocket*>(QObject::sender());
        QString socketIpAddress = client->peerAddress().toString();
        
    int port = client->peerPort();
        QString data = QString(client->readAll());
        qDebug() << 
    "Message: " + data + " (" + socketIpAddress + ":" + QString::number(port) + ")";
        
    // redirect the message, just passing the message to all connected clients.
        sendMessageToClients(data);
    }

    // This function gets triggered whenever a client's network state has changed,
    // such as connected, disconnected, listening, and so on.
    void Server::socketStateChanged(QAbstractSocket::SocketState state)
    {
        QTcpSocket* client = qobject_cast<QTcpSocket*>(QObject::sender());
        QString socketIpAddress = client->peerAddress().toString();
        
    int port = client->peerPort();
        QString desc;
        
    // simply print out a relevant message according to its new state
        if (state == QAbstractSocket::UnconnectedState)
            desc = 
    "The socket is not connected.";
        
    else if (state == QAbstractSocket::HostLookupState)
            desc = 
    "The socket is performing a host name lookup.";
        
    else if (state == QAbstractSocket::ConnectingState)
            desc = 
    "The socket has started establishing a connection.";
        
    else if (state == QAbstractSocket::ConnectedState)
            desc = 
    "A connection is established.";
        
    else if (state == QAbstractSocket::BoundState)
            desc = 
    "The socket is bound to an address and port.";
        
    else if (state == QAbstractSocket::ClosingState)
            desc = 
    "The socket is about to close (data may still be waiting to be written).";
        
    else if (state == QAbstractSocket::ListeningState)
            desc = 
    "For internal use only.";
        qDebug() << 
    "Socket state changed (" + socketIpAddress + ":" + QString::number(port) + "): " + desc;
    }
    Main.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #include <QCoreApplication>
    #include "Server.h"

    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);

        Server* myServer = 
    new Server();
        myServer->startServer();

        
    return a.exec();
    }

    2、客户端QtInstantMessagingClient

     基于Widget的应用程序,客户端需要一个友好的界面,父类QMainWindow,MainWindow.ui定义界面如下:

    可以给不同的客户端取个名字,如“Michael”、“James”等等,点击“Connect”按钮连接服务端,此时Label变为“Disconnect”。

    QT       += core gui network

     MainWindow.h
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>
    #include <QDebug>
    #include <QTcpSocket>

    namespace Ui {
    class MainWindow;
    }

    class MainWindow : public QMainWindow
    {
        Q_OBJECT

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

    private slots:
        
    void on_connectButton_clicked();
        
    void socketConnected();
        
    void socketDisconnected();
        
    void socketReadyRead();

        
    void on_sendButton_clicked();

    private:
        Ui::MainWindow* ui;
        
    bool            connectedToHost;
        QTcpSocket*     socket;

        
    void printMessage(QString message);
    };

    #endif // MAINWINDOW_H
     MainWindow.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
     
    #include "MainWindow.h"
    #include "ui_MainWindow.h"

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(
    new Ui::MainWindow)
    {
        ui->setupUi(
    this);
        connectedToHost = 
    false;
    }

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

    void MainWindow::on_connectButton_clicked()
    {
        
    if (!connectedToHost)
        {
            
    // create a QTcpSocket object called socket and make it connect to a host at 127.0.0.1 on port 8801.
            socket = new QTcpSocket();
            
    // connected the socket object to its respective slot functions when connected(),disconnected(), and readReady() signals were triggered.
            // This is exactly the same as the server code
            connect(socket, SIGNAL(connected()), this, SLOT(socketConnected()));
            connect(socket, SIGNAL(disconnected()), 
    this, SLOT(socketDisconnected()));
            connect(socket, SIGNAL(readyRead()), 
    this, SLOT(socketReadyRead()));
            
    // Since this is only for testing purposes, we will connect the client to our test server,
            // which is located on the same computer.
            // If you're running the server on another computer,
            // you may change the IP address to a LAN or WAN address, depending on your need.
            socket->connectToHost("127.0.0.1"8001);
        }
        
    else
        {
            QString name = ui->nameInput->text();
            socket->write(
    "<font color="Orange">" + name.toUtf8() + " has left the chat room.</font>");
            socket->disconnectFromHost();
        }

    }

    void MainWindow::socketConnected()
    {
        qDebug() << 
    "Connected to server.";
        printMessage(
    "<font color="Green">Connected to server.</font>");
        QString name = ui->nameInput->text();
        socket->write(
    "<font color="Purple">" + name.toUtf8() + " has joined the chat room.</font>");
        ui->connectButton->setText(
    "Disconnect");
        connectedToHost = 
    true;
    }

    void MainWindow::socketDisconnected()
    {
        qDebug() << 
    "Disconnected from server.";
        printMessage(
    "<font color="Red">Disconnected from server.</font>");
        ui->connectButton->setText(
    "Connect");
        connectedToHost = 
    false;
    }

    void MainWindow::socketReadyRead()
    {
        ui->chatDisplay->append(socket->readAll());
    }

    void MainWindow::printMessage(QString message)
    {
        ui->chatDisplay->append(message);
    }


    void MainWindow::on_sendButton_clicked()
    {
        QString name = ui->nameInput->text();
        QString message = ui->messageInput->text();
        socket->write(
    "<font color="Blue">" + name.toUtf8() + "</font>: " + message.toUtf8());
        ui->messageInput->clear();
    }
     Main.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #include "MainWindow.h"
    #include <QApplication>

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        
        MainWindow w;
        w.show();

        
    return a.exec();
    }

    构建成功后,将生成的QtInstantMessagingServer.exe以及QtInstantMessagingClient.exe置于.QtQt5.12.05.12.0mingw73_64in目录下(该目录下可以双击exe直接运行!)

     

  • 相关阅读:
    js中有哪些是循环遍历的方法?
    堆内存和栈内存
    Html5和Css3
    PyCharm IDE 的使用
    python基础语法
    数据挖掘书籍简介
    寄存器-2
    汇编基础
    Std::bind()
    手游页游和端游的服务端框架
  • 原文地址:https://www.cnblogs.com/MakeView660/p/10825439.html
Copyright © 2011-2022 走看看