QT中TCP通信及遇到的问题

以自定数据包格式进行通信

数据包格式如下:

服务端代码如下:

。cpp文件:主界面程序会发送emit sendTime()和emit sendOCRMsg(OCRMsg, dateTime)信号对应HeratPack和sendData槽函数

#include "TCPthread.h"
#include <qdebug.h>
#include <qtimer.h>
#include <qthread.h>
#include <qdatastream.h>
TCPthread::TCPthread(QObject *parent)
{
    qDebug() << "TCPthread线程id:" << QThread::currentThread();
    tcpServer = NULL;
    
    //监听套接字,指定父对象,让其自动回收空间
    tcpServer = new QTcpServer(this);

    tcpServer->listen(QHostAddress::AnyIPv4, 8888);

    //当有客服端连接时
    connect(tcpServer, &QTcpServer::newConnection,this,&TCPthread::createSocket);
//-----------------------------------------------------------------------------------------------
}
void TCPthread::createSocket() {
    //取出建立好连接的套接字
    QTcpSocket *tcpSocket = tcpServer->nextPendingConnection();

    socketList.push_back(tcpSocket);

    //获取客户端的IP和端口
    QString ip = tcpSocket->peerAddress().toString();
    qint16 port = tcpSocket->peerPort();
    IPort = QString("TCPClient-[%1:%2]:成功连接").arg(ip).arg(port);
    qDebug() << IPort;

    connect(tcpSocket, &QTcpSocket::connected,
        [=]() {
        qDebug() << "成功和服务器建立好连接";
    });

    //接受客服端的数据
    connect(tcpSocket, &QTcpSocket::readyRead,this, &TCPthread::readData);

    //当客户端断开连接
    connect(tcpSocket, &QTcpSocket::disconnected, this, &TCPthread::clientDiscon);

}
//从客户端读取数据
void TCPthread::readData() {
    //从通信套接字中取出内容
    if (socketList.size() != 0) {
        for (int i = 0; i < socketList.size(); i++)
        {
            QByteArray array = socketList[i]->readAll();            
        }
    }
}
//客户端断开连接
void TCPthread::clientDiscon() {
    //与服务器连接的客户端
    QTcpSocket *tcpsocket = qobject_cast<QTcpSocket*>(QObject::sender());
    //移除
    socketList.removeOne(tcpsocket);
    qDebug() << "Client-IP:" << tcpsocket->peerAddress().toString() << "断开连接";
    tcpsocket->deleteLater();
}
//TCP服务器发送板坯报文数据槽函数
void TCPthread::sendData(QString OCR_Msg, QDateTime dateTime) {
    
    //封装包头
    QByteArray sendOCRByte;//用于发送数据的字节数组
    QDataStream out(&sendOCRByte, QIODevice::WriteOnly);//使用数据流写入数据
    out.setByteOrder(QDataStream::LittleEndian);//设置小端模式
    out << ushort(0) << m_OCRPackID;//占位符,这里必须要先这样占位,然后后续读算出整体长度后在插入

    qDebug() << "报文头长度:" << sendOCRByte.length();//4

    //封装数据
    QString s_data = OCR_Msg + dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz") +"0";
    qDebug() << s_data << "字符串长度:" << s_data.length();//48

    QByteArray ba = s_data.toLocal8Bit(); //字符串转字节数组
    qDebug() << "字符字节数组长度:" << ba.length(); //48
//---------------------------------------------------------
    char * c_data;
    c_data = ba.data();
    sendOCRByte.append(c_data);//在4个字节数组中添加48个字符串
//---------------------------------------------------------
    out.device()->seek(0);//回到数据流开头,插入数据的长度  
    ushort t_len = (ushort)(sendOCRByte.length());
    out << t_len;
    qDebug() << "板坯报文长度:" << t_len;//52

    //发送数据|多例
    if (socketList.size() != 0) {
        for (int i = 0; i < socketList.size(); i++)
        {
            socketList[i]->write(sendOCRByte);
            socketList[i]->flush();
        }
    }
}
//发送心跳报文
void TCPthread::HeratPack() {
    if (socketList.size() != 0) {
        for (int i = 0; i < socketList.size(); i++)
        {
            //用于心跳报文要发送的数据
            QByteArray sendHeartByte;
            //使用数据流写入数据
            QDataStream out(&sendHeartByte, QIODevice::WriteOnly);
            //设置小端模式
            out.setByteOrder(QDataStream::LittleEndian);
            //占位符,这里必须要先这样占位,然后后续读算出整体长度后在插入
            out << ushort(0) << m_heartPackID ;
            //回到文件开头,插入数据的长度  
            out.device()->seek(0);
            ushort len = (ushort)(sendHeartByte.size());
            out << len;//4
        
            qDebug() <<"心跳报文长度:" << len  << "心跳报文ID:" << m_heartPackID;

            //往套接字缓存中写入数据,并发送
            socketList[i]->write(sendHeartByte);
            socketList[i]->flush();
        }
    }
}
TCPthread::~TCPthread()
{
    //主动和客户端断开连接
    if (socketList.size() != 0) {
        for (int i = 0; i < socketList.size(); i++)
        {
            socketList[i]->disconnectFromHost();
            socketList[i]->close();
            socketList[i] = NULL;
            delete socketList[i];
        }
    }
    delete tcpServer;    
}

