添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《 阿里云开发者社区用户服务协议 》和 《 阿里云开发者社区知识产权保护指引 》。如果您发现本社区中有涉嫌抄袭的内容,填写 侵权投诉表单 进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。 qDebug ( ) << "Current OS is Linux" ; # elif defined(Q_OS_WIN) qDebug ( ) << "Current OS is Windows" ; # else qDebug ( ) << "Unknown OS" ; # endif QString folderName = "pic" ; //QString folderPath = QDir::currentPath() + "/" + folderName; QString folderPath = QApplication :: applicationDirPath ( ) + "/" + folderName ; QDir folder ( folderPath ) ; if ( ! folder . exists ( ) ) bool success = folder . mkpath ( "." ) ; // 创建文件夹 if ( success ) qDebug ( ) << "文件夹创建成功" ; qDebug ( ) << "文件夹创建失败" ; qDebug ( ) << "文件夹已存在" ; QDir :: setCurrent ( folderPath ) ; // 设置文件生成路径 AdClient w ; w . show ( ) ; return a . exec ( ) ;

tcp_MSG.h 共用Tcp传输信息

#ifndef TCP_MSG_H
#define TCP_MSG_H
#include<QMetaType>
#define tcp_MSG_txt_NUM 256
#define tcp_MSG_city_NUM 32
#define tcp_MSG_weather_NUM 128
#define tcp_MSG_path_NUM 128
#define tcp_MSG_photo_NUM 1280*800
#pragma pack(1)     //设置结构体为1字节对齐
typedef struct
    int type;// 消息类型
    char txt[tcp_MSG_txt_NUM];// 文字信息
    char city[tcp_MSG_city_NUM];// 城市
    char area[tcp_MSG_city_NUM];// 地区
    char weather[tcp_MSG_weather_NUM];// 天气
    char fileName[tcp_MSG_path_NUM];// 文件名
    int index; // 编号
    int allAd_Num;// 总数
    int fileSize;// 文件大小
}tcp_MSG;
#pragma pack()        //结束结构体对齐设置
Q_DECLARE_METATYPE(tcp_MSG)
// 实现对象的元编程功能。它可以用来定义宏,类型和函数,以支持将元数据与类型关联起来。它还可以用来实现类型安全性,类型转换和序列化功能。
//宏来注册tcp_MSG类型
enum MsgType{
    Init=0, // 初始化
    WEATHER, //天气
    MASSEGE,// 留言
    VIDEO, // 视频
    AD_add, // 添加广告
    AD_delete, // 删除广告
    Write_back,//回复
#pragma pack(1)     //设置结构体为1字节对齐
typedef struct
    int type;// 消息类型
    int state;// 状态  0不发送 1发送
    char id[32];// id
}tcp_backMSG;
#pragma pack()        //结束结构体对齐设置
Q_DECLARE_METATYPE(tcp_backMSG)
//宏来注册tcp_backMSG类型
#pragma pack(1)     //设置结构体为1字节对齐
typedef struct
    int type;// 消息类型
    char photo[tcp_MSG_photo_NUM];
}tcp_Image;
#pragma pack()        //结束结构体对齐设置
Q_DECLARE_METATYPE(tcp_Image)
//宏来注册tcp_Image类型
#endif // TCP_MSG_H

adclient.h 客户端

