[QT] TCP communication (QTcpServer and QTcpSocket)

1. Overview of TCP communication

TCP is a low-level network protocol used by most Internet network protocols (such as HTTP) for data transmission. It is a reliable, stream-oriented, and connection-oriented transmission protocol, especially suitable for continuous data transmission.

TCP communication must first establish a TCP connection, which is divided into server and client.
Qt provides QTcpServer class and QTcpSocket class for establishing TCP communication.
The server must use QTcpServer to monitor the port and establish a server; QTcpSocket is used to communicate with the socket after the connection is established.

2. QTcpServer

QTcpServer inherits from QObject

2.1 Public functions

void close()Shut down the server and stop network monitoring

bool listen(address, port)Start listening on the given IP address and port, and return true if successful.address = QHostAddress addr(IP)

bool isListening()Return true to indicate that the server is in the listening state

QTcpSocket* nextPendingConnection()Returns the next incoming connection waiting. The socket is created as a child of the server, which means it will be automatically deleted when the QTcpServer object is destroyed. Explicitly delete the object when you are done with it to avoid wasting memory. Returns 0 if this function is called when no connections are pending. Note: The returned QTcpSocket object cannot be used from other threads. If you want to use an incoming connection from another thread, you need to override incomingConnection().

QHostAddress serverAddress()If the server is in the listening state, return the server address

quint16 serverPort()If the server is in the listening state, return the server listening port

bool waitForNewConnection()Wait for new connections in a blocking manner

2.2 Signal

void acceptError(QAbstractSocket::SocketError socketError)This signal is emitted when an error occurs when accepting a new connection, and the parameter socketError describes the error message

void newConnection()This signal is emitted when there is a new connection

2.3 Protection function

void incomingConnection(qintptr socketDescriptor)When a new connection is available, QTcpServer calls this function internally, creates a QTcpServer object, adds it to the internal available new connection list, and then emits the newConnection() signal. If the user inherits the defined class from QTcpServer, he can redefine this function, but must call addPendingConnection(). The qintptr is different according to the system type, 32-bit is qint32, and 64-bit is qint64.

void addPendingConnection(QTcpSocket* socket)Called by incomingConnection() to add the created QTcpSocket to the internal list of new available connections.

3. QTcpSocket

QTcpSocket is indirectly inherited from QIODevice

QIODevice -> QAbstractSocket -> QTcpSocket

In addition to the construction and destruction of the QTcpSocket class, other functions are inherited or redefined from QAbstractSocket

3.1 Public functions

void connectToHost(QHostAddress& address, quint16 port)Asynchronously connect to the TCP server with the specified IP address and port. If the connection is successful, the connected() signal will be sent

void disconnectFromHost()Disconnect the socket, the disconnected() signal will be emitted after the close is successful

bool waitForConnected()Wait until a socket connection is established

bool waitForDisconnected()Wait until the socket connection is disconnected

QHostAddress localAddress()Return the address of this socket

quint16 localPortReturn the port of this socket

QHostAddress peerAddress()In the connected state, return the address of the socket of the other party

QString peerName()Returns the hostname of the peer connected to by connectToHost()

quint16 peerPort()In the connected state, return the port of the other party's socket

qint64 readBufferSize()Returns the size of the internal read buffer, which determines the size of the data that can be read by the read() and realAll() functions

void setReadBufferSize(qint64 size)Set the size of the internal read buffer

qint64 bytesAvailable()Returns the number of bytes of data in the buffer that needs to be read

bool canReadLine()Returns true if there are rows of data to read from the socket buffer

SocketState state()Returns the current state of the socket

3.2 Signal

void connected()connectToHost() emits this signal after successfully connecting to the server

void disconnected()This signal is emitted when the socket is disconnected

void error(QAbstractSocket::SocketError socketError)This signal is emitted when an error occurs on the socket

void hostFound()This signal is emitted after calling connectToHost() to find the host

