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());
//移除
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 + String("yyyy-MM-dd hh:") +"0";
qDebug() << s_data << "字符串长度:" << s_data.length();//48
QByteArray ba = Local8Bit(); //字符串转字节数组
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->Utf8());//中⽂不乱码
}
//接收信息显⽰
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);
}
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
}
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;
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。