10.4QT实现TCP服务器客户端搭建的代码,现象

服务器:
.pro:
cpp 复制代码
QT       += core gui network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
widget.h:
cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>       //服务器头文件
#include <QTcpSocket>       //客户端头文件
#include <QList>            //链表容器
#include <QMessageBox>      //消息对话框
#include <QDebug>           //测试

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_startBtn_clicked();

    void newConnection_slot();
    void readyRead_slot();

private:
    Ui::Widget *ui;

    //定义服务器指针
    QTcpServer *server;
    //定义客户端容器
    QList<QTcpSocket *> clientList;
};
#endif // WIDGET_H
widget.cpp:
cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //实例化一个服务器
    server = new QTcpServer;

    connect(server, &QTcpServer::newConnection, this, &Widget::newConnection_slot);

}

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

//启动服务器按钮对应的槽函数
void Widget::on_startBtn_clicked()
{
    quint16 port = ui->portEdit->text().toUInt();       //获取ui界面上的端口号

    //监听客户端的连接请求
    if(!server->listen(QHostAddress::Any, port)){
        QMessageBox::critical(this, "失败", "监听失败");
        return;
    }else{
        QMessageBox::information(this, "成功", "服务器启动成功");
    }

    //此时,服务器已经成功进入监听状态,如果有客户端向服务器发来请求
    //那么该服务器,就会自动发射一个newconnection信号,我们可以将该信号连接到对应槽函数中执行相关逻辑
    //由于只需要进行一次连接即可,所以可以将该连接放在构造函数中完成
}

//自定义处理newConnection信号的槽函数的定义
void Widget::newConnection_slot()
{
    qDebug()<<"您有新的客户端发来请求";

    //获取最新连接的客户端套接字
    QTcpSocket* s = server->nextPendingConnection();
    //将该套接字放入客户端链表中
    clientList.push_back(s);

    //至此,多个客户端已经和服务器建立连接,并放入客户端容器中了
    //此时,如果有客户端向服务器发来数据,那么对应的客户端套接字就会自动发射一个readyRead信号
    //我们可以将该信号连接到自定义的槽函数中,处理相关逻辑
    connect(s, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
}

//自定义处理readyRead信号的槽函数的声明
void Widget::readyRead_slot()
{
    qDebug()<<"您有新的客户端消息发来";

    //遍历客户端链表,将无效的客户端移除
    for(int i=0; i<clientList.size(); i++){
        //判断当前套接字是否是有效连接
        if(0 == clientList[i]->state()){
            //如果是0,表示该套接字为无效连接,将该套接字移除出客户端容器
            clientList.removeAt(i);
            i--;
        }
    }

    //遍历客户端链表,判断是哪个客户端发来的数据
    for(int i=0; i<clientList.size(); i++){
        //获取当前套接字中待读数据的字节数,0说明无数据待读
        if(clientList[i]->bytesAvailable()){
            //将该套接字中的数据读取出来
            QByteArray msg = clientList[i]->readAll();

            //将数据展示到ui界面
            ui->msgWidget->addItem(QString::fromLocal8Bit(msg));

            //将接收到的数据转发给所有客户端
            for (int j=0; j<clientList.size(); j++) {
                clientList[j]->write(msg);
            }
        }
    }
}
widget.ui:
客户端:
.pro:
cpp 复制代码
QT       += core gui network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
widget.h:
cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpSocket>   //客户端类
#include <QMessageBox>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_connectBtn_clicked();

    void connected_slot();
    void readyRead_slot();

    void on_sendBtn_clicked();

    void on_disconnectBtn_clicked();

    void disconnected_slot();

private:
    Ui::Widget *ui;

    //定义客户端指针
    QTcpSocket *socket;

    //定义字符串接收用户名
    QString usrname;
};
#endif // WIDGET_H
widget.cpp:
cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //给客户端指针实例化对象
    socket = new QTcpSocket(this);

    connect(socket, &QTcpSocket::connected, this, &Widget::connected_slot);

    //如果服务器向客户端发来消息,那么该客户端会自动发射一个readyRead信号,我们可以将信号连接到自定义槽函数中处理
    connect(socket, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);

    connect(socket, &QTcpSocket::disconnected, this, &Widget::disconnected_slot);
}

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