void stateChanged(QAbstractSocket::SocketState socketState)This signal is emitted when the socket state changes, and the parameter socketState indicates the current state of the socket

void readyRead()This signal is emitted when the buffer has new data to read, and the data in the buffer is read in the slot function of this signal

4. Code example

4.1 Server side

To use the Qt network module, you need to add in the configuration file .pro:

Qt += network

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QAction>
#include <QCloseEvent>
#include <QComboBox>
#include <QGridLayout>
#include <QHostInfo>
#include <QLabel>
#include <QLineEdit>
#include <QMainWindow>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QSpinBox>
#include <QTcpServer>
#include <QTcpSocket>

namespace Ui {
    
    
    class MainWindow;
}

class MainWindow : public QMainWindow {
    
    
    Q_OBJECT

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

protected:
    void closeEvent(QCloseEvent* event);

private slots:
    //工具栏按钮
    void slotActStartTriggered();
    void slotActStopTriggered();
    void slotActClearTriggered();
    void slotActQuitTriggered();

    //界面按钮
    void slotBtnSendClicked();

    //自定义槽函数
    void slotNewConnection();       // QTcpServer的newConnection()信号
    void slotClientConnected();     //客户端socket连接
    void slotClientDisconnected();  //客户端socket断开连接
    void slotSocketStateChange(QAbstractSocket::SocketState socketState);
    void slotSocketReadyRead();  //读取socket传入的数据

private:
    Ui::MainWindow* ui;

    QAction* m_pActStartListen;
    QAction* m_pActStopListen;
    QAction* m_pActClearText;
    QAction* m_pActQuit;
    QWidget* m_pCentralWidget;
    QGridLayout* m_pGridLayout;
    QLabel* m_pLabel1;
    QComboBox* m_pComBoxIP;
    QLabel* m_pLabel2;
    QSpinBox* m_pSpinBoxPort;
    QLineEdit* m_pLineEdit;
    QPushButton* m_pBtnSend;
    QPlainTextEdit* m_pPlainText;
    QLabel* m_pLabListenStatus;  //状态栏标签
    QLabel* m_pLabSocketState;   //状态栏标签
    QTcpServer* m_pTcpServer;    // TCP服务器
    QTcpSocket* m_pTcpSocket;    // TCP通信的socket

    QString getLocalIP();  //获取本机IP地址
};

#endif  // MAINWINDOW_H

MainWindow.cpp

#include "mainwindow.h"

