mirror of
https://gitee.com/js-yhsec/energy_storage.git
synced 2026-05-27 18:59:26 +08:00
完成系统管理web端功能,实现系统管理服务端接口,实现登录功能
This commit is contained in:
28
src/protocol/Communicator.cpp
Normal file
28
src/protocol/Communicator.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "Communicator.h"
|
||||
#include "TcpEntity.h"
|
||||
|
||||
std::shared_ptr<CommEntity> Communicator::createEntity(DataFields& data)
|
||||
{
|
||||
std::string commType = data.getStr("commType");
|
||||
std::string ip = data.getStr("ip");
|
||||
int port = data.getInt("port");
|
||||
int isclient = data.getInt("isclient");
|
||||
|
||||
if (commType == "TCP")
|
||||
{
|
||||
auto entity = std::make_shared<TcpEntity>();
|
||||
entity->setHost(ip, port, isclient);
|
||||
return entity;
|
||||
}
|
||||
else if (commType == "MODBUS")
|
||||
{
|
||||
}
|
||||
else if (commType == "ACTIVEX")
|
||||
{
|
||||
}
|
||||
else if (commType == "SDK")
|
||||
{
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
39
src/protocol/Communicator.h
Normal file
39
src/protocol/Communicator.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "common/DataFields.h"
|
||||
|
||||
class CommEntity
|
||||
{
|
||||
public:
|
||||
CommEntity() {}
|
||||
CommEntity(std::string type) : type(type) {}
|
||||
|
||||
void setType(std::string type) { this->type = type; }
|
||||
|
||||
// 启动通讯连接
|
||||
virtual int start() { return 0; };
|
||||
// 关闭通讯连接
|
||||
virtual void close() { isCloseRequest_ = true; };
|
||||
|
||||
std::string id() { return id_; }
|
||||
|
||||
bool isAlive() { return isAlive_; }
|
||||
bool isConnected() { return isConnected_; }
|
||||
|
||||
public:
|
||||
std::string id_;
|
||||
bool isAlive_ = false;
|
||||
bool isConnected_ = false;
|
||||
bool isCloseRequest_ = false;
|
||||
std::string type;
|
||||
};
|
||||
|
||||
|
||||
class Communicator
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<CommEntity> createEntity(DataFields& data);
|
||||
};
|
||||
281
src/protocol/TcpEntity.cpp
Normal file
281
src/protocol/TcpEntity.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
#include "TcpEntity.h"
|
||||
#include "common/Utils.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
static std::string ToHexText(std::string s)
|
||||
{
|
||||
std::stringstream ss;
|
||||
for (unsigned int i = 0; i < s.size(); ++i)
|
||||
{
|
||||
unsigned char ch = s[i];
|
||||
ss << std::setw(2) << std::setfill('0') << std::hex << std::uppercase << (int)ch << ((i < s.size() - 1) ? " " : "");
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
TcpEntity::TcpEntity(TcpHandler* handler)
|
||||
: handler_(handler), isClient_(true)
|
||||
{
|
||||
}
|
||||
|
||||
TcpEntity::~TcpEntity()
|
||||
{
|
||||
}
|
||||
|
||||
void TcpEntity::setHandler(TcpHandler* handler)
|
||||
{
|
||||
handler_ = handler;
|
||||
}
|
||||
|
||||
void TcpEntity::setHost(string host, int port, bool isClient)
|
||||
{
|
||||
host_ = host;
|
||||
port_ = port;
|
||||
isClient_ = isClient;
|
||||
}
|
||||
|
||||
|
||||
void TcpEntity::setReconnect(int ms)
|
||||
{
|
||||
tReconnect_ = ms;
|
||||
}
|
||||
|
||||
int TcpEntity::start()
|
||||
{
|
||||
if (isAlive_)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
isAlive_ = true;
|
||||
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sockaddr_.sin_family = AF_INET;
|
||||
sockaddr_.sin_port = htons(port_);
|
||||
sockaddr_.sin_addr.S_un.S_addr = (isClient_ ? inet_addr(host_.c_str()) : htonl(INADDR_ANY));
|
||||
|
||||
std::thread([=]() { this->runThreadTcp(); }).detach();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TcpEntity::runThreadTcp()
|
||||
{
|
||||
//if (isRequestClose_) { break; }
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
|
||||
std::cout << "TCP thread start ..." << std::endl;
|
||||
if (isClient_)
|
||||
{
|
||||
this->runClientLoop();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->runServerLoop();
|
||||
}
|
||||
isAlive_ = false;
|
||||
}
|
||||
|
||||
void TcpEntity::close()
|
||||
{
|
||||
isCloseRequest_ = true;
|
||||
}
|
||||
|
||||
void TcpEntity::runServerLoop()
|
||||
{
|
||||
sock_ = ::socket(AF_INET, SOCK_STREAM, 0);
|
||||
// 绑定套接字 【注意】functional中定义了bind与winsock2的定义发生重载导致异常,这里需要使用::bind(加::)
|
||||
if (::bind(sock_, (SOCKADDR*)&sockaddr_, sizeof(SOCKADDR)) == SOCKET_ERROR)
|
||||
{
|
||||
std::cout << "TCP server bind [" << hostport() << "] failed." << std::endl;
|
||||
return;
|
||||
}
|
||||
// 启动监听,准备接收客户请求
|
||||
if (::listen(sock_, 5) == SOCKET_ERROR)
|
||||
{
|
||||
std::cout << "TCP server listen [" << hostport() << "] failed." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
int addrlen = sizeof(SOCKADDR);
|
||||
while (1)
|
||||
{
|
||||
if (isCloseRequest_) { break; }
|
||||
|
||||
Client client;
|
||||
|
||||
// 等待客户请求到来
|
||||
client.sock = ::accept(sock_, (SOCKADDR*)&client.sock_addr, &addrlen);
|
||||
if (client.sock == INVALID_SOCKET)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
client.host = inet_ntoa(client.sock_addr.sin_addr);
|
||||
|
||||
// 存储客户端的连接信息
|
||||
vecClient_.push_back(client);
|
||||
|
||||
// 创建线程处理
|
||||
std::thread th([=]() { this->runServerRecvLoop(client, client.host); });
|
||||
th.detach();
|
||||
}
|
||||
::closesocket(sock_);
|
||||
|
||||
// 连接关闭
|
||||
for (auto iter = vecClient_.begin(); iter != vecClient_.end(); ++iter)
|
||||
{
|
||||
::closesocket(iter->sock);
|
||||
vecClient_.erase(iter);
|
||||
}
|
||||
isCloseRequest_ = false;
|
||||
}
|
||||
|
||||
void TcpEntity::runServerRecvLoop(Client client, std::string client_name)
|
||||
{
|
||||
std::vector<char> buf(1024000, 0);
|
||||
while (1)
|
||||
{
|
||||
if (isCloseRequest_ || !isAlive_)
|
||||
{
|
||||
break;
|
||||
}
|
||||
memset(buf.data(), 0, buf.size());
|
||||
// 接收数据
|
||||
int n = ::recv(client.sock, &buf[0], buf.size(), 0);
|
||||
// 需要判断 errno是否等于 EINTR 。如果errno == EINTR 则说明recv函数是由于程序接收到信号后返回的,socket连接还是正常的
|
||||
if (n <= 0 && GetLastError() != EINTR)
|
||||
{
|
||||
// 客户端连接异常(关闭)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
// 连接关闭
|
||||
for (auto iter = vecClient_.begin(); iter != vecClient_.end(); ++iter)
|
||||
{
|
||||
if (iter->sock == client.sock)
|
||||
{
|
||||
vecClient_.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TcpEntity::runClientLoop()
|
||||
{
|
||||
// 数据缓存
|
||||
std::vector<char> buf(1024000, 0);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (isCloseRequest_) { break; }
|
||||
|
||||
//创建套接字,向服务器发出连接请求
|
||||
sock_ = ::socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (::connect(sock_, (SOCKADDR*)&sockaddr_, sizeof(SOCKADDR)) != SOCKET_ERROR)
|
||||
{
|
||||
isConnected_ = true;
|
||||
std::cout << "TCP client connect to [" << hostport() << "] success." << std::endl;
|
||||
|
||||
// 连接服务器成功,循环等待接受消息
|
||||
while (1)
|
||||
{
|
||||
if (isCloseRequest_) { break; }
|
||||
|
||||
memset(buf.data(), 0, buf.size());
|
||||
int n = ::recv(sock_, buf.data(), buf.size(), 0);
|
||||
if (n <= 0 && GetLastError() != EINTR)
|
||||
{
|
||||
// TCP通讯异常, 关闭连接
|
||||
::closesocket(sock_);
|
||||
isConnected_ = false;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 处理消息
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isConnected_ = false;
|
||||
std::cout << "TCP client connect to [" << hostport() << "] failed." << std::endl;
|
||||
}
|
||||
|
||||
// 连接异常
|
||||
if (tReconnect_ > 0)
|
||||
{
|
||||
// 重新连接
|
||||
std::cout << "TCP client [" << hostport() << "] reconnect (" << tReconnect_ << ")." << std::endl;
|
||||
//std::this_thread::sleep_for(std::chrono::microseconds(tReconnect_));
|
||||
Sleep(tReconnect_);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 关闭线程
|
||||
std::cout << "TCP client [" << hostport() << "] close." << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sock_ != INVALID_SOCKET)
|
||||
{
|
||||
::closesocket(sock_);
|
||||
sock_ = INVALID_SOCKET;
|
||||
isConnected_ = false;
|
||||
}
|
||||
if (isCloseRequest_)
|
||||
{
|
||||
}
|
||||
isCloseRequest_ = false;
|
||||
}
|
||||
|
||||
bool TcpEntity::sendData(std::string data, std::string clientId)
|
||||
{
|
||||
if (isClient_)
|
||||
{
|
||||
// #客户端
|
||||
if (sock_ == INVALID_SOCKET)
|
||||
{
|
||||
//Spdlogger::error("TCP client send data failed, connect error, invalid socket, device: {}:{}.", this->type_, client_code);
|
||||
return false;
|
||||
}
|
||||
int len = ::send(sock_, data.c_str(), data.size(), 0);
|
||||
//Spdlogger::info("TCP client send data success, data length={}, device: {}:{}.", len, this->type_, client_code);
|
||||
return (len > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vecClient_.size() <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (auto& client : vecClient_)
|
||||
{
|
||||
std::string client_addr = inet_ntoa(client.sock_addr.sin_addr);
|
||||
::send(client.sock, data.c_str(), data.size(), 0);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool TcpEntity::isAlive()
|
||||
{
|
||||
return isAlive_;
|
||||
}
|
||||
|
||||
bool TcpEntity::isConnected()
|
||||
{
|
||||
return isConnected_;
|
||||
}
|
||||
117
src/protocol/TcpEntity.h
Normal file
117
src/protocol/TcpEntity.h
Normal file
@@ -0,0 +1,117 @@
|
||||
#ifndef _TcpEntity_H_
|
||||
#define _TcpEntity_H_
|
||||
|
||||
#include <Winsock2.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
#include "Communicator.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum class ETcpEvent
|
||||
{
|
||||
NUL = 0, //
|
||||
SRV_SUCCESS, // 服务端启动成功(listen成功)
|
||||
ACCEPT, // 服务端接收到客户端的连接
|
||||
CONN_OK, // 作为客户端时,连接成功
|
||||
CONN_ERR, // 作为客户端时,连接失败
|
||||
MSG_RECV, // 接收消息
|
||||
MSG_SEND, // 发送消息
|
||||
CLOSE, // 断开连接
|
||||
ERR // 异常错误
|
||||
};
|
||||
|
||||
class TcpHandler;
|
||||
class TcpParser;
|
||||
|
||||
class TcpEntity : public CommEntity, public std::enable_shared_from_this<TcpEntity>
|
||||
{
|
||||
public:
|
||||
struct Client
|
||||
{
|
||||
SOCKET sock;
|
||||
SOCKADDR_IN sock_addr;
|
||||
std::string host;
|
||||
std::shared_ptr<TcpParser> parser = nullptr;
|
||||
};
|
||||
|
||||
public:
|
||||
// 初始化服务端
|
||||
TcpEntity(TcpHandler* handler = nullptr);
|
||||
~TcpEntity();
|
||||
|
||||
int start() override;
|
||||
void close() override;
|
||||
|
||||
void runThreadTcp();
|
||||
|
||||
void setHost(string host, int port, bool is_client);
|
||||
std::string host() { return host_; }
|
||||
int port() { return port_; }
|
||||
std::string hostport() { return host_ + ":" + std::to_string(port_); }
|
||||
|
||||
void setReconnect(int ms);
|
||||
|
||||
bool isClient() { return isClient_; }
|
||||
|
||||
void setHandler(TcpHandler* handler);
|
||||
|
||||
bool sendData(std::string data, std::string clientId="");
|
||||
|
||||
bool isAlive();
|
||||
bool isConnected();
|
||||
|
||||
|
||||
std::shared_ptr<TcpParser> parser = nullptr;
|
||||
|
||||
private:
|
||||
void runServerLoop();
|
||||
void runServerRecvLoop(Client client, std::string client_name);
|
||||
|
||||
void runClientLoop();
|
||||
|
||||
private:
|
||||
// 本机的SOCKET对象
|
||||
SOCKET sock_ = INVALID_SOCKET;
|
||||
|
||||
// socket addr信息
|
||||
SOCKADDR_IN sockaddr_;
|
||||
|
||||
// TCP类型是否是客户端: true: 客户端, false: 服务端
|
||||
bool isClient_ = true;
|
||||
|
||||
// 通讯地址,作为客户端时有效
|
||||
std::string host_;
|
||||
|
||||
// 通讯端口
|
||||
int port_ = 0;
|
||||
|
||||
// 重连间隔时间,单位秒
|
||||
int tReconnect_ = 0;
|
||||
|
||||
// 作为服务端时连接的客户端SOCKET
|
||||
std::vector<Client> vecClient_;
|
||||
|
||||
// 回调处理对象
|
||||
TcpHandler* handler_ = nullptr;
|
||||
|
||||
bool isAlive_ = false;
|
||||
bool isCloseRequest_ = false;
|
||||
bool isConnected_ = false;
|
||||
|
||||
// 状态更新时间戳
|
||||
int64_t ts_;
|
||||
|
||||
int64_t tsHeartbeat_=0;
|
||||
};
|
||||
|
||||
class TcpHandler
|
||||
{
|
||||
public:
|
||||
virtual void onEvent(TcpEntity* entity, TcpEntity::Client* client, ETcpEvent evt, std::string msg) {};
|
||||
};
|
||||
|
||||
#endif // !_TcpEntity_H_
|
||||
Reference in New Issue
Block a user