QT的TcpServer

Server服务器端

QT版本5.6.1

  1. 界面设计
  2. 工程文件:

添加 network 模块

  1. 头文件引入TcpServer类和TcpSocket :QTcpServer和QTcpSocket
cpp 复制代码
#include <QTcpServer>
#include <QTcpSocket>
  1. 创建server对象并实例化:
cpp 复制代码
   /*h文件中*/
    QTcpServer *tcpServer;
   /*cpp文件中*/
   tcpServer = new QTcpServer(this);

使用This作为父对象,方便结束进程生命周期时,释放内存空间

  1. 构建槽函数:
cpp 复制代码
private slots:
    void newConnection_Slot();
    void readyRead_Slot();
    void stateChanged_Slot(QAbstractSocket::SocketState);

注 : 在C++的类中声明函数时可以不写参数名只写参数类型,但是,在实现时必须写出参数名。例如 : void stateChanged_Slot(QAbstractSocket::SocketState);形参是枚举类型,但是没有具体的形参名

newConnection_Slot: 当有客户端的socket建立连接时,tcpserver会发送newConnection()信号,触发连接槽函数,用于创建一个新的socket与客户端对接
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(newConnection_Slot()));

cpp 复制代码
void Widget::newConnection_Slot()
{


   ui->recvEdit->append("Have a clinet connection");
   QTcpSocket *temptcpSocket = tcpServer->nextPendingConnection();
   connect(temptcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Slot()));
   connect(temptcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(stateChanged_Slot(QAbstractSocket::SocketState)));


    // 客户端的ip地址
    QString ipaddr = temptcpSocket->peerAddress().toString();
    quint16 port = temptcpSocket->peerPort();
    // 打印客户端连接的端口信息
    ui->recvEdit->append("服务端:客户端的ip地址:" + ipaddr);
    ui->recvEdit->append("服务端:客户端的端口:" + QString::number(port));

}

readyRead_Slot : 当有客户端的socket发送数据过来,服务端用来与客户端对接的socket发送数据可读信号readyRead(),触发槽函数,读数据
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Slot()));

cpp 复制代码
void Widget::readyRead_Slot()
{
    //sender()返回触发该函数的信号所属者的指针
    QTcpSocket *tcpSocket = (QTcpSocket *)sender();
    QString buf;

    buf = tcpSocket->readAll();

    ui->recvEdit->append(buf);

}

stateChanged_Slot(QAbstractSocket::SocketState) : 当服务端的socket与客户端断开连接时,会发送连接状态改变信号,触发槽函数

cpp 复制代码
void Widget::stateChanged_Slot(QAbstractSocket::SocketState socketState)
{
    QTcpSocket *tcpSocket = (QTcpSocket *)sender();
    switch(socketState){
    case QAbstractSocket::UnconnectedState:
        ui->recvEdit->append("connection end");
        tcpSocket->deleteLater();
    break;

    default:
        break;
    }

}
  1. ui按键槽函数:
cpp 复制代码
    void on_openBt_clicked();
    void on_colseBt_clicked();
    void on_sendBt_clicked();

void on_openBt_clicked() : 打开服务端

cpp 复制代码
void Widget::on_openBt_clicked()
{
   //判断输入的端口号是否为空,为空则直接返回
      if(ui->portEdit->text().isEmpty()){
          ui->recvEdit->append("port is empty!!");
          return;
      }
      //启动监听,QHostAddress::Any表示所有IP地址
     tcpServer->listen(QHostAddress::Any, ui->portEdit->text().toUInt());
     ui->recvEdit->append("open successful");
     ui->openBt->setEnabled(false);
     ui->colseBt->setEnabled(true);
}

on_colseBt_clicked : 关闭客户端

cpp 复制代码
void Widget::on_colseBt_clicked()
{
   //关闭tcpserver知识关闭的监听功能,不会有新的客户端建立连接,但是已经建立连接的socket仍然可以通信
    tcpServer->close();
    ui->recvEdit->append("close successful");
    ui->openBt->setEnabled(true);
    ui->colseBt->setEnabled(false);
}

on_sendBt_clicked : 发送数据

cpp 复制代码
void Widget::on_sendBt_clicked()
{
    //返回server端与客户端建立连接的所有socket
    QList <QTcpSocket *> socketList = tcpServer->findChildren<QTcpSocket *>();
    qDebug() << "tcpSocket 数量:" << socketList.count() << endl;

    if (socketList.count() == 0) {
        ui->recvEdit->append("当前没有客户端连接,请先与客户端连接!");
        return;
    }
    foreach (QTcpSocket *tmpTcpSocket, socketList) {
        // 服务端向每个客户端发送消息
        tmpTcpSocket->write(ui->sendEdit->text().toUtf8());
    }
    ui->recvEdit->append("服务端:" + ui->sendEdit->text());
}