#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
    
    
    ui->setupUi(this);
    this->setWindowTitle(QStringLiteral("TCP服务端"));
    ui->menuBar->hide();

    //工具栏
    ui->mainToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);  //设置工具栏显示风格(图标在上文字在下)
    m_pActStartListen = new QAction(QIcon(":/new/prefix1/res/开始.png"), QStringLiteral("开始监听"), this);
    m_pActStopListen = new QAction(QIcon(":/new/prefix1/res/暂停.png"), QStringLiteral("停止监听"), this);
    m_pActClearText = new QAction(QIcon(":/new/prefix1/res/清空数据.png"), QStringLiteral("清空文本框"), this);
    m_pActQuit = new QAction(QIcon(":/new/prefix1/res/退出.png"), QStringLiteral("退出"), this);
    ui->mainToolBar->addAction(m_pActStartListen);
    ui->mainToolBar->addAction(m_pActStopListen);
    ui->mainToolBar->addAction(m_pActClearText);
    ui->mainToolBar->addSeparator();
    ui->mainToolBar->addAction(m_pActQuit);

    //界面布局
    m_pCentralWidget = new QWidget(this);
    m_pGridLayout = new QGridLayout(m_pCentralWidget);
    m_pLabel1 = new QLabel(QStringLiteral("监听地址"), m_pCentralWidget);  //父对象为新的widget
    // label对象被析构了,所以不会在界面显示。label1需要作为成员变量才可显示或者用指针
    //    QLabel label1;
    //    label1.setText("监听地址");
    m_pComBoxIP = new QComboBox(m_pCentralWidget);
    // m_pComBoxIP->addItem("192.168.1.104");  // QComboBox设置默认项必须添加项
    //必须先add项才能操作下面
    //    comBoxAddr->setCurrentIndex(0);
    //    comBoxAddr->setCurrentText("192.168.1.104");
    m_pLabel2 = new QLabel(QStringLiteral("监听端口"), m_pCentralWidget);
    m_pSpinBoxPort = new QSpinBox(m_pCentralWidget);
    m_pSpinBoxPort->setMinimum(1);
    m_pSpinBoxPort->setMaximum(65535);  //端口范围1~65535
    m_pLineEdit = new QLineEdit(m_pCentralWidget);
    m_pBtnSend = new QPushButton(QStringLiteral("发送消息"), m_pCentralWidget);
    m_pPlainText = new QPlainTextEdit(m_pCentralWidget);
    m_pGridLayout->addWidget(m_pLabel1, 0, 0, Qt::AlignRight);
    // GLayout->addWidget(&label1, 0, 0, Qt::AlignRight);  //对象可以用&的方式
    m_pGridLayout->addWidget(m_pComBoxIP, 0, 1, 1, 2);
    m_pGridLayout->addWidget(m_pLabel2, 0, 3, Qt::AlignRight);
    m_pGridLayout->addWidget(m_pSpinBoxPort, 0, 4);
    m_pGridLayout->addWidget(m_pLineEdit, 1, 0, 1, 4);
    m_pGridLayout->addWidget(m_pBtnSend, 1, 4);
    m_pGridLayout->addWidget(m_pPlainText, 2, 0, 5, 5);
    this->setCentralWidget(m_pCentralWidget);

    //状态栏
    m_pLabListenStatus = new QLabel(QStringLiteral("监听状态:"));
    m_pLabListenStatus->setMinimumWidth(150);
    ui->statusBar->addWidget(m_pLabListenStatus);
    m_pLabSocketState = new QLabel(QStringLiteral("Socket状态:"));
    m_pLabSocketState->setMinimumWidth(200);
    ui->statusBar->addWidget(m_pLabSocketState);

    QString localIP = getLocalIP();
    this->setWindowTitle(this->windowTitle() + "---本机IP:" + localIP);
    m_pComBoxIP->addItem(localIP);

    m_pTcpServer = new QTcpServer(this);
    connect(m_pTcpServer, &QTcpServer::newConnection, this, &MainWindow::slotNewConnection);

    connect(m_pActStartListen, &QAction::triggered, this, &MainWindow::slotActStartTriggered);
    connect(m_pActStopListen, &QAction::triggered, this, &MainWindow::slotActStopTriggered);
    connect(m_pBtnSend, &QPushButton::clicked, this, &MainWindow::slotBtnSendClicked);
    connect(m_pActClearText, &QAction::triggered, this, &MainWindow::slotActClearTriggered);
    connect(m_pActQuit, &QAction::triggered, this, &MainWindow::slotActQuitTriggered);
}

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

void MainWindow::closeEvent(QCloseEvent* event) {
    
    
	//关闭窗口时停止监听
    if (m_pTcpServer->isListening())
        m_pTcpServer->close();  //停止网络监听
    QMessageBox::StandardButton button = QMessageBox::question(this, QStringLiteral(""), "是否退出?");
    if (button == QMessageBox::StandardButton::Yes) {
    
    
        event->accept();
    } else {
    
    
        event->ignore();
    }
}

