diff --git a/applications/emsConfigurer/emsConfigurer.pro b/applications/emsConfigurer/emsConfigurer.pro index 1b92ed0..31ce512 100644 --- a/applications/emsConfigurer/emsConfigurer.pro +++ b/applications/emsConfigurer/emsConfigurer.pro @@ -97,7 +97,10 @@ HEADERS += \ mysqlutils.h \ mytablemodel.h \ singleton.h \ - ziputils.h + ziputils.h \ + hv_tcpclient.h \ + kdefine.h \ + frame_define.h FORMS += \ formserialportsettingdialog.ui \ diff --git a/applications/emsConfigurer/frame_define.h b/applications/emsConfigurer/frame_define.h new file mode 100644 index 0000000..bf26eed --- /dev/null +++ b/applications/emsConfigurer/frame_define.h @@ -0,0 +1,55 @@ +#pragma once +#pragma pack(1) + +#include "kdefine.h" + +__NAMESPACE_BEGIN__(HJ) + +#define FRAME_HEADER_LENGTH (5) +#define FRAME_TAILE_LENGTH (4) + +typedef enum tagErrorCode : unsigned char +{ + ERR_OK = 0X00, + ERR_INVALID_LEN = 0X01, + ERR_INVALID_UTF8 = 0X02, + ERR_INVALID_BUF_LEN = 0X03, + ERR_INVALID_JSON_FMT = 0X04, + ERR_INVALID_FSUCODE = 0X05, + ERR_UNKOWN = 0XFF +}ErrorCode; + +typedef enum tagFrameType : unsigned char +{ + Frame_Response = 0x00, //返回帧 + Frame_Request = 0x01, //请求帧 + Frame_Echo_Request = 0x02, //测试请求帧 + Frame_DeviceData_Request = 0x03, //来自采集程序的数据请求包,将数据保存到数据库中 +}FrameType; + +typedef struct tagFrameTail +{ + unsigned char frame_delimiter[4] = { 0xEE,0xFF,0xEE,0xFF }; +}FrameTail; + +typedef struct tagFrame +{ + FrameType frame_type; //帧类型 + unsigned int frame_len; //帧数据长度 + unsigned char frame_content[1]; //帧的内容,实际应为json字符串,由json内容自解释 + tagFrame() + { + frame_type = Frame_Response; + frame_len = 1; + frame_content[0] = ERR_OK; + } + void setErrorFrame(ErrorCode err = ERR_OK) + { + frame_len = 1; + frame_content[0] = err; + } +}MessageFrame; + +__NAMESPACE_END__(HJ) + +#pragma pack() \ No newline at end of file diff --git a/applications/emsConfigurer/globalparameters.cpp b/applications/emsConfigurer/globalparameters.cpp index b7ad80c..fd129d2 100644 --- a/applications/emsConfigurer/globalparameters.cpp +++ b/applications/emsConfigurer/globalparameters.cpp @@ -7,8 +7,11 @@ #include #include +#include + #include "globalparameters.h" #include "mytablemodel.h" +#include "kutilities.h" AppData::~AppData() { @@ -67,7 +70,8 @@ void AppCommon::InitializeTableView(MyTableModel *model, QTableView *tableView) pHeaderView->setFont(QFont("Arial", 12)); // 璁剧疆琛ㄥご鍒楀鑷姩璋冩暣 - for (int i = 0; i < model->columnCount(); ++i) { + for (int i = 0; i < model->columnCount(); ++i) + { pHeaderView->setSectionResizeMode(i, QHeaderView::Stretch); } @@ -112,3 +116,69 @@ CWaitorCursor::~CWaitorCursor() { QApplication::restoreOverrideCursor(); } + +/////////////////////////////////////////////////// +/// \brief AppTcpClient +/// +/// + +AppTcpClient::~AppTcpClient() +{ + if (m_tcpclient) + { + m_tcpclient->stop(); + delete m_tcpclient; + } +} + +AppTcpClient::AppTcpClient(token) + :m_tcpclient(nullptr), m_connfd(0) +{ +} + +void onMessage(const hv::SocketChannelPtr& channel, hv::Buffer* buf); + + +int AppTcpClient::Initialize(QString remote_host, int remote_port) +{ + using namespace hv; + + if (!m_tcpclient || !m_tcpclient->isConnected()) + { + if (m_tcpclient) + { + m_tcpclient->stop(); + delete m_tcpclient; + } + + m_tcpclient = new hv::TcpClient(); + m_connfd = m_tcpclient->createsocket(remote_port, remote_host.toStdString().c_str()); + if (m_connfd < 0) + { + return -20; + } + + m_tcpclient->onMessage = onMessage; + + //m_tcpclient.onMessage = [](const SocketChannelPtr& channel, Buffer* buf) + //{ + // hlogi("<==\n%s", Kutilities::printHex((void*)buf->data(),(int)buf->size()).c_str()); + //}; + + reconn_setting_t reconn; + reconn_setting_init(&reconn); + reconn.min_delay = 1000; + reconn.max_delay = 10000; + reconn.delay_policy = 2; + //reconn.max_retry_cnt = 50; + m_tcpclient->setReconnect(&reconn); + + m_tcpclient->start(); + } + return m_connfd; +} + +void onMessage(const hv::SocketChannelPtr& channel, hv::Buffer* buf) +{ + hlogi("<==\n%s", Kutilities::printHex((void*)buf->data(),(int)buf->size()).c_str()); +} diff --git a/applications/emsConfigurer/globalparameters.h b/applications/emsConfigurer/globalparameters.h index 571c223..595ca85 100644 --- a/applications/emsConfigurer/globalparameters.h +++ b/applications/emsConfigurer/globalparameters.h @@ -5,6 +5,9 @@ #include #include "singleton.h" +#include "hv_tcpclient.h" + +#define DEVICE_SERVER_PORT (44242) class QAbstractTableModel; class QTableView; @@ -131,4 +134,21 @@ public: void InitializeTableView(MyTableModel* model,QTableView* tableView); }; + +class AppTcpClient:public Singleton +{ +public: + AppTcpClient(token); + ~AppTcpClient(); + + AppTcpClient(const AppTcpClient&)=delete; + AppTcpClient& operator =(const AppTcpClient&)= delete; + + int Initialize(QString remote_host, int remote_port=DEVICE_SERVER_PORT); + +public: + hv::TcpClient* m_tcpclient; + int m_connfd; +}; + #endif // GLOBALPARAMETERS_H diff --git a/applications/emsConfigurer/hv_tcpclient.h b/applications/emsConfigurer/hv_tcpclient.h new file mode 100644 index 0000000..3d8fabd --- /dev/null +++ b/applications/emsConfigurer/hv_tcpclient.h @@ -0,0 +1,376 @@ +#ifndef HV_TCP_CLIENT_HPP_ +#define HV_TCP_CLIENT_HPP_ + +#include +#include +#include + +#include +#include + +namespace hv +{ + +template +class TcpClientEventLoopTmpl +{ +public: + typedef std::shared_ptr TSocketChannelPtr; + + TcpClientEventLoopTmpl(EventLoopPtr loop = NULL) + { + loop_ = loop ? loop : std::make_shared(); + remote_port = 0; + connect_timeout = HIO_DEFAULT_CONNECT_TIMEOUT; + tls = false; + tls_setting = NULL; + reconn_setting = NULL; + unpack_setting = NULL; + } + + virtual ~TcpClientEventLoopTmpl() + { + HV_FREE(tls_setting); + HV_FREE(reconn_setting); + HV_FREE(unpack_setting); + } + + const EventLoopPtr& loop() + { + return loop_; + } + + // delete thread-safe + void deleteInLoop() + { + loop_->runInLoop([this]() + { + delete this; + }); + } + + // NOTE: By default, not bind local port. If necessary, you can call bind() after createsocket(). + // @retval >=0 connfd, <0 error + int createsocket(int remote_port, const char* remote_host = "127.0.0.1") + { + memset(&remote_addr, 0, sizeof(remote_addr)); + int ret = sockaddr_set_ipport(&remote_addr, remote_host, remote_port); + if (ret != 0) + { + return NABS(ret); + } + this->remote_host = remote_host; + this->remote_port = remote_port; + return createsocket(&remote_addr.sa); + } + + int createsocket(struct sockaddr* remote_addr) + { + int connfd = ::socket(remote_addr->sa_family, SOCK_STREAM, 0); + // SOCKADDR_PRINT(remote_addr); + if (connfd < 0) + { + perror("socket"); + return -2; + } + + hio_t* io = hio_get(loop_->loop(), connfd); + assert(io != NULL); + hio_set_peeraddr(io, remote_addr, SOCKADDR_LEN(remote_addr)); + channel = std::make_shared(io); + return connfd; + } + + int bind(int local_port, const char* local_host = "0.0.0.0") + { + sockaddr_u local_addr; + memset(&local_addr, 0, sizeof(local_addr)); + int ret = sockaddr_set_ipport(&local_addr, local_host, local_port); + if (ret != 0) + { + return NABS(ret); + } + return bind(&local_addr.sa); + } + + int bind(struct sockaddr* local_addr) + { + if (channel == NULL || channel->isClosed()) + { + return -1; + } + int ret = ::bind(channel->fd(), local_addr, SOCKADDR_LEN(local_addr)); + if (ret != 0) + { + perror("bind"); + } + return ret; + } + + // closesocket thread-safe + void closesocket() + { + if (channel && channel->status != SocketChannel::CLOSED) + { + loop_->runInLoop([this]() + { + if (channel) + { + setReconnect(NULL); + channel->close(); + } + }); + } + } + + int startConnect() + { + if (channel == NULL || channel->isClosed()) + { + int connfd = createsocket(&remote_addr.sa); + if (connfd < 0) + { + hloge("createsocket %s:%d return %d!\n", remote_host.c_str(), remote_port, connfd); + return connfd; + } + } + if (channel == NULL || channel->status >= SocketChannel::CONNECTING) + { + return -1; + } + if (connect_timeout) + { + channel->setConnectTimeout(connect_timeout); + } + if (tls) + { + channel->enableSSL(); + if (tls_setting) + { + int ret = channel->newSslCtx(tls_setting); + if (ret != 0) + { + hloge("new SSL_CTX failed: %d", ret); + closesocket(); + return ret; + } + } + if (!is_ipaddr(remote_host.c_str())) + { + channel->setHostname(remote_host); + } + } + channel->onconnect = [this]() + { + if (unpack_setting) + { + channel->setUnpack(unpack_setting); + } + channel->startRead(); + if (onConnection) + { + onConnection(channel); + } + if (reconn_setting) + { + reconn_setting_reset(reconn_setting); + } + }; + channel->onread = [this](Buffer* buf) + { + if (onMessage) + { + onMessage(channel, buf); + } + }; + channel->onwrite = [this](Buffer* buf) + { + if (onWriteComplete) + { + onWriteComplete(channel, buf); + } + }; + channel->onclose = [this]() + { + bool reconnect = reconn_setting != NULL; + if (onConnection) + { + onConnection(channel); + } + if (reconnect) + { + startReconnect(); + } + }; + return channel->startConnect(); + } + + int startReconnect() + { + if (!reconn_setting) return -1; + if (!reconn_setting_can_retry(reconn_setting)) return -2; + uint32_t delay = reconn_setting_calc_delay(reconn_setting); + hlogi("reconnect... cnt=%d, delay=%d", reconn_setting->cur_retry_cnt, reconn_setting->cur_delay); + loop_->setTimeout(delay, [this](TimerID timerID) + { + startConnect(); + }); + return 0; + } + + // start thread-safe + void start() + { + loop_->runInLoop(std::bind(&TcpClientEventLoopTmpl::startConnect, this)); + } + + bool isConnected() + { + if (channel == NULL) return false; + return channel->isConnected(); + } + + // send thread-safe + int send(const void* data, int size) + { + if (!isConnected()) return -1; + return channel->write(data, size); + } + int send(Buffer* buf) + { + return send(buf->data(), buf->size()); + } + int send(const std::string& str) + { + return send(str.data(), str.size()); + } + + int withTLS(hssl_ctx_opt_t* opt = NULL) + { + tls = true; + if (opt) + { + if (tls_setting == NULL) + { + HV_ALLOC_SIZEOF(tls_setting); + } + opt->endpoint = HSSL_CLIENT; + *tls_setting = *opt; + } + return 0; + } + + void setConnectTimeout(int ms) + { + connect_timeout = ms; + } + + void setReconnect(reconn_setting_t* setting) + { + if (setting == NULL) + { + HV_FREE(reconn_setting); + return; + } + if (reconn_setting == NULL) + { + HV_ALLOC_SIZEOF(reconn_setting); + } + *reconn_setting = *setting; + } + bool isReconnect() + { + return reconn_setting && reconn_setting->cur_retry_cnt > 0; + } + + void setUnpack(unpack_setting_t* setting) + { + if (setting == NULL) + { + HV_FREE(unpack_setting); + return; + } + if (unpack_setting == NULL) + { + HV_ALLOC_SIZEOF(unpack_setting); + } + *unpack_setting = *setting; + } + +public: + TSocketChannelPtr channel; + + std::string remote_host; + int remote_port; + sockaddr_u remote_addr; + int connect_timeout; + bool tls; + hssl_ctx_opt_t* tls_setting; + reconn_setting_t* reconn_setting; + unpack_setting_t* unpack_setting; + + // Callback + std::function onConnection; + std::function onMessage; + // NOTE: Use Channel::isWriteComplete in onWriteComplete callback to determine whether all data has been written. + std::function onWriteComplete; + +private: + EventLoopPtr loop_; +}; + +template +class TcpClientTmpl : private EventLoopThread, public TcpClientEventLoopTmpl +{ +public: + TcpClientTmpl(EventLoopPtr loop = NULL) + : EventLoopThread(loop) + , TcpClientEventLoopTmpl(EventLoopThread::loop()) + , is_loop_owner(loop == NULL) + {} + virtual ~TcpClientTmpl() + { + stop(true); + } + + const EventLoopPtr& loop() + { + return EventLoopThread::loop(); + } + + // start thread-safe + void start(bool wait_threads_started = true) + { + if (isRunning()) + { + TcpClientEventLoopTmpl::start(); + } + else + { + EventLoopThread::start(wait_threads_started, [this]() + { + TcpClientTmpl::startConnect(); + return 0; + }); + } + } + + // stop thread-safe + void stop(bool wait_threads_stopped = true) + { + TcpClientEventLoopTmpl::closesocket(); + if (is_loop_owner) + { + EventLoopThread::stop(wait_threads_stopped); + } + } + +private: + bool is_loop_owner; +}; + +typedef TcpClientTmpl TcpClient; + +} + +#endif // HV_TCP_CLIENT_HPP_ diff --git a/applications/emsConfigurer/kdefine.h b/applications/emsConfigurer/kdefine.h new file mode 100644 index 0000000..5ab3434 --- /dev/null +++ b/applications/emsConfigurer/kdefine.h @@ -0,0 +1,41 @@ +#ifndef __KDEFINE_INCLUDE__ +#define __KDEFINE_INCLUDE__ + +#define K22_STR_EXP(__A) #__A +#define K22_STR(__A) K22_STR_EXP(__A) +#define K22_STRW_EXP(__A) L ## #__A +#define K22_STRW(__A) K22_STRW_EXP(__A) + +#define K22_CMS_VERSION_MAJOR 1 +#define K22_CMS_VERSION_MINOR 215 +#define K22_CMS_VERSION_REVISION 0 +#define K22_VERSION K22_STR(K22_CMS_VERSION_MAJOR) "." K22_STR(K22_CMS_VERSION_MINOR) "." K22_STR(K22_CMS_VERSION_REVISION) "" + +#ifdef __cplusplus + +# ifndef EXTERN_C +# define EXTERN_C extern "C" +# endif + +# ifndef BEGIN_EXTERN_C +# define BEGIN_EXTERN_C extern "C" { +# endif + +# ifndef END_EXTERN_C +# define END_EXTERN_C } // extern "C" +# endif + +#else + +# define EXTERN_C extern +# define BEGIN_EXTERN_C +# define END_EXTERN_C + +#endif // __cplusplus + +#define __NAMESPACE_BEGIN__(X) namespace X { +#define __NAMESPACE_END__(X) } +#define __USING_NAMESPACE__(X) using namespace X +#define __USING_NAMESPACE_HJ__ using namespace HJ + +#endif //__KDEFINE_INCLUDE__ diff --git a/applications/emsConfigurer/main.cpp b/applications/emsConfigurer/main.cpp index 5937f83..7ee9029 100644 --- a/applications/emsConfigurer/main.cpp +++ b/applications/emsConfigurer/main.cpp @@ -38,6 +38,8 @@ int main(int argc, char *argv[]) std::string logFilePath = (appDir + QString::fromStdString("/emsConfigurer.log")).toStdString(); hlog_set_file(logFilePath.c_str()); + hlog_set_level_by_str("DEBUG"); + hlogi("=========--- Welcome to the Earth ---========="); hlogi("%s version: %s", argv[0], "1.1.0"); hlog_fsync(); diff --git a/applications/emsConfigurer/mainwindow.cpp b/applications/emsConfigurer/mainwindow.cpp index 403faf4..a7c5100 100644 --- a/applications/emsConfigurer/mainwindow.cpp +++ b/applications/emsConfigurer/mainwindow.cpp @@ -9,6 +9,7 @@ #include "MainDialog.h" #include "mysqlutils.h" + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) @@ -28,8 +29,8 @@ MainWindow::MainWindow(QWidget *parent) QRegularExpression rx("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$"); QRegularExpressionValidator* ipValidator = new QRegularExpressionValidator(rx, this); ui->serverIp->setValidator(ipValidator); - //setIp("127.0.0.1"); - setIp("192.168.0.155"); + setIp("127.0.0.1"); + //setIp("192.168.0.155"); } MainWindow::~MainWindow() @@ -55,6 +56,7 @@ bool MainWindow::testDatabase() int dbport = 3306; std::string dbuser = "root"; std::string dbpasswd = "Hj57471000"; + //std::string dbpasswd = "L2ysc1s1kr"; std::string dbname = "hjems"; bool dbok = MysqlUtils::getInstance()->OpenDatabase(dbserver,dbport,dbuser,dbpasswd,dbname); if (!dbok) @@ -67,9 +69,31 @@ bool MainWindow::testDatabase() return true; } +bool MainWindow::testServerEcho() +{ + using namespace hv; + + QString svr = ui->serverIp->text(); + + int connfd = AppTcpClient::getInstance()->Initialize("127.0.0.1",DEVICE_SERVER_PORT); + if (connfd <= 0) + { + hloge("failed to connect to device data service ..."); + return false; + } + + hlogi("connect to device data service port %d, connfd=%d ...", DEVICE_SERVER_PORT, connfd); + + unsigned char frame[10] = { 0x02, 0x01,0x00,0x00,0x00, 0x00,0xEE,0xFF,0xEE,0xFF}; + int cnt = AppTcpClient::getInstance()->m_tcpclient->send((void*)frame,10); + hlogd("send %d bytes, connfd=%d ...", cnt, connfd); + + return cnt > 0 ? true : false; +} + void MainWindow::on_pb_Logon_clicked() { - if (testDatabase()) + if (testDatabase() && testServerEcho()) { m_pMainDialog = new MainDialog(); m_pMainDialog->show(); @@ -85,8 +109,14 @@ void MainWindow::on_pb_Logon_clicked() void MainWindow::on_pb_Test_clicked() { if (testDatabase()) - QMessageBox::information(this, tr("Successfully"),tr("Connect to device successfully!")); + QMessageBox::information(this, tr("Successfully"),tr("Connect to device database successfully!")); else - QMessageBox::critical(this, tr("Critical Message"),tr("Failed to connect to device!")); + QMessageBox::critical(this, tr("Critical Message"),tr("Failed to connect to device database!")); + + //娴嬭瘯涓庤澶囩鎺ユ敹鏈嶅姟鐨勮繛鎺 + if (testServerEcho()) + QMessageBox::information(this, tr("Successfully"),tr("Connect to device data service successfully!")); + else + QMessageBox::critical(this, tr("Critical Message"),tr("Failed to connect to device data service!")); } diff --git a/applications/emsConfigurer/mainwindow.h b/applications/emsConfigurer/mainwindow.h index ebda528..97a2d4b 100644 --- a/applications/emsConfigurer/mainwindow.h +++ b/applications/emsConfigurer/mainwindow.h @@ -24,6 +24,7 @@ public: protected: void setIp(const QString &ip); bool testDatabase(); + bool testServerEcho(); //娴嬭瘯鍚庣鏈嶅姟鍣ㄥ搷搴 private slots: void on_pb_Logon_clicked();