工程源码:

widget.h:

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>


namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
    void state_Slot(QAbstractSocket::SocketState);

private:
    Ui::Widget *ui;
    QTcpServer *tcpServer;

private slots:
    void newConnection_Slot();
    void readyRead_Slot();
    void stateChanged_Slot(QAbstractSocket::SocketState);


    void on_openBt_clicked();
    void on_colseBt_clicked();
    void on_sendBt_clicked();
};

#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);
    tcpServer = new QTcpServer(this);

    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(newConnection_Slot()));
}



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

void Widget::newConnection_Slot()
{


     ui->recvEdit->append("Have a clinet connection");
   QTcpSocket *temptcpSocket = tcpServer->nextPendingConnection();
    connect(temptcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Slot()));
    connect(temptcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(stateChanged_Slot(QAbstractSocket::SocketState)));


    // 客户端的ip地址
    QString ipaddr = temptcpSocket->peerAddress().toString();
    quint16 port = temptcpSocket->peerPort();
    // 打印客户端连接的端口信息
    ui->recvEdit->append("服务端:客户端的ip地址:" + ipaddr);
    ui->recvEdit->append("服务端:客户端的端口:" + QString::number(port));

}

void Widget::readyRead_Slot()
{
    //sender()返回触发该函数的信号所属者的指针
    QTcpSocket *tcpSocket = (QTcpSocket *)sender();
    QString buf;

    buf = tcpSocket->readAll();

    ui->recvEdit->append(buf);

}

void Widget::stateChanged_Slot(QAbstractSocket::SocketState socketState)
{
    QTcpSocket *tcpSocket = (QTcpSocket *)sender();
    switch(socketState){
    case QAbstractSocket::UnconnectedState:
        ui->recvEdit->append("connection end");
        tcpSocket->deleteLater();
    break;
    default:
        break;
    }

}



void Widget::on_openBt_clicked()
{
      if(ui->portEdit->text().isEmpty()){
          ui->recvEdit->append("port is empty!!");
          return;
      }
     tcpServer->listen(QHostAddress::Any, ui->portEdit->text().toUInt());
     ui->recvEdit->append("open successful");
     ui->openBt->setEnabled(false);
     ui->colseBt->setEnabled(true);
}

void Widget::on_colseBt_clicked()
{
    tcpServer->close();
    ui->recvEdit->append("close successful");
    ui->openBt->setEnabled(true);
    ui->colseBt->setEnabled(false);
}

void Widget::on_sendBt_clicked()
{
    //返回server端与客户端建立连接的所有socket
    QList <QTcpSocket *> socketList = tcpServer->findChildren<QTcpSocket *>();
    qDebug() << "tcpSocket 数量:" << socketList.count() << endl;

    if (socketList.count() == 0) {
        ui->recvEdit->append("当前没有客户端连接,请先与客户端连接!");
        return;
    }
    foreach (QTcpSocket *tmpTcpSocket, socketList) {
        // 服务端向每个客户端发送消息
        tmpTcpSocket->write(ui->sendEdit->text().toUtf8());
    }
    ui->recvEdit->append("服务端:" + ui->sendEdit->text());
}
相关推荐
死磕音视频2 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
顽疲5 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
用户8334423966145 小时前
从批量操作到任务中心,再到现场工作台:DeviceForge v2.10—v2.12 完整演进
qt
Wang's Blog5 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友
宛 禾6 小时前
Qt 控件入门:QLabel 从拖拽到对象树,一篇讲透
c++·qt·学习
程序喵大人7 小时前
【C++入门】编译链接模型 - 07 链接器怎样把符号对上号
开发语言·c++·编译器·编译链接·链接器
微三云 - 廖会灵 (私域系统开发)7 小时前
供应链系统实战:多渠道订单聚合与分布式库存一致性方案总结
开发语言·分布式·php
学逆向的7 小时前
C 数据溢出与精度丢失
c语言·开发语言·网络安全
霸道流氓气质8 小时前
AgentFlow 入门与实战:Task-Based 并发、EWMA 动态调度与四道门禁的 Java 生产级编排
java·开发语言
释厄6238 小时前
错误无误公理——错误正确本同源都迭代定律——逆转有价值
android·开发语言·kotlin