void MainWindow::slotActStartTriggered() {
    
    
    //开始监听
    QString IP = m_pComBoxIP->currentText();
    quint16 port = m_pSpinBoxPort->value();
    QHostAddress addr(IP);
    m_pTcpServer->listen(addr, port);  //开始监听
    // m_pTcpServer->listen(QHostAddress::LocalHost, port);  //监听本机上某个端口
    // QHostAddress::LocalHost :IPv4本地主机地址。等价于QHostAddress("127.0.0.1")
    m_pPlainText->appendPlainText("**开始监听...");
    m_pPlainText->appendPlainText("**服务器地址:" + m_pTcpServer->serverAddress().toString());
    m_pPlainText->appendPlainText("**服务器端口:" + QString::number(m_pTcpServer->serverPort()));
    m_pActStartListen->setEnabled(false);  //开始之后不能再开始
    m_pActStopListen->setEnabled(true);
    m_pLabListenStatus->setText(QStringLiteral("监听状态:正在监听"));
}

void MainWindow::slotActStopTriggered() {
    
    
    //停止监听
    if (m_pTcpServer->isListening()) {
    
    
        m_pTcpServer->close();
        m_pActStartListen->setEnabled(true);
        m_pActStopListen->setEnabled(false);
        m_pLabListenStatus->setText("监听状态:已停止监听");
    }
}

void MainWindow::slotActClearTriggered() {
    
     m_pPlainText->clear(); }

void MainWindow::slotActQuitTriggered() {
    
     this->close(); }

void MainWindow::slotBtnSendClicked() {
    
    
    //发送一行字符串,以换行符结束
    QString msg = m_pLineEdit->text();
    m_pPlainText->appendPlainText("[out]: " + msg);
    m_pLineEdit->clear();
    m_pLineEdit->setFocus();  // 发送完设置焦点

    //字符串的传递一般都要转换为UTF-8格式,编译器不同可能导致乱码,UFTF-8格式是统一的格式,每个编译器都会带,防止乱码
    QByteArray str = msg.toUtf8();  //返回字符串的UTF-8格式
    str.append('\n');
    m_pTcpSocket->write(str);
}

void MainWindow::slotNewConnection() {
    
    
    m_pTcpSocket = m_pTcpServer->nextPendingConnection();  //获取socket
    connect(m_pTcpSocket, &QTcpSocket::connected, this, &MainWindow::slotClientConnected);
    // slotClientConnected();
    connect(m_pTcpSocket, &QTcpSocket::disconnected, this, &MainWindow::slotClientDisconnected);
    connect(m_pTcpSocket, &QTcpSocket::stateChanged, this, &MainWindow::slotSocketStateChange);
    slotSocketStateChange(m_pTcpSocket->state());
    connect(m_pTcpSocket, &QTcpSocket::readyRead, this, &MainWindow::slotSocketReadyRead);
}

void MainWindow::slotClientConnected() {
    
    
    //客户端接入时
    m_pPlainText->appendPlainText("**client socket connected");
    m_pPlainText->appendPlainText("**peer address: " + m_pTcpSocket->peerAddress().toString());  //对端的地址
    m_pPlainText->appendPlainText("**peer port: " + QString::number(m_pTcpSocket->peerPort()));  //对端的端口
}

void MainWindow::slotClientDisconnected() {
    
    
    //客户端断开连接时
    m_pPlainText->appendPlainText("**client socket disconnected");
    m_pTcpSocket->deleteLater();
}

void MainWindow::slotSocketStateChange(QAbstractSocket::SocketState socketState) {
    
    
    // socket状态变化时
    switch (socketState) {
    
    
        case QAbstractSocket::UnconnectedState: m_pLabSocketState->setText("socket状态:UnconnectedSate"); break;
        case QAbstractSocket::HostLookupState: m_pLabSocketState->setText("socket状态:HostLookupState"); break;
        case QAbstractSocket::ConnectingState: m_pLabSocketState->setText("socket状态:ConnectingState"); break;
        case QAbstractSocket::ConnectedState: m_pLabSocketState->setText("socket状态:ConnectedState"); break;
        case QAbstractSocket::BoundState: m_pLabSocketState->setText("socket状态:BoundState"); break;
        case QAbstractSocket::ClosingState: m_pLabSocketState->setText("socket状态:ClosingState"); break;
        case QAbstractSocket::ListeningState: m_pLabSocketState->setText("socket状态:ListeningState"); break;
    }
}

