串列埠資料通過Tcp轉到伺服器實現資料轉發
阿新 • • 發佈:2018-12-18
主要目的:通過串列埠獲取外設的資料,轉發到伺服器進行處理並在Web端顯示裝置的資訊。
主要用到的知識點:
第一:串列埠通訊相關的知識。
1.串列埠通訊用到的兩個標頭檔案:
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
QSerialPort:用於訪問串列埠,並對串列埠進行操作。
QSerialPortInfo:提供了系統中存在的串列埠的資訊。
2.工程檔案(.pro)中加下面一行程式碼:
QT += serialport
注意:工程檔案中新增上述程式碼後,要儲存後才能生效,方法:在QT Creator中檔案—儲存所有檔案。
第二:Tcp通訊相關知識。
1.Tcp通訊用到的標頭檔案:
#include <QTcpSocket>
2.需要.pro檔案中加入下面程式碼:
QT += network
程式碼實現:
第一:設計模組截圖
下面的紅色是各個控制元件的QbjectNname,在程式碼要用到,為了方便讀者方便閱讀所以都標記出來了。下面“傳送”按鈕是預留按鈕,在程式碼中沒有用到,準備在後面的更新中再優化用到此按鈕哦。
第二:程式碼展示
SerialPort.pro #------------------------------------------------- # # Project created by QtCreator 2018-10-15T16:35:22 # #------------------------------------------------- QT += core gui network serialport greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = SerialPort TEMPLATE = app SOURCES += main.cpp\ widget.cpp HEADERS += widget.h FORMS += widget.ui
注意:QT += core gui network serialport,一定要新增後在檔案中儲存,不然會出問題的哦。
widget.h #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QTcpSocket> #include<QHostAddress> #include<QDebug> #include<QSerialPort> #include<QSerialPortInfo> #include<QTextCodec> #include<QByteArray> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); void InitTcp(); void InitPort(); void doProcessWrite(); void doProcessTcpWrite(); private slots: void doProssConnected(); void doProcessReadyRead(); void doProssDisconnected(); void doProcessSerialRead(); private slots: void on_pushButton_clicked(); void on_ConnectBtn_clicked(); //void on_SendBtn_clicked(); void on_ClearBtn_clicked(); void on_CheckBtn_clicked(); private: Ui::Widget *ui; QTcpSocket *myTcpSocket; bool pushBtnFlag=false; QSerialPort *mySerial; QByteArray tempStr;//儲存的從伺服器獲取的位元組流 QByteArray readComDataMsg;//儲存的從串列埠獲取的位元組流 }; #endif // WIDGET_H
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
w.setWindowTitle("串列埠轉Tcp工具");
return a.exec();
}
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//初始化埠
InitPort();
//初始化Tcp
InitTcp();
ui->SendBtn->setEnabled(false);
}
Widget::~Widget()
{
delete ui;
}
void Widget::InitTcp()
{
myTcpSocket=new QTcpSocket(this);
//由於connectToHost沒有返回值,所以通過三個connect來判斷和伺服器的狀態
connect(myTcpSocket,SIGNAL(disconnected()),this,SLOT(doProssDisconnected()));
connect(myTcpSocket,SIGNAL(connected()),this,SLOT(doProssConnected()));
connect(myTcpSocket,SIGNAL(readyRead()),this,SLOT(doProcessReadyRead()));
}
//點選開啟Tcp連線伺服器
void Widget::on_pushButton_clicked()
{
if(ui->pushButton->text()=="開啟TCP")
{
QString ServceIp=ui->lineEdit_IP->text();
QString ServcePort=ui->lineEdit_Port->text();
myTcpSocket->connectToHost(QHostAddress(ServceIp),ServcePort.toUInt());
ui->pushButton->setText("關閉TCP");
}
else if(ui->pushButton->text()=="關閉TCP")
{
myTcpSocket->close();
ui->pushButton->setText("開啟TCP");
ui->textEdit_Client->append("TCP關閉成功!");
}
}
void Widget::doProssConnected()
{
QString str="開啟伺服器成功";
ui->textEdit_Client->append(str);
}
void Widget::doProcessReadyRead()
{
QTcpSocket *myTcpSocket=(QTcpSocket *)this->sender();
//讀取伺服器向緩衝區的儲存資料
while (!myTcpSocket->atEnd())
{
tempStr= myTcpSocket->readAll();
// tempStr=QString::fromLocal8Bit(tempMsg);
}
//處理向串列埠寫入資料
doProcessWrite();
}
void Widget::doProssDisconnected()
{
// QString msg="伺服器斷開";
// ui->textEdit_Client->append(msg);
ui->pushButton->setText("關閉TCP");
}
//向伺服器寫入資料。
void Widget::doProcessTcpWrite()
{
if(!readComDataMsg.isEmpty())
{
int ret= myTcpSocket->write(readComDataMsg);
readComDataMsg.clear();
if(ret<0)
{
return;
}
}
else{
qDebug()<<"向伺服器寫入資料失敗";
}
}
//........................................................................
//.............................串列埠.......................................
void Widget::InitPort()
{
mySerial = new QSerialPort(this);
foreach (const QSerialPortInfo&info,QSerialPortInfo::availablePorts())
{
QSerialPort serial;
serial.setPort(info);
//串列埠每開啟一次就要close一次,不然下次打不開。
if(serial.open(QIODevice::ReadWrite))
{
ui->ComBC->addItem(info.portName());
serial.close();
}
}
QStringList baudList;//波特率
baudList<<"115200"<<"57600"<<"38400"<<"19200"<<"9600"<< "4800"<<"2400"<<"1200";
ui->BaudCB->addItems(baudList);
QStringList dataBitsList;
dataBitsList<<"8"<<"7"<<"6"<<"5";
ui->DataBitsCB->addItems(dataBitsList);
QStringList parityList;
parityList<<"無校驗"<<"奇校驗"<<"偶校驗";
ui->ParityCB->addItems(parityList);
QStringList stopBitsList;
stopBitsList<<"1"<<"1.5"<<"2";
ui->StopCB->addItems(stopBitsList);
QStringList setFlowCtrl;
setFlowCtrl<<"off"<<"RTS/CTS"<<"XON/XOFF";
ui->FlowsCB->addItems(setFlowCtrl);
//ui->SendBtn->setEnabled(false);
}
void Widget::on_ConnectBtn_clicked()
{
if(ui->ConnectBtn->text()=="串列埠連線")
{
mySerial->setPortName(ui->ComBC->currentText());
bool openSerial= mySerial->open(QIODevice::ReadWrite);
if(openSerial)
{
//設定波特率
if ( ui->BaudCB->currentText()=="115200")
{
mySerial->setBaudRate(QSerialPort::Baud115200);
}
//qDebug()<<"115200";
else if ( ui->BaudCB->currentText()==" 9600")
{
mySerial->setBaudRate(QSerialPort::Baud9600);
}
else if ( ui->BaudCB->currentText()==" 1200")
{
mySerial->setBaudRate(QSerialPort::Baud1200);
}
else if ( ui->BaudCB->currentText()==" 2400")
{
mySerial->setBaudRate(QSerialPort::Baud2400);
}
else if ( ui->BaudCB->currentText()==" 4800")
{
mySerial->setBaudRate(QSerialPort::Baud4800);
}
else if ( ui->BaudCB->currentText()==" 19200")
{
mySerial->setBaudRate(QSerialPort::Baud19200);
}
else if ( ui->BaudCB->currentText()==" 38400")
{
mySerial->setBaudRate(QSerialPort::Baud38400);
}
else if ( ui->BaudCB->currentText()==" 57600")
{
mySerial->setBaudRate(QSerialPort::Baud57600);
}
//設定資料位
if (ui->DataBitsCB->currentText()=="8")
mySerial->setDataBits(QSerialPort::Data8);
else if (ui->DataBitsCB->currentText()=="7")
mySerial->setDataBits(QSerialPort::Data7);
else if (ui->DataBitsCB->currentText()=="6")
mySerial->setDataBits(QSerialPort::Data6);
else if (ui->DataBitsCB->currentText()=="5")
mySerial->setDataBits(QSerialPort::Data5);
//設定校驗位
if (ui->ParityCB->currentText()=="0")
mySerial->setParity(QSerialPort::NoParity);
else if (ui->ParityCB->currentText()=="2")
mySerial->setParity(QSerialPort::EvenParity);
else if (ui->ParityCB->currentText()=="3")
mySerial->setParity(QSerialPort::OddParity);
//停止位
if (ui->StopCB->currentText()=="1")
mySerial->setStopBits(QSerialPort::OneStop);
else if (ui->StopCB->currentText()=="3")
mySerial->setStopBits(QSerialPort::OneAndHalfStop);
else if (ui->StopCB->currentText()=="2")
mySerial->setStopBits(QSerialPort::TwoStop);
//流控制
if (ui->FlowsCB->currentText()=="0")
mySerial->setFlowControl(QSerialPort::NoFlowControl);
else if (ui->FlowsCB->currentText()=="1")
mySerial->setFlowControl(QSerialPort::HardwareControl);
else if (ui->FlowsCB->currentText()=="2")
mySerial->setFlowControl(QSerialPort::SoftwareControl);
}
connect(mySerial,SIGNAL(readyRead()),this,SLOT(doProcessSerialRead()));
ui->ConnectBtn->setText("串列埠關閉");
ui->BaudCB->setEnabled(false);
ui->DataBitsCB->setEnabled(false);
ui->FlowsCB->setEnabled(false);
ui->ParityCB->setEnabled(false);
ui->StopCB->setEnabled(false);
ui->ComBC->setEnabled(false);
}
else if(ui->ConnectBtn->text()=="串列埠關閉")
{
mySerial->close();
ui->ConnectBtn->setText("串列埠連線");
ui->BaudCB->setEnabled(true);
ui->DataBitsCB->setEnabled(true);
ui->FlowsCB->setEnabled(true);
ui->ParityCB->setEnabled(true);
ui->StopCB->setEnabled(true);
ui->ComBC->setEnabled(true);
}
}
//讀取串列埠的資料
void Widget::doProcessSerialRead()
{
readComDataMsg = mySerial->readAll();
QString str=QString::fromLocal8Bit(readComDataMsg);
QString strTemp=str.replace(QString("\r\n"),QString(" "));
ui->textEdit_Servce->append(strTemp);
//ui->textEdit_Servce->setText(readComDataMsg);
// }
doProcessTcpWrite();
// readComData.clear();
}
//void Widget::on_SendBtn_clicked()
//{
// //QString serialTemp=ui->textEdit_Client->toPlainText();
// QString serialTemp="log versionb ontime 1\r\n";
// //QString serialTemp="log gpgga ontime 1 \r\n";
// //qDebug()<<serialTemp;
// int ret= mySerial->write(serialTemp.toLatin1());
// qDebug()<<ret;
// qDebug()<<serialTemp;
// if(ret<0)
// {
// qDebug()<<ret;
// }
//}
void Widget::on_ClearBtn_clicked()
{
ui->textEdit_Servce->clear();
}
//向串列埠寫入資料
void Widget::doProcessWrite()
{
if(!tempStr.isEmpty())
{
//qDebug()<<"向串列埠寫入資料正確";
char *ch=tempStr.data();
int ret= mySerial->write(ch);
if(ret<0)
{
return;
}
}
else{
//qDebug()<<"向串列埠寫入資料錯誤";
return;
}
QString str=QString::fromLocal8Bit(tempStr);
QString strReplace= str.replace(QString("\r\n"),QString(""));
if(!strReplace.isEmpty())
{
ui->textEdit_Client->append(strReplace);
qDebug()<<strReplace;
}
else {
return;
}
tempStr.clear();
}
//重新整理串列埠
void Widget::on_CheckBtn_clicked()
{
ui->ComBC->clear();
foreach (const QSerialPortInfo&info,QSerialPortInfo::availablePorts())
{
QSerialPort serial;
serial.setPort(info);
if(serial.open(QIODevice::ReadWrite))
{
ui->ComBC->addItem(info.portName());
serial.close();
}
}
}
程式碼思路梳理:從伺服器獲取位元組流儲存在tempStr全域性變數中,然後寫入到串列埠,從串列埠中獲取的資料儲存在readComDataMsg全域性變數中,寫入到伺服器和在介面上顯示。
繼續優化的問題:
1.進行大量串列埠資料的轉發,執行一天軟體正常執行,資料轉發正常,可以優化成多執行緒間通訊,拓展知識。
2.doProcessWrite()/doProcessTcpWrite()這兩個函式時直接呼叫的,應該使用Qt的風格,用emit傳送訊號,使用訊號和槽函式模式。
歡迎有問題的小夥伴或者對程式碼有見解的,多多交流哦。