#ifndef ADCLIENT_H
#define ADCLIENT_H
#include <QMainWindow>
#include "addate.h"
#include "adsocket.h"
#include "weather.h"
#include "rollmassege.h"
#include <QLabel>
#include <QProgressDialog>
#include "stdlib.h"
#include <QThread>
#include <QTimer>
#include <QFile>
#include <QMessageBox>
#include <QNetworkInterface>
#include <QTcpSocket>
#include <QHostAddress>
#include <QAbstractSocket>
#include <QLineEdit>
#include <QPushButton>
namespace Ui {
class AdClient;
class AdClient : public QMainWindow
    Q_OBJECT
public:
    explicit AdClient(QWidget *parent = 0);
    ~AdClient();
    void saveFile();// 保存文件
    void InitStatusBar();// 初始化底部状态栏
    QString GetLocalIP();// 获取本地IP
public slots:
    void showImage(QImage);// 图片显示
    void showProgressBar(int currentProgress,int finish);//进度条显示
    void autoPlayTimeOut();//自动播放
    void GUI_WarningMsg(QString title,QString text,QString buttons,QString defaultButton);//设置警报
    void connectToServer();// 链接到服务器
private:
    Ui::AdClient *ui;
    AdDate *date;
    AdSocket *socket;
    Weather *weater;
    RollMassege *rollmsg;
    QProgressDialog *progress;// 创建进度条
    QTimer autoPlayTimer;
    int index;
    QLabel *mLocalIP;
    QLabel *serverIP_lb;
    QLineEdit *serverIP;
    QLabel *serverPort_lb;
    QLineEdit *serverPort;
    QPushButton *connectTcp;
#endif // ADCLIENT_H

adclient.cpp 客户端

#include "adclient.h"
#include "ui_adclient.h"
#include <QDebug>
QMap<QString,QImage> qMapPicturePath;// 图片路径
//QTcpSocket 的默认缓存区大小是 64KB(65536字节)
AdClient::AdClient(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::AdClient)
    ui->setupUi(this);
    this->setWindowIcon(QIcon(":/client.jpg"));
    date = new AdDate(ui->date_lb);//时间
    socket = new AdSocket;// TCP客户端
    weater = new Weather(ui->weather_lb);// 接收天气信息绘制
    rollmsg = new RollMassege(ui->msg_lb, ui->msg_lb);// 滚动信息
    connect(socket, SIGNAL(sig_showWeather(QString,QString,QString)), weater, SLOT(showWeather(QString,QString,QString)));
    connect(socket, SIGNAL(sig_showTxt(QString)), rollmsg, SLOT(showTxt(QString)));
    connect(socket, SIGNAL(sig_showImage(QImage)), this, SLOT(showImage(QImage)));
    connect(socket, SIGNAL(sig_showProgressBar(int,int)), this, SLOT(showProgressBar(int,int)),Qt::QueuedConnection);
    connect(socket, SIGNAL(GUI_WarningSignal(QString,QString,QString,QString)), this, SLOT(GUI_WarningMsg(QString,QString,QString,QString)));
    date->start();//更新时间
    progress = nullptr;
    autoPlayTimer.stop();
    connect(&autoPlayTimer, SIGNAL(timeout()), this, SLOT(autoPlayTimeOut()));
    InitStatusBar();// 初始化底部状态栏
AdClient::~AdClient()
    delete socket;
    delete ui;
// 保存文件
void AdClient::saveFile()
    QString fileName=qMapPicturePath.lastKey();
    qDebug()<<"lastKey:"<<fileName;
    QImage image=qMapPicturePath.last();
    image.save(fileName);
// 初始化底部状态栏
void AdClient::InitStatusBar()
    mLocalIP=new QLabel(this);
    mLocalIP->setMinimumWidth(230);
    QString ip = GetLocalIP();
    //    mLocalIP->setText("本地IP:"+ip);
    mLocalIP->setText("本地IP:"+tr("<font color=\"red\">%1</font>").arg(ip));
    serverIP_lb=new QLabel(this);
    serverIP_lb->setMinimumWidth(100);
    serverIP_lb->setText("服务器IP:");
    serverIP=new QLineEdit(this);
    serverIP->setMinimumWidth(200);
    serverIP->setInputMask("000.000.000.000");
    serverPort_lb=new QLabel(this);
    serverPort_lb->setMinimumWidth(60);
    serverPort_lb->setText("Port:");
    serverPort=new QLineEdit(this);
    serverPort->setMinimumWidth(60);
    serverPort->setPlaceholderText("8888");
    connectTcp=new QPushButton("链接",this);
    connectTcp->setMinimumWidth(100);
    ui->statusBar->addWidget(mLocalIP);
    ui->statusBar->addWidget(serverIP_lb);
    ui->statusBar->addWidget(serverIP);
    ui->statusBar->addWidget(serverPort_lb);
    ui->statusBar->addWidget(serverPort);
    ui->statusBar->addWidget(connectTcp);
    connect(connectTcp, SIGNAL(clicked()), this, SLOT(connectToServer()));
// 获取本地IP
QString AdClient::GetLocalIP()
    QList<QHostAddress> list=QNetworkInterface::allAddresses();
    foreach(QHostAddress address,list)
        if(address.protocol()==QAbstractSocket::IPv4Protocol)
            qDebug()<<address.toString();
            return address.toString();
    return "";
// 图片显示
void AdClient::showImage(QImage image)
    qDebug()<<"显示图片"<<__LINE__;
    QPixmap pixmap=QPixmap::fromImage(image);
    // 内容是否自动缩放,参数true自动缩放
    ui->video_lb->setScaledContents(true);//显示图片的全部
    // 将图片缩放到指定大小,参数ui->label->size()表示缩放的大小,Qt::KeepAspectRatio表示保持图片的宽高比,Qt::SmoothTransformation表示使用平滑缩放算法
    ui->video_lb->setPixmap(pixmap.scaled(ui->video_lb->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
    qDebug()<<"图片数量:"<<qMapPicturePath.count();
    qDebug()<<"定时器状态:"<<autoPlayTimer.isActive();
    if(qMapPicturePath.count()>=2)
        if(!autoPlayTimer.isActive()){
            // 两张以上图片开启播放
            autoPlayTimer.start(5000);
            index=0;
        autoPlayTimer.stop();
    if(qMapPicturePath.count()>=1)
        // 功能没问题,调试注释,避免多次保存
        //saveFile();// 保存文件
//进度条显示
void AdClient::showProgressBar(int currentProgress, int finish)
    qDebug()<<"进度条显示"<<__LINE__;
    if (!progress)
        //创建进度条
        progress = new QProgressDialog("接收中....", "取消", 0, 100, this);
        progress->setWindowModality(Qt::WindowModal);
        progress->setFixedSize(this->width()*0.3,this->height()*0.3);
        progress->setVisible(true);
    //usleep(500);//在Windows环境下已被弃用
    QThread::msleep(50);//休眠50毫秒
    //更新进度条
    progress->setValue(currentProgress * 100 / finish);
    //如果任务已经完成,隐藏进度条
    if (currentProgress == finish)
        qDebug()<<"进度条显示完成"<<__LINE__;
        progress->hide();
        delete progress;
        progress = nullptr;
//自动播放
void AdClient::autoPlayTimeOut()
    QList<QString> keyList = qMapPicturePath.keys();//存放的就是QMap的key值
    if(index>=qMapPicturePath.count())// 删除广告时有可能 >
        index=0;
    QImage image=qMapPicturePath.value(keyList.at(index));
    qDebug()<<"自动播放:"<<keyList.at(index);
    showImage(image);
    index++;
//设置警报
void AdClient::GUI_WarningMsg(QString title, QString text, QString buttons, QString defaultButton)
    Q_UNUSED(buttons)//忽略编译器发出的警告,表明变量event未使用
    Q_UNUSED(defaultButton)
    QMessageBox *box=new QMessageBox(QMessageBox::Warning,title,text,QMessageBox::Cancel,this);
    QTimer::singleShot(5000,this,[=](){
        if(!box->isHidden()&&box->isVisible())
            box->accept();
    });// 5s后必执行
    box->exec();
    return;
// 链接到服务器
void AdClient::connectToServer()
    if(serverIP->text().isEmpty()||serverPort->text().isEmpty())
        QMessageBox::warning(this,"提示","请输入IP或Port");
        return;
    socket->id=GetLocalIP();
    socket->address=serverIP->text();
    qDebug()<<"服务器IP:"<<socket->address;
    socket->port=serverPort->text().toInt();
    qDebug()<<"服务器Port:"<<socket->port;
    qDebug()<<"是否已经连接:"<<socket->isValid();
    if(socket->isValid())// 如果套接字有效并且可以使用,则返回true;否则返回false。
        socket->disconnectFromHost();// 与服务器断开连接
        // 无需再手动连接,只要更新IP和Port就行,AdSocket::conAgain会重新发起连接.
        socket->connectToHost(QHostAddress(socket->address), socket->port);
    qDebug()<<"是否已经连接:"<<socket->isValid();

addate.h 时间处理

#ifndef ADDATE_H
#define ADDATE_H
#include <QTime>
#include <QDate>
#include <QLabel>
#include <QTimer>
class AdDate : public QObject
    Q_OBJECT
public:
    AdDate(QLabel *_mlabel, QObject *parent = 0);
    ~AdDate();
    void start();// 定时器开启
public slots:
    void updateTime();// 定时器1s超时执行一次
private:
    QLabel *mlabel;
    QTimer *mtimer;
#endif // ADDATE_H

addate.cpp 时间处理

#include "addate.h"
AdDate::AdDate(QLabel *_mlabel, QObject *parent):
    QObject(parent)
    mlabel = _mlabel;
    mtimer = new QTimer;
    connect(mtimer, SIGNAL(timeout()), this, SLOT(updateTime()));
AdDate::~AdDate()
    delete mtimer;
void AdDate::start()
     mtimer->start(1000);
void AdDate::updateTime()
    QString time = QTime::currentTime().toString("hh:mm:ss")+"\n"
            +QDate::currentDate().toString("yy/MM/dd ddd");
    mlabel->setText(time);

adsocket.h 客户端Socket处理

#ifndef ADSOCKET_H
#define ADSOCKET_H
#include <QTcpSocket>
#include <QHostAddress>
#include <QAbstractSocket>
#include <QAbstractSocket>
#include <QImage>
#include <QLabel>
#include <QBuffer>
#include <QTime>
#include "string.h"
#include "tcp_MSG.h"
class AdSocket : public QTcpSocket
    Q_OBJECT
public:
    explicit AdSocket(QObject *parent = 0);
    ~AdSocket();
    QString id;
    QString address;
    int port;
    int readMsgType;
signals:
    void sig_showWeather(QString city,QString area,QString wt);// 发送天气信息
    void sig_showTxt(QString tcp_Txt);// 发送文字信息
    void sig_showImage(QImage tcp_image);// 发送文字信息
    void sig_showProgressBar(int currentProgress, int finish);// 发送进度条信息
    void GUI_WarningSignal(QString title,QString text,QString buttons,QString defaultButton);//设置警报
public slots:
    void readMsg();// 接收信息
    void conSuc(); // 成功建立连接
    void conAgain();// 重新连接
    void conAgain(QAbstractSocket::SocketError);// 重新连接
private:
    int needFileSize;
    int currentReceiveSize;
    QByteArray currentReceiveByte;
    int milsec;
    QString fileName;
#endif // ADSOCKET_H

adsocket.cpp 客户端Socket处理

#include "adsocket.h"
#include <QDebug>
extern QMap<QString,QImage> qMapPicturePath;// 图片路径
// QTcpSocket会自动处理大小端问题
AdSocket::AdSocket(QObject *parent) :
    QTcpSocket(parent)
    //注册tcp_MSG类型
    qRegisterMetaType<tcp_MSG>("tcp_MSG");
    id = "0011";
    /* 每当有新的输入数据时,就会发出这个信号。
    请记住,新传入的数据只报告一次;如果您不读取所有数据,这个类会缓冲数据,您可以稍后读取它,但是除非新数据到达,否则不会发出信号。*/
    connect(this, SIGNAL(readyRead()),this, SLOT(readMsg()));
    //该信号在调用connectToHost()并成功建立连接之后发出。
    connect(this, SIGNAL(connected()),this, SLOT(conSuc()));
    // 该信号在套接字断开连接时发出
    connect(this, SIGNAL(disconnected()),this, SLOT(conAgain()));
    address="127.0.0.1";
    port=8888;
    //connectToHost(QHostAddress(address), port);// 默认连接127.0.0.1 8888
    //该信号在错误发生后发出。socketError参数描述发生错误的类型
    connect(this, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(conAgain(QAbstractSocket::SocketError)));
    readMsgType=MsgType::Init;
    milsec=0;
AdSocket::~AdSocket()
// 接收信息
void AdSocket::readMsg()
    //读取缓冲区数据
    QByteArray  buffer = readAll();
    qDebug()<<"进来了"<<__LINE__;
    if(readMsgType==MsgType::Init)
        tcp_MSG *msg=(tcp_MSG *)buffer.data();        //强转为结构体,需要用结构体指针接收
        qDebug()<<"进来了"<<__LINE__;
        qDebug()<<"类型"<<msg->type;
        switch (msg->type)
        case WEATHER://天气
            QString city=msg->city;
            QString area=msg->area;
            QString weather=msg->weather;
            //weather="\t\t"+city+"\t"+area+"\n"+weather;
            emit sig_showWeather(city,area,weather);// 发送天气信息
            break;
        case MASSEGE:// 留言
            QString tcp_Txt=msg->txt;
            qDebug()<<"文字信息:"<<tcp_Txt;
            emit sig_showTxt(tcp_Txt);// 发送文字信息
            break;
        case VIDEO:// 视频
            qDebug()<<"发送视频信息:";
            break;
        case AD_add://添加广告
            qDebug()<<"添加广告"<<__LINE__;
            qDebug()<<"文件名"<< QString(msg->fileName);
            qDebug()<<"编号"<< msg->index;
            qDebug()<<"总数"<< msg->allAd_Num;
            needFileSize=msg->fileSize;
            currentReceiveSize=0;
            currentReceiveByte.clear();
            QByteArray  sendTcpData;
            //使用字节数组,将结构体转为字符数组,发送的是字符数组(数据在传输过程中都是byte类型的)
            //直接sizeof(senddata)内存会变小,设置了对齐方式解决
            sendTcpData.resize(sizeof(tcp_backMSG));
            tcp_backMSG backMsg={
            strcpy(backMsg.id,id.toUtf8().data());
            backMsg.state=1;
            backMsg.type=MsgType::Write_back;
            //将封装好的结构体转为QByteArray数组,因为传输都是Byte类型
            memcpy(sendTcpData.data(),&backMsg,sizeof(tcp_backMSG));
            this->write(sendTcpData);// 回复
            fileName.clear();
            fileName=QString(msg->fileName);
            readMsgType=MsgType::AD_add;
            break;
        case AD_delete://删除广告
            qDebug()<<"删除广告"<<__LINE__;
            qDebug()<<"文件名"<< QString(msg->fileName);
            int  success= qMapPicturePath.remove(QString(msg->fileName));
            if(success)
                if(qMapPicturePath.count()>=1)
   // 有图片
                    emit sig_showImage(qMapPicturePath.first());
   // 没有图片
                    QImage image(100, 100, QImage::Format_RGBA8888);
                    image.fill(QColor(0, 0, 0, 0));// 纯透明图片
                    emit sig_showImage(image);
                emit GUI_WarningSignal("提示","删除广告成功",NULL,NULL);
                emit GUI_WarningSignal("提示","删除广告失败",NULL,NULL);
            break;
        default:
            qDebug()<<"";
            break;
    else if(readMsgType==MsgType::AD_add)
        qDebug()<<"添加广告"<<__LINE__;
        qDebug()<<"需要接收大小:"<<needFileSize;
        // 记录开始时间
        QTime startTime = QTime::currentTime();
        currentReceiveSize+=buffer.size();
        currentReceiveByte+=buffer;
        qDebug()<<"当前接收大小:"<<currentReceiveSize;
        emit sig_showProgressBar(currentReceiveSize,needFileSize);
        // 记录结束时间
        QTime endTime = QTime::currentTime();
        // 计算运行时间
        milsec += startTime.msecsTo(endTime);
        if(needFileSize==currentReceiveSize)
            qDebug()<<"图片接收完成";
            startTime = QTime::currentTime();
            QByteArray Ret_bytearray = QByteArray::fromBase64(currentReceiveByte);
            QBuffer buffer(&Ret_bytearray);
            buffer.open(QIODevice::WriteOnly);
            QPixmap imageresult;
            imageresult.loadFromData(Ret_bytearray);
            qMapPicturePath.insert(fileName,imageresult.toImage());// 先插入键值
            emit sig_showImage(imageresult.toImage());
            readMsgType=MsgType::Init;
            endTime = QTime::currentTime();
            milsec += startTime.msecsTo(endTime);
            qDebug()<<"接收消耗时间"<<milsec<<"毫秒";
// 成功建立连接
void AdSocket::conSuc()
    QByteArray  sendTcpData;
    //使用字节数组,将结构体转为字符数组,发送的是字符数组(数据在传输过程中都是byte类型的)
    //直接sizeof(senddata)内存会变小,设置了对齐方式解决
    sendTcpData.resize(sizeof(tcp_backMSG));
    tcp_backMSG msg={
    strcpy(msg.id,id.toUtf8().data());
    msg.state=0;
    msg.type=MsgType::Init;
    //将封装好的结构体转为QByteArray数组,因为传输都是Byte类型
    memcpy(sendTcpData.data(),&msg,sizeof(tcp_backMSG));
    this->write(sendTcpData);
    qDebug()<<"connect success";
// 重新连接
void AdSocket::conAgain()
    qDebug()<<"套接字断开连接时重新连接";
    abort();// 终止当前连接并重置套接字
    connectToHost(QHostAddress(address), port);
// 重新连接
void AdSocket::conAgain(QAbstractSocket::SocketError error)
    qDebug()<<"连接失败:"<<error;
    readMsgType=MsgType::Init;
    abort();// 终止当前连接并重置套接字
    if(error==QAbstractSocket::ConnectionRefusedError)
        connectToHost(QHostAddress(address), port);

weather.h 天气信息处理

#ifndef WEATHER_H
#define WEATHER_H
#include <QObject>
#include <QLabel>
#include <QDebug>
class Weather : public QObject
    Q_OBJECT
public:
    explicit Weather( QLabel *_label,QObject *parent = 0);
signals:
public slots:
    void showWeather(QString city,QString area,QString weather);
private:
    QLabel *label;
    QString _city;
    QString _area;
#endif // WEATHER_H

weather.cpp 天气信息处理

#include "weather.h"
Weather::Weather( QLabel *_label, QObject *parent) :
    QObject(parent)
    label = _label;
void Weather::showWeather(QString city,QString area,QString weather)
    _city=city;
    qDebug()<<"城市:"<<_city;
    _area=area;
    qDebug()<<"地区:"<<_area;
    weather="\t\t"+_city+"\t"+_area+"\n\t"+weather;
    label->setText(weather);

rollmassege.h 滚动信息处理

#ifndef ROLLMASSEGE_H
#define ROLLMASSEGE_H
#include <QLabel>
#include <QEvent>
#include <QTimer>
#include <QRect>
#include <QPainter>
#include <QFont>
class RollMassege : public QLabel
    Q_OBJECT
public:
    explicit RollMassege(QWidget *parent = 0);
    explicit RollMassege(QLabel *_label, QWidget *parent = 0);
    void paintEvent(QPaintEvent *event);
signals:
public slots:
    void updateMsg();
    void showTxt(QString tcp_Txt);
private:
    QString txt;
    QRect rect;
    int offset;//偏移量
    QTimer *timer;
#endif // ROLLMASSEGE_H

rollmassege.cpp 滚动信息处理

#include "rollmassege.h"
#include <QDebug>
RollMassege::RollMassege(QWidget *parent) :
    QLabel(parent)
RollMassege::RollMassege(QLabel *_label, QWidget *parent) :
    QLabel(parent)
    rect = _label->geometry();
    rect.setWidth(798);
    rect.setHeight(80);
    setGeometry(rect);
    show();
    qDebug()<<rect.width()<<" "<<rect.height();
    offset = rect.width();//偏移量
    txt = "暂无信息";
    timer = new QTimer;
    connect(timer, SIGNAL(timeout()), this, SLOT(updateMsg()));
    timer->start(50);
// 绘画事件
void RollMassege::paintEvent(QPaintEvent *event)
    Q_UNUSED(event); //忽略编译器发出的警告,表明变量event未使用
    QPainter painter(this);
    QFont font;
    font.setPointSize(16);
    painter.setFont(font);
    painter.drawText(rect.x()+offset, rect.y()+30, txt);// 绘制文字,x+偏移量
void RollMassege::updateMsg()
    offset--;
    if(offset<0) offset = rect.width();
    update();// 刷新,触发绘画事件paintEvent
void RollMassege::showTxt(QString tcp_Txt)
    txt =tcp_Txt;
    update();
 

Gitee:08Qt-Advertising-Machine Qt广告机

  • QTcpSocket发送和接收使用 自定义 信息结构体,
  • 结构体需要1字节对齐 ,参考Qt 利用TCP/IP socket通信 发送与接收结构体(简单通信协议解析)

  • 发送
    ```cpp
    QByteArray sendTcpData;
    //使用字节数组,将结构体转为字符数组,发送的是字符数组(数据在传输过程中都是byte类型的)
    //直接sizeof(senddata)内存会变小,设置了对齐方式解决
    sendTcpData.resize(sizeof(tcp_MSG));
  • //将封装好的结构体转为QByteArray数组,因为传输都是Byte类型
    memcpy(sendTcpData.data(),&msg,sizeof(tcp_MSG));

    socket->write(sendTcpData);

    ```cpp //读取缓冲区数据 QByteArray buffer = readAll(); tcp_MSG *msg=(tcp_MSG *)buffer.data(); //强转为结构体,需要用结构体指针接收

    QTcpSocket 的默认缓存区大小是 64KB(65536字节)

    图片一般比较大,需要循环接收,校验发送长度和接收长度

    因为QTcpSocket是一个基于字节流的套接字,它只能传输二进制数据。而图片文件是一种二进制文件,不能直接传输。因此,需要将图片文件转换为一种可传输的文本格式,如Base64编码。

    Base64编码是一种将二进制数据转换为ASCII字符的编码方式。它将每3个字节转换为4个字符,因此可以将任何二进制数据转换为一种文本格式,方便传输

    本项目发送图片,使用 服务器下发消息类型,客户端回复并开启图片接收; 服务器 把图片发给 回复的客户端;

  • 发送
    ```cpp
    *在adtcp.cpp的Ad_SendAction()中先下发消息类型
    {
    QFileInfo file(path);
    QImage image(path);
    QByteArray byteArray;
    QBuffer buffer(&byteArray);
    buffer.open(QIODevice::WriteOnly);

    //获取文件的后缀名,并将其转换为大写字母
    image.save(&buffer,file.suffix().toUpper().toStdString().c_str()); //将图片保存为PNG/JPG等格式

    sendImage = byteArray.toBase64();

    msg.fileSize=sendImage.size();

    buffer.close();
    }

  • 在adtcp.cpp的read_back()中先下发消息类型
    {
    // 返回此信号的 发送对象
    QTcpSocket
    getSocket=qobject_cast(sender());
    //读取缓冲区数据
    QByteArray buffer = getSocket->readAll();//client_list->last()->msocket->readAll();// 读取最后客户端(也就是最新的)
    tcp_backMSG msg=(tcp_backMSG )buffer.data(); //强转为结构体,需要用结构体指针接收

    else if(msg->type==MsgType::Write_back&&msg->state==1)
        getSocket->write(sendImage);
        // 用于等待发送的数据被写入到网络套接字描述符中,这样就可以确保数据完全被发送出去,
        //该函数会阻塞程序继续执行,直到数据被完全发送出去
        if (getSocket->waitForBytesWritten())
            getSocket->flush(); //释放socket缓存
    ```cpp
    * 在adsocket.cpp的readMsg()先回复并开启图片接收
        //读取缓冲区数据
        QByteArray  buffer = readAll();
        tcp_MSG *msg=(tcp_MSG *)buffer.data();        //强转为结构体,需要用结构体指针接收
        needFileSize=msg->fileSize;// 需要接收图片大小
        QByteArray  sendTcpData;
        //使用字节数组,将结构体转为字符数组,发送的是字符数组(数据在传输过程中都是byte类型的)
        //直接sizeof(senddata)内存会变小,设置了对齐方式解决
        sendTcpData.resize(sizeof(tcp_backMSG));
        tcp_backMSG backMsg={};
        strcpy(backMsg.id,id.toUtf8().data());
        backMsg.state=1;
        backMsg.type=MsgType::Write_back;
        //将封装好的结构体转为QByteArray数组,因为传输都是Byte类型
        memcpy(sendTcpData.data(),&backMsg,sizeof(tcp_backMSG));
        this->write(sendTcpData);// 回复
    * 在adsocket.cpp的readMsg()图片接收
        QByteArray  buffer = readAll();
        qDebug()<<"需要接收大小:"<<needFileSize;
        currentReceiveSize+=buffer.size();
        currentReceiveByte+=buffer;//当前累计接收大小
        if(needFileSize==currentReceiveSize)
        {qDebug()<<"图片接收完成";
           QByteArray Ret_bytearray = QByteArray::fromBase64(currentReceiveByte);
           QBuffer buffer(&Ret_bytearray);
           buffer.open(QIODevice::WriteOnly);
           QPixmap imageresult;
           imageresult.loadFromData(Ret_bytearray);
           QImage pic=imageresult.toImage();
    下载地址:
    国内下载 http://47.98.241.45/outbound/Public/sip/eyeBeam.zip(eyebeam)
    国内下载 sipphone.cc/phone_lite_…
    国外下载 phone.ddrj.com/phone_lite_…
    百度云下载 pan.baidu.com/s/1hs64Nbu
    双击 phone.exe AI源码,VOS,SIP软件
                                    AI_WX_3307623172