void MainWindow::slotSocketReadyRead() {
    
    
    //读取缓冲区行文本
    while (m_pTcpSocket->canReadLine()) {
    
    
        m_pPlainText->appendPlainText("[in]: " + m_pTcpSocket->readLine());
    }
}

QString MainWindow::getLocalIP() {
    
    
    //获取本机IPv4地址
    QString hostName = QHostInfo::localHostName();  //本地主机名
    QHostInfo hostInfo = QHostInfo::fromName(hostName);
    QString localIP = "";
    QList<QHostAddress> addList = hostInfo.addresses();
    if (!addList.isEmpty()) {
    
    
        for (int i = 0; i < addList.count(); i++) {
    
    
            QHostAddress aHost = addList.at(i);
            if (QAbstractSocket::IPv4Protocol == aHost.protocol()) {
    
    
                localIP = aHost.toString();
                break;
            }
        }
    }
    return localIP;
}

4.2 Client

To use the Qt network module, you need to add in the configuration file .pro:

Qt += network

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QAction>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QHostInfo>
#include <QLabel>
#include <QLineEdit>
#include <QMainWindow>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QSpinBox>
#include <QTcpSocket>

namespace Ui {
    
    
    class MainWindow;
}

class MainWindow : public QMainWindow {
    
    
    Q_OBJECT

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

protected:
    void closeEvent(QCloseEvent* event);

private slots:
    //工具栏按钮
    void slotActConnectTriggered();
    void slotActDisConnectTriggered();
    void slotActClearTriggered();
    void slotActQuitTriggered();

    //界面按钮
    void slotBtnSendClicked();

    //自定义槽函数
    void slotConnected();
    void slotDisconnected();
    void slotSocketStateChange(QAbstractSocket::SocketState socketState);
    void slotSocketReadyRead();

private:
    Ui::MainWindow* ui;

    QAction* m_pActConnectServer;
    QAction* m_pActDisconnect;
    QAction* m_pActClear;
    QAction* m_pActQuit;
    QWidget* m_pCentralWidget;
    QLabel* m_pLabel1;
    QLabel* m_pLabel2;
    QLineEdit* m_pLineEditIP;
    QSpinBox* m_pSpinBoxPort;
    QLineEdit* m_pLineEdit;
    QPushButton* m_pBtnSend;
    QPlainTextEdit* m_pPlainText;
    QLabel* m_pLabSocketState;
    QTcpSocket* m_pTcpClient;

    QString getLocalIP();
    void loadStyleFile();
};

#endif  // MAINWINDOW_H

MainWindow.cpp

#include "mainwindow.h"