遇到的问题:

1、心跳报文中为发送4个字节长度报文:两个quint16类型的数据均占2个字节,甲方并要求使用小端模式

解决办法:使用QByteArray字节数组进行写入

2、数据报文中,需使用ushort类型2个占4个字节和48个字节字符串共52个字节

解决办法:前面ushort类型使用QDataStraem类型写到QByteArray中。后面字符串使用char *类型append添加到QByteArray中,这样共52个字节

客户端:读取数据

。cpp文件:

#include "Client.h"
#pragma execution_character_set("utf-8")
Client::Client(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
}
//连接按钮|获取服务器地址和端口号
void Client::on_Connect_Button_clicked()
{
    socket = new QTcpSocket(this);
    socket->connectToHost(ui.leip->text(),ui.leport->text().toInt());
    connect(socket,SIGNAL(readyRead()),this,SLOT(receiveMessage()));
}
//发送按钮|获取文本框内容
void Client::on_Send_Button_clicked()
{
    QString str = ui.tesend->toPlainText();
    socket->write(str.toUtf8());//中文不乱码

}
//接收信息显示
void Client::receiveMessage()
{
    qDebug() << socket->bytesAvailable() << "========";//4\52
    if (socket->bytesAvailable() <= 0)
    {
        return;
    }
    QByteArray buffer;

    buffer = socket->readAll();

    //m_buffer.append(buffer);

    qDebug() << buffer.size(); //4或者52

    if (buffer.size() == 4) {
        QString s = buffer.mid(4);
        if (s == "ABC" )
        {
            //QString str = QString(buffer);
            ui.tereceive->append(s);
        }
        qDebug() << buffer.mid(0,2).toInt(); //0
        qDebug() << buffer.mid(2, 2).toInt();//0
        QDataStream packet(buffer);
        packet.setByteOrder(QDataStream::LittleEndian);
        quint16 len, ID;
        packet >> len >>ID;
        qDebug() << len <<ID;//4 1 
        ui.tereceive->append(QString::number(len)); //4
        ui.tereceive->append(QString::number(ID)); //1
    }
    if (buffer.size() == 52)
    {
        /*quint16 length = (quint16)buffer.mid(0,2).toInt();
        quint16 packID = (quint16)buffer.mid(2, 2).toInt();*/
        //qDebug() << "报文长度:" << length << " 报文ID:" << packID;//报文长度: 4  报文ID: 0
        //---------------------------------------------------------------------------------------
        QDataStream OCRpacket(buffer);
        OCRpacket.setByteOrder(QDataStream::LittleEndian);
        quint16 ocr_length, ocr_ID;
        OCRpacket >> ocr_length >> ocr_ID;
        qDebug() << "报文长度2:" << ocr_length << " 报文ID2:" << ocr_ID;
        //--------------------------------------------------------------------------------------------
        QString OCRstr = QString::fromStdString(buffer.mid(4, 24).toStdString());
        qDebug() << OCRstr;
        QString s_dateTome = QString::fromStdString(buffer.mid(28, 52).toStdString());
        qDebug() << s_dateTome;
        ui.tereceive->append(OCRstr);
        ui.tereceive->append(s_dateTome);
    }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值