//连接服务器按钮对应的槽函数
void Widget::on_connectBtn_clicked()
{
    //获取ui界面上的相关信息
    usrname = ui->usrnameEdit->text();  //获取用户名
    QString ip = ui->IPEdit->text();    //获取ip地址
    quint16 port = ui->portEdit->text().toUInt();    //获取端口号
    //将客户端连接到给定的服务器
    socket->connectToHost(ip, port);

    //此时,已经向服务器发送连接请求了,如果成功连接服务器,那么客户端会自动发送一个connected的信号
}

//自定义处理connected的信号的槽函数的定义
void Widget::connected_slot()
{
    QMessageBox::information(this, "成功", "您已经成功进入聊天室");
    //向服务器发送一条数据:xxx进入聊天室
    QString msg = usrname+": 进入聊天室";

    socket->write(msg.toLocal8Bit());       //将数据发送给服务器
}

//自定义处理readyRead信号的槽函数的定义
void Widget::readyRead_slot(){
    //读取套接字中的信息
    QByteArray msg = socket->readAll();

    //将数据展示到ui界面
    ui->msgWidget->addItem(QString::fromLocal8Bit(msg));
}

//发送按钮对应的槽函数
void Widget::on_sendBtn_clicked()
{
    //获取ui界面输入的内容
    QString msg = usrname + ":" + ui->msgEdit->text();

    //发送给服务器
    socket->write(msg.toLocal8Bit());

    //清空编辑框内容
    ui->msgEdit->clear();
}

//断开服务器按钮对应的槽函数
void Widget::on_disconnectBtn_clicked()
{
    //告诉大家我走了
    QString msg = usrname + ": 离开聊天室";
    socket->write(msg.toLocal8Bit());

    //断开连接
    socket->disconnectFromHost();

    //当成功与服务器断开连接后,该客户端会自动发送一个disconnected的信号
    //可以连接到自定义槽函数处理
}

//自定义的处理disconnected信号的槽函数的定义
void Widget::disconnected_slot()
{
    QMessageBox::information(this, "提示", "退出成功");
}
widget.ui:
实现效果:
相关推荐
Mikko715 分钟前
Linux 重启后日志没了?进程被 OOM 杀了去哪看?logrotate 之后日志还往旧文件写?三台真机实测日志与性能排查
linux·运维·centos
光依旧24 分钟前
发版就掉请求?Spring Boot优雅停机的四步
运维·spring boot·nginx·高可用·优雅停机·mcp server
yichengerp2 小时前
电子行业常用erp系统有哪些?推荐适合中小电子厂的易呈erp软件,操作简单,易落地
大数据·运维·人工智能·云计算·制造
天国梦2 小时前
国密门禁品牌怎么选?2026年最新3个避坑要点
运维·服务器·数据库·python
Tech探索者2 小时前
没有公网 IP、不会端口映射?用 Natfrp 轻松远程访问家中 NAS
网络协议·tcp/ip·智能路由器
好好学习O(∩_∩)O2 小时前
[QT] 多线程moveToThread 和易踩的8个坑
开发语言·qt
dog2503 小时前
带宽,时延,抖动的不可能三角
网络·tcp/ip
夜之眷属3 小时前
PriorityQueue:for-each 遍历和 poll 取出,顺序一样吗?
java·服务器·数据结构·后端·算法
信可维3 小时前
自动化操作多平台账号:登录态、双会话与 User Data 的 3 个坑
运维·自动化
龙仔7253 小时前
RustDesk 自建服务器 Key 强校验配置笔记
运维·服务器·笔记