#include "ui_mainwindow.h"

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

    // QSS样式
    loadStyleFile();

    //工具栏
    ui->mainToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    ui->mainToolBar->setMinimumHeight(50);
    m_pActConnectServer = new QAction(QIcon(":/new/prefix1/res/链接.png"), QStringLiteral("连接服务器"), this);
    m_pActDisconnect = new QAction(QIcon(":/new/prefix1/res/断开链接.png"), QStringLiteral("断开连接"), this);
    m_pActClear = new QAction(QIcon(":/new/prefix1/res/清空数据.png"), QStringLiteral("清空文本框"), this);
    m_pActQuit = new QAction(QIcon(":/new/prefix1/res/退出.png"), QStringLiteral("退出"), this);
    ui->mainToolBar->addAction(m_pActConnectServer);
    ui->mainToolBar->addAction(m_pActDisconnect);
    ui->mainToolBar->addAction(m_pActClear);
    ui->mainToolBar->addSeparator();
    ui->mainToolBar->addAction(m_pActQuit);

    //布局
    m_pCentralWidget = new QWidget(this);
    m_pLabel1 = new QLabel(QStringLiteral("服务器地址"), m_pCentralWidget);
    m_pLabel2 = new QLabel(QStringLiteral("端口"), m_pCentralWidget);
    m_pLineEditIP = new QLineEdit(m_pCentralWidget);
    m_pSpinBoxPort = new QSpinBox(m_pCentralWidget);
    m_pSpinBoxPort->setMinimum(1);
    m_pSpinBoxPort->setMaximum(65535);
    QHBoxLayout* HLay1 = new QHBoxLayout();
    HLay1->addWidget(m_pLabel1, 2);
    HLay1->addWidget(m_pLineEditIP, 6);
    HLay1->addWidget(m_pLabel2, 2, Qt::AlignRight);
    HLay1->addWidget(m_pSpinBoxPort, 3);
    m_pLineEdit = new QLineEdit(m_pCentralWidget);
    m_pBtnSend = new QPushButton(QStringLiteral("发送消息"), m_pCentralWidget);
    QHBoxLayout* HLay2 = new QHBoxLayout();
    HLay2->addWidget(m_pLineEdit, 10);
    HLay2->addWidget(m_pBtnSend, 2);
    m_pPlainText = new QPlainTextEdit(m_pCentralWidget);
    QGridLayout* GridLayout = new QGridLayout(m_pCentralWidget);
    GridLayout->addLayout(HLay1, 0, 0);
    GridLayout->addLayout(HLay2, 1, 0);
    GridLayout->addWidget(m_pPlainText);
    this->setCentralWidget(m_pCentralWidget);

    //状态栏
    m_pLabSocketState = new QLabel(this);
    m_pLabSocketState->setText(QStringLiteral("socket状态:"));
    ui->statusBar->addWidget(m_pLabSocketState);
    m_pLabSocketState->setMinimumWidth(150);

    QString localIP = getLocalIP();
    this->setWindowTitle(this->windowTitle() + "---本机IP:" + localIP);
    m_pLineEditIP->setText(localIP);

    m_pTcpClient = new QTcpSocket(this);
    connect(m_pActConnectServer, &QAction::triggered, this, &MainWindow::slotActConnectTriggered);
    connect(m_pActDisconnect, &QAction::triggered, this, &MainWindow::slotActDisConnectTriggered);
    connect(m_pActClear, &QAction::triggered, this, &MainWindow::slotActClearTriggered);
    connect(m_pActQuit, &QAction::triggered, this, &MainWindow::slotActQuitTriggered);
    connect(m_pBtnSend, &QPushButton::clicked, this, &MainWindow::slotBtnSendClicked);
    connect(m_pTcpClient, &QTcpSocket::connected, this, &MainWindow::slotConnected);
    connect(m_pTcpClient, &QTcpSocket::disconnected, this, &MainWindow::slotDisconnected);
    connect(m_pTcpClient, &QTcpSocket::stateChanged, this, &MainWindow::slotSocketStateChange);
    connect(m_pTcpClient, &QTcpSocket::readyRead, this, &MainWindow::slotSocketReadyRead);
}

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

void MainWindow::closeEvent(QCloseEvent* event) {
    
    
	//关闭之前断开连接
    if (m_pTcpClient->state() == QAbstractSocket::ConnectedState)
        m_pTcpClient->disconnectFromHost();
    QMessageBox::StandardButton button = QMessageBox::question(this, QStringLiteral(""), "是否退出?");
    if (button == QMessageBox::StandardButton::Yes) {
    
    
        event->accept();
    } else {
    
    
        event->ignore();
    }
}
void MainWindow::slotActConnectTriggered() {
    
    
    //连接到服务器按钮
    QString addr = m_pLineEditIP->text();
    quint16 port = m_pSpinBoxPort->value();
    m_pTcpClient->connectToHost(addr, port);
}

