1. 程式人生 > >串列埠資料通過Tcp轉到伺服器實現資料轉發

串列埠資料通過Tcp轉到伺服器實現資料轉發

主要目的:通過串列埠獲取外設的資料,轉發到伺服器進行處理並在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傳送訊號,使用訊號和槽函式模式。

       歡迎有問題的小夥伴或者對程式碼有見解的,多多交流哦。