void MainWindow::slotActDisConnectTriggered() {
    
    
    //断开连接按钮
    if (m_pTcpClient->state() == QAbstractSocket::ConnectedState) {
    
    
        m_pTcpClient->disconnectFromHost();
    }
}

void MainWindow::slotActClearTriggered() {
    
     m_pPlainText->clear(); }

void MainWindow::slotActQuitTriggered() {
    
     this->close(); }

void MainWindow::slotBtnSendClicked() {
    
    
    //发送数据
    QString msg = m_pLineEdit->text();
    m_pPlainText->appendPlainText("[out]: " + msg);
    m_pLineEdit->clear();
    m_pLineEdit->setFocus();
    QByteArray str = msg.toUtf8();
    str.append('\n');
    m_pTcpClient->write(str);
}

void MainWindow::slotConnected() {
    
    
    // Connected()信号槽函数
    m_pPlainText->appendPlainText("**已连接到服务器");
    m_pPlainText->appendPlainText("**peer address: " + m_pTcpClient->peerAddress().toString());
    m_pPlainText->appendPlainText("**peer port: " + QString::number(m_pTcpClient->peerPort()));
    m_pActConnectServer->setEnabled(false);
    m_pActDisconnect->setEnabled(true);
}

void MainWindow::slotDisconnected() {
    
    
    // Disconnected()信号槽函数
    m_pPlainText->appendPlainText("**已断开与服务器的连接");
    m_pActConnectServer->setEnabled(true);
    m_pActDisconnect->setEnabled(false);
}

void MainWindow::slotSocketStateChange(QAbstractSocket::SocketState socketState) {
    
    
    switch (socketState) {
    
    
        case QAbstractSocket::UnconnectedState: m_pLabSocketState->setText("socket状态:UnconnectedSate"); break;
        case QAbstractSocket::HostLookupState: m_pLabSocketState->setText("socket状态:HostLookupState"); break;
        case QAbstractSocket::ConnectingState: m_pLabSocketState->setText("socket状态:ConnectingState"); break;
        case QAbstractSocket::ConnectedState: m_pLabSocketState->setText("socket状态:ConnectedState"); break;
        case QAbstractSocket::BoundState: m_pLabSocketState->setText("socket状态:BoundState"); break;
        case QAbstractSocket::ClosingState: m_pLabSocketState->setText("socket状态:ClosingState"); break;
        case QAbstractSocket::ListeningState: m_pLabSocketState->setText("socket状态:ListeningState"); break;
    }
}

void MainWindow::slotSocketReadyRead() {
    
    
    while (m_pTcpClient->canReadLine()) {
    
    
        m_pPlainText->appendPlainText("[in]: " + m_pTcpClient->readLine());
    }
}

QString MainWindow::getLocalIP() {
    
    
    QString hostName = QHostInfo::localHostName();
    QHostInfo hostInfo = QHostInfo::fromName(hostName);
    QString localIP = "";
    QList<QHostAddress> addrList = hostInfo.addresses();
    if (!addrList.isEmpty()) {
    
    
        for (int i = 0; i < addrList.size(); i++) {
    
    
            QHostAddress aHost = addrList.at(i);
            if (aHost.protocol() == QAbstractSocket::IPv4Protocol) {
    
    
                localIP = aHost.toString();
                break;
            }
        }
    }
    return localIP;
}

/* 添加QSS样式 */
void MainWindow::loadStyleFile() {
    
    
    QFile file(":/new/prefix1/sytle/style.css");
    file.open(QFile::ReadOnly);
    QString styleSheet = tr(file.readAll());
    this->setStyleSheet(styleSheet);
    file.close();
}

4.3 Interface display

insert image description here
The client interface uses QSS

Guess you like

Origin blog.csdn.net/WL0616/article/details/128869597