Compare commits

...

35 Commits

Author SHA1 Message Date
lingel 3bc7711fe0 ppt最终上传
5 months ago
lingel 4c88920ce1 ppt更改
5 months ago
lingel 28a8bd37af 文档最终上传
5 months ago
lingel 18e64662d3 更改
5 months ago
pzthu8lr3 5e47926b92 Delete 'model/高可用分布式网关管理软件系统--讲解视频.mp4'
5 months ago
ps249eph7 cbaeab7ac4 Merge pull request '前端数据展示' (#33) from xumingyang_branch into master
5 months ago
xmy c9b6e1b156 前端
5 months ago
lyy 0239d9462b 更新数据显示优化组件,更新主备切换操作板
5 months ago
lingel 1608dd75ab 视频上传
5 months ago
lingel 2edd7b08b6 中台最终版上传
5 months ago
pf7astvk4 2d274e7798 Merge pull request '新的主动探测算法' (#32) from dongjiaqi_branch into master
5 months ago
ps249eph7 3f898d4131 Merge pull request '灾备' (#31) from xumingyang_branch into master
5 months ago
xmy 9205ad7e65 灾备
5 months ago
pf7astvk4 2db7937be6 Merge pull request '修正文件路径' (#22) from liuyuyang_branch into master
5 months ago
lingel 08201469c5 Merge branch 'master' of https://bdgit.educoder.net/pf7astvk4/Nginx
5 months ago
lingel fb687b96ef 新的中台处理模块,controller_completed,
5 months ago
pf7astvk4 f05f5ae364 Merge pull request '自评报告' (#29) from dongjiaqi_branch into master
5 months ago
pf7astvk4 25f49838bc Merge pull request '开发文档修改调整' (#28) from dongjiaqi_branch into master
5 months ago
lingel f79a906ee7 11
5 months ago
lyy 2a6320ca9d 11
5 months ago
lyy f411754a28 Merge branch 'master' of https://bdgit.educoder.net/pf7astvk4/Nginx
5 months ago
pf7astvk4 fe1b2cc254 Merge pull request 'try' (#26) from dongjiaqi_branch into master
5 months ago
lyy b6709de6e0 更新全部前端代码
5 months ago
lyy eca93ac7f1 Merge branch 'master' of https://bdgit.educoder.net/pf7astvk4/Nginx
5 months ago
lyy 152bf9a883 修正代码结构
5 months ago
ps249eph7 da16a19c33 Merge pull request '网关灾备' (#18) from xumingyang_branch into master
5 months ago
xmy b21d410226 网关灾备
5 months ago
pzthu8lr3 6933dfb58a Merge pull request '开发内容合并' (#17) from yuankaifeng_branch into master
5 months ago
lingel ea52d2645b 更新
5 months ago
pf7astvk4 e1b86f92f3 Merge pull request '新的补丁文件' (#16) from dongjiaqi_branch into master
5 months ago
ps249eph7 b8c482a8ca Merge pull request '网关灾备' (#15) from xumingyang_branch into master
5 months ago
xmy 68f57b4e5d 网关灾备
5 months ago
lyy 048b544f8e 更新所有前端代码,优化前端显示
5 months ago
lyy d00aa35bbf 更新全部前端代码,优化界面设计
5 months ago
pf7astvk4 abdc2b11b7 Merge pull request '主动探测完整' (#12) from dongjiaqi_branch into master
5 months ago

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

@ -0,0 +1,288 @@
#include <iostream>
#include <thread>
#include <vector>
#include <map>
#include <mutex>
#include <atomic>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>
#define BUFFER_SIZE 1024
#define HTTP_SERVER_PORT 8080
std::vector<std::thread> threads; // 存储所有连接线程
std::map<int, int> sockets; // 存储套接字
std::mutex sockets_mutex; // 用于同步访问 sockets
std::atomic<bool> exit_flag(false); // 原子退出标志
// 维护连接的函数
void KeepConnection(int sock) {
char buffer[BUFFER_SIZE];
int nbytes;
while (!exit_flag) {
nbytes = recv(sock, buffer, BUFFER_SIZE, 0);
if (nbytes <= 0) {
std::cout << "Gateway disconnected" << std::endl;
break;
}
std::cout << "Received from gateway (Socket " << sock << "): " << buffer << std::endl;
}
{
std::lock_guard<std::mutex> lock(sockets_mutex);
sockets.erase(sock); // 从集合中移除套接字
}
close(sock);
}
// 连接到网关的函数
void ConnectToGateway(const std::string& ip, int port) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Could not create socket");
return;
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if (inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr) <= 0) {
perror("Invalid address");
close(sock);
return;
}
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection to the server failed");
close(sock);
return;
}
{
std::lock_guard<std::mutex> lock(sockets_mutex);
sockets[sock] = 1; // 将套接字添加到集合中
}
std::cout << "Connected to gateway at " << ip << ":" << port << " (Socket " << sock << ")" << std::endl;
// 在新线程中维护连接
threads.emplace_back(KeepConnection, sock);
}
// 处理HTTP请求的函数
void HandleHttpRequest(int client_socket) {
char buffer[BUFFER_SIZE];
int bytes_read = recv(client_socket, buffer, sizeof(buffer), 0);
if (bytes_read <= 0) {
close(client_socket);
return;
}
// 简单解析HTTP请求
std::string http_request(buffer, bytes_read);
std::string ip;
int port;
// 寻找IP和端口号
auto host_pos = http_request.find("Host: ");
if (host_pos != std::string::npos) {
auto start = host_pos + std::string("Host: ").size();
ip = http_request.substr(start, http_request.find("\r\n", start) - start);
}
auto content_length_pos = http_request.find("Content-Length:");
if (content_length_pos != std::string::npos) {
auto start = content_length_pos + std::string("Content-Length: ").size();
int length = std::stoi(http_request.substr(start, http_request.find("\r\n", start) - start));
if (length > 0) {
char* content = new char[length];
bytes_read = recv(client_socket, content, length, 0);
if (bytes_read > 0) {
// 解析JSON内容假设前端发送的是JSON格式
// 这里需要添加JSON解析逻辑来提取IP和端口
// 示例:{"ip":"192.168.1.1","port":8080}
// 可以使用第三方库如nlohmann/json来解析JSON
// 假设解析后得到ip和port
// ConnectToGateway(ip, port);
delete[] content;
}
}
}
// 发送HTTP响应
std::string response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n";
send(client_socket, response.c_str(), response.size(), 0);
close(client_socket);
}
// 启动HTTP服务器的函数
void StartHttpServer() {
int http_server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (http_server_socket < 0) {
perror("Could not create HTTP server socket");
return;
}
int opt = 1;
if (setsockopt(http_server_socket, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("Setsockopt failed");
close(http_server_socket);
return;
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(HTTP_SERVER_PORT);
if (bind(http_server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Bind failed");
close(http_server_socket);
return;
}
if (listen(http_server_socket, 5) < 0) {
perror("Listen failed");
close(http_server_socket);
return;
}
std::cout << "HTTP server listening on port " << HTTP_SERVER_PORT << std::endl;
while (!exit_flag) {
int client_socket = accept(http_server_socket, NULL, NULL);
if (client_socket < 0) {
perror("Accept failed");
continue;
}
threads.emplace_back(HandleHttpRequest, client_socket);
}
close(http_server_socket);
}
int main() {
// threads.emplace_back(StartHttpServer);
// std::string command, ip;
// int port;
// bool in_connect_mode = false;
// std::cout << "Enter command (connect/exit): ";
// while (true) {
// if (in_connect_mode)
// {
// std::cout << "continue connect or not ? (y or n) ";
// std::cin >> command;
// if(command=="y"){
// std::cout << "Enter the gateway IP address: ";
// std::cin >> ip;
// std::cout << "Enter the gateway port: ";
// std::cin >> port;
// ConnectToGateway(ip, port);
// }
// else {
// in_connect_mode = false; // 退出连接模式
// std::cout << "Exiting connect mode." << std::endl;
// }
// }
// else{
// std::cout << "Enter command (connect/exit): ";
// std::cin>>command;
// if (command == "connect") {
// if (in_connect_mode) {
// std::cout << "Already in connect mode." << std::endl;
// continue;
// }
// in_connect_mode = true; // 进入连接模式
// std::cout << "Enter the gateway IP address: ";
// std::cin >> ip;
// std::cout << "Enter the gateway port: ";
// std::cin >> port;
// ConnectToGateway(ip, port);
// } else if (command == "exit") {
// exit_flag = true; // 设置退出标志
// std::cout << "Exiting program." << std::endl;
// // 关闭所有套接字
// for (auto& sock_pair : sockets) {
// shutdown(sock_pair.first, SHUT_RDWR); // 关闭套接字的发送和接收
// close(sock_pair.first);
// }
// sockets.clear();
// std::cout << "sockets.clear" << std::endl;
// // 等待所有线程结束
// for (auto& thread : threads) {
// if (thread.joinable()) {
// thread.join();
// }
// }
// threads.clear();
// break; // 退出主循环
// } else {
// std::cout << "Unknown command" << std::endl;
// }
// }
// }
// std::cout<<"out"<<std::endl;
// return 0;
std::thread http_server_thread(StartHttpServer);
std::string command, ip;
int port;
bool in_connect_mode = false;
while (true) {
std::cout << "Enter command (connect/exit): ";
std::cin >> command;
if (command == "connect") {
if (in_connect_mode) {
std::cout << "Already in connect mode." << std::endl;
continue;
}
in_connect_mode = true;
std::cout << "Enter the gateway IP address: ";
std::cin >> ip;
std::cout << "Enter the gateway port: ";
std::cin >> port;
ConnectToGateway(ip, port);
} else if (command == "exit") {
break; // 接收到退出命令,退出主循环
} else {
std::cout << "Unknown command" << std::endl;
}
}
// 设置退出标志
exit_flag = true;
// 强制结束HTTP服务器线程
if (http_server_thread.joinable()) {
http_server_thread.join();
}
// 关闭所有套接字
for (auto& sock_pair : sockets) {
shutdown(sock_pair.first, SHUT_RDWR);
close(sock_pair.first);
}
sockets.clear();
// 等待所有工作线程结束
for (auto& thread : threads) {
if (thread.joinable()) {
thread.join();
}
}
threads.clear();
std::cout << "Exited program." << std::endl;
return 0;
}

@ -0,0 +1,31 @@
#include <iostream>
#include <mysql/mysql.h>
int main() {
MYSQL *conn;
conn = mysql_init(NULL);
if (conn == NULL) {
std::cerr << "MySQL init failed" << std::endl;
return 1;
}
const char *server = "localhost";
const char *user = "rtsw";
const char *password = "123456";
const char *database = "nginxdb";
unsigned int port = 3306; // 使用云数据库提供的端口
if (mysql_real_connect(conn, server, user, password, database, port, NULL, 0) == NULL) {
std::cerr << "Connection error: " << mysql_error(conn) << std::endl;
mysql_close(conn);
return 1;
}
std::cout << "Successfully connected to the database" << std::endl;
// ... 执行数据库操作 ...
mysql_close(conn);
return 0;
}

@ -0,0 +1,86 @@
#include <iostream>
#include <thread>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define MAX_CLIENTS 5
#define BUFFER_SIZE 1024
// 声明 handle_client 函数
void handle_client(int client_socket);
int main() {
int server_fd, new_socket;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[BUFFER_SIZE];
int opt = 1;
// 创建套接字
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// 设置选项,允许重用地址
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt failed");
exit(EXIT_FAILURE);
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
// 绑定
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听
if (listen(server_fd, MAX_CLIENTS) < 0) {
perror("listen failed");
exit(EXIT_FAILURE);
}
std::cout << "Server listening on port " << PORT << std::endl;
while (true) {
client_len = sizeof(client_addr);
new_socket = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);
if (new_socket < 0) {
perror("accept failed");
exit(EXIT_FAILURE);
}
std::cout << "New client connected from " << inet_ntoa(client_addr.sin_addr) << " port " << ntohs(client_addr.sin_port) << std::endl;
// 创建并启动线程处理客户端
std::thread(handle_client, new_socket).detach();
}
close(server_fd);
return 0;
}
// 定义 handle_client 函数
void handle_client(int client_socket) {
while (true) {
char buffer[BUFFER_SIZE];
memset(buffer, 0, BUFFER_SIZE); // 清空缓冲区
int nbytes = read(client_socket, buffer, BUFFER_SIZE);
if (nbytes <= 0) {
std::cout << "Client disconnected." << std::endl;
close(client_socket);
break;
}
std::cout << "Received message from client: " << buffer << std::endl;
// 这里可以添加更多的处理逻辑
}
}

@ -0,0 +1,66 @@
#include <iostream>
#include <mysql/mysql.h>
int main() {
MYSQL *conn;
conn = mysql_init(NULL);
if (conn == NULL) {
std::cerr << "MySQL init failed" << std::endl;
return 1;
}
const char *server = "localhost";
const char *user = "rtsw";
const char *password = "123456";
const char *database = "nginxdb";
unsigned int port = 3306;
if (mysql_real_connect(conn, server, user, password, database, port, NULL, 0) == NULL) {
std::cerr << "Connection error: " << mysql_error(conn) << std::endl;
mysql_close(conn);
return 1;
}
std::cout << "Successfully connected to the database" << std::endl;
// 插入数据
const char *insert_query = "INSERT INTO users (username, email) VALUES ('newuser', 'newuser@example.com')";
if (mysql_query(conn, insert_query)) {
std::cerr << "Insert error: " << mysql_error(conn) << std::endl;
} else {
std::cout << "Insert successful" << std::endl;
}
// 查询数据
const char *select_query = "SELECT * FROM users";
MYSQL_RES *result = mysql_store_result(conn);
if (result) {
MYSQL_ROW row;
while ((row = mysql_fetch_row(result))) {
std::cout << "id: " << row[0] << ", username: " << row[1] << ", email: " << row[2] << std::endl;
}
mysql_free_result(result);
} else {
std::cerr << "Select error: " << mysql_error(conn) << std::endl;
}
// 更新数据
const char *update_query = "UPDATE users SET email = 'newuser_updated@example.com' WHERE username = 'newuser'";
if (mysql_query(conn, update_query)) {
std::cerr << "Update error: " << mysql_error(conn) << std::endl;
} else {
std::cout << "Update successful" << std::endl;
}
// 删除数据
const char *delete_query = "DELETE FROM users WHERE username = 'newuser'";
if (mysql_query(conn, delete_query)) {
std::cerr << "Delete error: " << mysql_error(conn) << std::endl;
} else {
std::cout << "Delete successful" << std::endl;
}
mysql_close(conn);
return 0;
}

@ -0,0 +1,280 @@
#include "connector_controller.h"
#define BUFFER_SIZE 1024
#define HTTP_SERVER_PORT 8080
std::vector<std::thread> threads; // 存储所有连接线程
std::map<int, int> sockets; // 存储套接字
std::mutex sockets_mutex; // 用于同步访问 sockets
std::atomic<bool> exit_flag(false); // 原子退出标志
// 维护连接的函数
void KeepConnection(int sock) {
char buffer[BUFFER_SIZE];
int nbytes;
while (!exit_flag) {
nbytes = recv(sock, buffer, BUFFER_SIZE, 0);
if (nbytes <= 0) {
std::cout << "Gateway disconnected" << std::endl;
break;
}
std::cout << "Received from gateway (Socket " << sock << "): " << buffer << std::endl;
}
{
std::lock_guard<std::mutex> lock(sockets_mutex);
sockets.erase(sock); // 从集合中移除套接字
}
close(sock);
}
// 连接到网关的函数
void ConnectToGateway(const std::string& ip, int port) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Could not create socket");
return;
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if (inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr) <= 0) {
perror("Invalid address");
close(sock);
return;
}
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection to the server failed");
close(sock);
return;
}
{
std::lock_guard<std::mutex> lock(sockets_mutex);
sockets[sock] = 1; // 将套接字添加到集合中
}
std::cout << "Connected to gateway at " << ip << ":" << port << " (Socket " << sock << ")" << std::endl;
// 在新线程中维护连接
threads.emplace_back(KeepConnection, sock);
}
// 处理HTTP请求的函数
void HandleHttpRequest(int client_socket) {
char buffer[BUFFER_SIZE];
int bytes_read = recv(client_socket, buffer, sizeof(buffer), 0);
if (bytes_read <= 0) {
close(client_socket);
return;
}
// 简单解析HTTP请求
std::string http_request(buffer, bytes_read);
std::string ip;
int port;
// 寻找IP和端口号
auto host_pos = http_request.find("Host: ");
if (host_pos != std::string::npos) {
auto start = host_pos + std::string("Host: ").size();
ip = http_request.substr(start, http_request.find("\r\n", start) - start);
}
auto content_length_pos = http_request.find("Content-Length:");
if (content_length_pos != std::string::npos) {
auto start = content_length_pos + std::string("Content-Length: ").size();
int length = std::stoi(http_request.substr(start, http_request.find("\r\n", start) - start));
if (length > 0) {
char* content = new char[length];
bytes_read = recv(client_socket, content, length, 0);
if (bytes_read > 0) {
// 解析JSON内容假设前端发送的是JSON格式
// 这里需要添加JSON解析逻辑来提取IP和端口
// 示例:{"ip":"192.168.1.1","port":8080}
// 可以使用第三方库如nlohmann/json来解析JSON
// 假设解析后得到ip和port
// ConnectToGateway(ip, port);
delete[] content;
}
}
}
// 发送HTTP响应
std::string response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n";
send(client_socket, response.c_str(), response.size(), 0);
close(client_socket);
}
// 启动HTTP服务器的函数
void StartHttpServer() {
int http_server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (http_server_socket < 0) {
perror("Could not create HTTP server socket");
return;
}
int opt = 1;
if (setsockopt(http_server_socket, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("Setsockopt failed");
close(http_server_socket);
return;
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(HTTP_SERVER_PORT);
if (bind(http_server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Bind failed");
close(http_server_socket);
return;
}
if (listen(http_server_socket, 5) < 0) {
perror("Listen failed");
close(http_server_socket);
return;
}
std::cout << "HTTP server listening on port " << HTTP_SERVER_PORT << std::endl;
while (!exit_flag) {
int client_socket = accept(http_server_socket, NULL, NULL);
if (client_socket < 0) {
perror("Accept failed");
continue;
}
threads.emplace_back(HandleHttpRequest, client_socket);
}
close(http_server_socket);
}
/*
int main() {
// threads.emplace_back(StartHttpServer);
// std::string command, ip;
// int port;
// bool in_connect_mode = false;
// std::cout << "Enter command (connect/exit): ";
// while (true) {
// if (in_connect_mode)
// {
// std::cout << "continue connect or not ? (y or n) ";
// std::cin >> command;
// if(command=="y"){
// std::cout << "Enter the gateway IP address: ";
// std::cin >> ip;
// std::cout << "Enter the gateway port: ";
// std::cin >> port;
// ConnectToGateway(ip, port);
// }
// else {
// in_connect_mode = false; // 退出连接模式
// std::cout << "Exiting connect mode." << std::endl;
// }
// }
// else{
// std::cout << "Enter command (connect/exit): ";
// std::cin>>command;
// if (command == "connect") {
// if (in_connect_mode) {
// std::cout << "Already in connect mode." << std::endl;
// continue;
// }
// in_connect_mode = true; // 进入连接模式
// std::cout << "Enter the gateway IP address: ";
// std::cin >> ip;
// std::cout << "Enter the gateway port: ";
// std::cin >> port;
// ConnectToGateway(ip, port);
// } else if (command == "exit") {
// exit_flag = true; // 设置退出标志
// std::cout << "Exiting program." << std::endl;
// // 关闭所有套接字
// for (auto& sock_pair : sockets) {
// shutdown(sock_pair.first, SHUT_RDWR); // 关闭套接字的发送和接收
// close(sock_pair.first);
// }
// sockets.clear();
// std::cout << "sockets.clear" << std::endl;
// // 等待所有线程结束
// for (auto& thread : threads) {
// if (thread.joinable()) {
// thread.join();
// }
// }
// threads.clear();
// break; // 退出主循环
// } else {
// std::cout << "Unknown command" << std::endl;
// }
// }
// }
// std::cout<<"out"<<std::endl;
// return 0;
std::thread http_server_thread(StartHttpServer);
std::string command, ip;
int port;
bool in_connect_mode = false;
while (true) {
std::cout << "Enter command (connect/exit): ";
std::cin >> command;
if (command == "connect") {
if (in_connect_mode) {
std::cout << "Already in connect mode." << std::endl;
continue;
}
in_connect_mode = true;
std::cout << "Enter the gateway IP address: ";
std::cin >> ip;
std::cout << "Enter the gateway port: ";
std::cin >> port;
ConnectToGateway(ip, port);
} else if (command == "exit") {
break; // 接收到退出命令,退出主循环
} else {
std::cout << "Unknown command" << std::endl;
}
}
// 设置退出标志
exit_flag = true;
// 强制结束HTTP服务器线程
if (http_server_thread.joinable()) {
http_server_thread.join();
}
// 关闭所有套接字
for (auto& sock_pair : sockets) {
shutdown(sock_pair.first, SHUT_RDWR);
close(sock_pair.first);
}
sockets.clear();
// 等待所有工作线程结束
for (auto& thread : threads) {
if (thread.joinable()) {
thread.join();
}
}
threads.clear();
std::cout << "Exited program." << std::endl;
return 0;
}
*/

@ -0,0 +1,22 @@
#ifndef CONNECTOR_CONTROLLER_H
#define CONNECTOR_CONTROLLER_H
#include <iostream>
#include <thread>
#include <vector>
#include <map>
#include <mutex>
#include <atomic>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>
// 函数声明
void StartHttpServer();
void ConnectToGateway(const std::string& ip, int port);
void KeepConnection(int sock);
void HandleHttpRequest(int client_socket);
#endif // CONNECTOR_CONTROLLER_H

@ -0,0 +1,68 @@
/*
*/
/*
#include <iostream>
#include <mysql/mysql.h>
int main() {
MYSQL *conn;
conn = mysql_init(NULL);
if (conn == NULL) {
std::cerr << "MySQL init failed" << std::endl;
return 1;
}
const char *server = "localhost";
const char *user = "rtsw";
const char *password = "123456";
const char *database = "nginxdb";
unsigned int port = 3306; // 使用云数据库提供的端口
if (mysql_real_connect(conn, server, user, password, database, port, NULL, 0) == NULL) {
std::cerr << "Connection error: " << mysql_error(conn) << std::endl;
mysql_close(conn);
return 1;
}
std::cout << "Successfully connected to the database" << std::endl;
// ... 执行数据库操作 ...
mysql_close(conn);
return 0;
}
*/
#include "connector_database.h"
// DatabaseOperation函数定义
void DatabaseOperation() {
MYSQL *conn = mysql_init(NULL);
if (conn == NULL) {
std::cerr << "MySQL init failed" << std::endl;
return;
}
const char *server = "localhost";
const char *user = "rtsw";
const char *password = "123456";
const char *database = "nginxdb";
unsigned int port = 3306;
if (mysql_real_connect(conn, server, user, password, database, port, NULL, 0) == NULL) {
std::cerr << "Connection error: " << mysql_error(conn) << std::endl;
mysql_close(conn);
return;
}
std::cout << "Successfully connected to the database" << std::endl;
// ... 执行数据库操作 ...
mysql_close(conn);
}

@ -0,0 +1,10 @@
#ifndef CONNECTOR_DATABASE_H
#define CONNECTOR_DATABASE_H
#include <iostream>
#include <mysql/mysql.h>
// 函数声明
void DatabaseOperation();
#endif // CONNECTOR_DATABASE_H

@ -0,0 +1,35 @@
#include <iostream>
#include <string>
#include "connector_controller.h"
#include "connector_database.h"
int main() {
std::string command;
bool running = true;
while (running) {
std::cout << "Enter command (start_http_server/connect_gateway/database_operation/exit): ";
std::cin >> command;
if (command == "start_http_server") {
StartHttpServer();
} else if (command == "connect_gateway") {
std::string ip;
int port;
std::cout << "Enter the gateway IP address: "<<std::endl;
std::cin>>ip; // 使用getline以获取包含空格的IP地址
std::cout << "Enter the gateway port: "<<std::endl;
std::cin >> port;
ConnectToGateway(ip, port);
} else if (command == "database_operation") {
DatabaseOperation();
} else if (command == "exit") {
running = false;
} else {
std::cout << "Unknown command" << std::endl;
}
}
std::cout << "Exiting program." << std::endl;
return 0;
}

@ -0,0 +1,125 @@
#include <iostream>
#include <thread>
#include <vector>
#include <map>
#include <mutex>
#include <atomic>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#define BUFFER_SIZE 1024
std::vector<std::thread> threads; // 存储所有连接线程
std::map<int, int> sockets; // 存储套接字
std::mutex sockets_mutex; // 用于同步访问 sockets
std::atomic<bool> exit_flag(false); // 原子退出标志
// 维护连接的函数
void KeepConnection(int sock) {
char buffer[BUFFER_SIZE];
int nbytes;
while (!exit_flag) {
nbytes = recv(sock, buffer, BUFFER_SIZE, 0);
if (nbytes <= 0) {
std::cout << "Gateway disconnected" << std::endl;
break;
}
std::cout << "Received from gateway (Socket " << sock << "): " << buffer << std::endl;
}
{
std::lock_guard<std::mutex> lock(sockets_mutex);
sockets.erase(sock); // 从集合中移除套接字
}
close(sock);
}
// 连接到网关的函数
void ConnectToGateway(const std::string& ip, int port) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Could not create socket");
return;
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if (inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr) <= 0) {
perror("Invalid address");
close(sock);
return;
}
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection to the server failed");
close(sock);
return;
}
{
std::lock_guard<std::mutex> lock(sockets_mutex);
sockets[sock] = 1; // 将套接字添加到集合中
}
std::cout << "Connected to gateway at " << ip << ":" << port << " (Socket " << sock << ")" << std::endl;
// 在新线程中维护连接
threads.emplace_back(KeepConnection, sock);
}
int main() {
std::string command, ip;
int port;
bool in_connect_mode = false;
while (true) {
std::cout << "Enter command (connect/exitconnect/exit): ";
std::cin >> command;
if (command == "connect") {
if (in_connect_mode) {
std::cout << "Already in connect mode." << std::endl;
continue;
}
in_connect_mode = true; // 进入连接模式
std::cout << "Enter the gateway IP address: ";
std::cin >> ip;
std::cout << "Enter the gateway port: ";
std::cin >> port;
ConnectToGateway(ip, port);
} else if (command == "exitconnect") {
if (!in_connect_mode) {
std::cout << "Not in connect mode." << std::endl;
continue;
}
in_connect_mode = false; // 退出连接模式
std::cout << "Exiting connect mode." << std::endl;
} else if (command == "exit") {
exit_flag = true; // 设置退出标志
std::cout << "Exiting program." << std::endl;
// 关闭所有套接字
for (auto& sock_pair : sockets) {
shutdown(sock_pair.first, SHUT_RDWR); // 关闭套接字的发送和接收
close(sock_pair.first);
}
sockets.clear();
// 等待所有线程结束
for (auto& thread : threads) {
if (thread.joinable()) {
thread.join();
}
}
threads.clear();
break; // 退出主循环
} else {
std::cout << "Unknown command" << std::endl;
}
}
return 0;
}

@ -0,0 +1,3 @@
# 默认忽略的文件
/shelf/
/workspace.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.12 (G:)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PackageRequirementsSettings">
<option name="requirementsPath" value="" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="EPYTEXT" />
<option name="myDocStringFormat" value="Epytext" />
</component>
</module>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.12 (controller)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (G:)" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/controller.iml" filepath="$PROJECT_DIR$/.idea/controller.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

@ -0,0 +1,11 @@
#!/usr/bin/env python
# encoding: utf-8
# @author: 原凯峰
# @contact: 2894340009@qq.com
# @software: pycharm
# @file: confControl.py
# @time: 2024/6/21 11:18
# @desc:
#TODO 通过ssh在线更改nginx的conf文件

@ -0,0 +1,378 @@
# encoding: utf-8
# @author: 原凯峰
# @contact: 2894340009@qq.com
# @software: pycharm
# @file: DatabaseOp.py
# @time: 2024/6/19 9:22
# @desc:
import mysql
from mysql.connector import Error
# 连接数据库函数
def connect_user_db():
"""
@author: 原凯峰
@return:
"""
try:
conn = mysql.connector.connect(
host="localhost",
user="rtsw",
password="123456",
database="nginxdb",
port=3306
)
if conn.is_connected():
return conn
except Error as e:
print("Connection error:", e)
# 插入用户数据函数
def insert_user_data(conn, username, real_name, ID, password, tel):
"""
@author: 原凯峰
@param conn:
@param username:
@param real_name:
@param ID:
@param password:
@param tel:
@return:
"""
try:
cursor = conn.cursor()
query = """
INSERT INTO user (username, real_name, ID, password, tel)
VALUES (%s, %s, %s, %s, %s)
"""
cursor.execute(query, (username, real_name, ID, password, tel))
conn.commit()
return cursor.lastrowid
except Error as e:
print("Insert error:", e)
# 搜索是否存在某用户
def select_user_data(conn,username,ID):
"""
@author: 原凯峰
@param conn:
@param username:
@param ID:
@return:
"""
try:
cursor = conn.cursor()
select_query = "SELECT * FROM user"
cursor.execute(select_query)
for row in cursor.fetchall():
print("id: {}, username: {}, email: {}".format(row[0], row[1], row[2]))
except Error as e:
print("Select error:", e)
# 查询用户函数
def select_exist_user(conn, username):
"""
@author: 原凯峰
@param conn:
@param username:
@return:
"""
try:
cursor = conn.cursor()
# 构造查询语句确保使用参数化查询以防止SQL注入
select_query = "SELECT * FROM user WHERE username = %s"
cursor.execute(select_query, (username,))
# 使用fetchall()来获取所有结果
results = cursor.fetchall()
# 如果结果不为空,则表示找到了匹配的用户名
if results:
for row in results:
print("id: {}, username: {}, email: {}".format(row[0], row[1], row[2]))
return True
else:
return False
except Error as e:
print("Select error:", e)
return False
# 更新用户信息函数
def update_user(conn, username, new_email):
"""
@author: 原凯峰
@param conn:
@param username:
@param new_email:
@return:
"""
try:
cursor = conn.cursor()
query = """
UPDATE users SET email = %s WHERE username = %s
"""
cursor.execute(query, (new_email, username))
conn.commit()
return cursor.rowcount
except Error as e:
print("Update error:", e)
# 删除用户函数
def delete_user(conn, username):
"""
@author: 原凯峰
@param conn:
@param username:
@return:
"""
try:
cursor = conn.cursor()
delete_query = """
DELETE FROM users WHERE username = %s
"""
cursor.execute(delete_query, (username,))
conn.commit()
return cursor.rowcount
except Error as e:
print("Delete error:", e)
# ************************server部分***************************** #
# 判断是否存在数据库中已经收录过这个服务器
def is_exist_server(conn, server_name):
"""
@todo 查询该服务器是否已经被servers数据库收录
@param conn:
@param server_name:
@return:
"""
try:
cursor = conn.cursor()
# 构造查询语句确保使用参数化查询以防止SQL注入
select_query = "SELECT * FROM servers WHERE server_name = %s"
cursor.execute(select_query, (server_name,))
# 使用fetchall()来获取所有结果
results = cursor.fetchall()
# 如果结果不为空,则表示找到了匹配的用户名
if results:
for row in results:
print("server_name: {}, status: {}".format(row[0], row[1]))
return True
else:
return False
except Error as e:
print("Select error:", e)
return False
# 将这一次的服务器活跃信息存放到服务器中,是第一次存放
def insert_server_data(conn,server_name,status,upstream,detect_date,responseTime,protocol):
"""
@param conn:
@param server_name:
@param status:
@param upstream:
@param detect_date:
@param responseTime:
@param protocol:
@return:
"""
try:
cursor = conn.cursor()
query = """
INSERT INTO servers (server_name, status, upstream, detect_date, responseTime, protocol)
VALUES (%s, %s, %s, %s, %s, %s)
"""
cursor.execute(query, (server_name, status, upstream, detect_date, responseTime, protocol))
conn.commit()
return cursor.lastrowid
except Error as e:
print("Insert error:", e)
# 在第n次获得这个服务器的信息时更改服务器列表中的信息
def update_server_list(conn,server_name, status, upstream, detect_date, responseTime, protocol):
"""
@todo 将服务器信息填入或者更改在服务器列表中
@return:
"""
# 更新的数据和条件
update_data = {
'status': f'{status}', # 需要更新的列和新值
'responseTime': f'{responseTime}',
'detect_date': f'{detect_date}',
'upstream': f'{upstream}',
'protocol': f'{protocol}',
# 可以添加更多的列和值
}
where_condition = f'server_name = {server_name}' # 定位记录的条件例如主键ID为1的记录
# 连接到数据库
try:
cursor = conn.cursor()
# 构建UPDATE语句
update_columns = ', '.join([f"{key} = %s" for key in update_data.keys()])
update_values = tuple(update_data.values())
# sql_update_query = f"UPDATE servers SET {update_columns} WHERE {where_condition}"
# 采用下面这个方法不会出错
sql_update_query = "UPDATE servers SET status = %s, responseTime = %s, detect_date = %s, upstream = %s, protocol = %s WHERE server_name = %s"
update_values = (status, responseTime, detect_date, upstream, protocol, server_name)
# 执行UPDATE语句
cursor.execute(sql_update_query, update_values)
# 提交事务
conn.commit()
# 打印受影响的行数
print(cursor.rowcount, "record(s) updated.")
except Error as e:
print("Error while updating data to MySQL", e)
# 获取服务器列表中的所有服务器的信息
def select_server_health_list(conn):
"""
TODO 获得目前数据库中所有的服务器名称返回一个数组
@author: 原凯峰
@param conn:
@return: 存放有服务器名称的数组
"""
sql_query ="SELECT * FROM servers"
cursor = conn.cursor()
# 执行查询语句
cursor.execute(sql_query)
# 获取所有查询结果
rows = cursor.fetchall()
# 将查询结果转换为字典列表
columns = [i[0] for i in cursor.description] # 获取列名
data_list = [dict(zip(columns, row)) for row in rows] # 将每行数据转换为字典
return data_list
def insert_serverhealthlog_data(conn,server_name,status,upstream,detect_date,responseTime,protocol):
"""
@param conn:
@param server_name:
@param status:
@param upstream:
@param detect_date:
@param responseTime:
@param protocol:
@return:
"""
try:
cursor = conn.cursor()
query = """
INSERT INTO serverhealthlog (server_name, status, upstream, detect_date, responseTime, protocol)
VALUES (%s, %s, %s, %s, %s, %s)
"""
cursor.execute(query, (server_name, status, upstream, detect_date, responseTime, protocol))
conn.commit()
return cursor.lastrowid
except Error as e:
print("Insert error:", e)
def select_server_health_log(conn,servername):
"""
#TODO 查询某个服务器的历史健康状态的多条数据需要查询ServerHealthLog表,这个查询时间的范围还需要确定
@author: 原凯峰
@param conn:
@param servername:
@return:返回值是一个字典列表
"""
sql_query = f"SELECT * FROM serverhealthlog WHERE server_name = '{servername}'"
cursor = conn.cursor()
# 执行查询语句
cursor.execute(sql_query)
# 获取所有查询结果
rows = cursor.fetchall()
# 将查询结果转换为字典列表
# 假设你的表有列名为'id', 'name', 'age'等
columns = [i[0] for i in cursor.description] # 获取列名
data_list = [dict(zip(columns, row)) for row in rows] # 将每行数据转换为字典
return data_list
def delete_server_health_log(conn,servername,finaldata):
"""
@todo 删除某个服务器某段时间之前的健康信息
@author: 原凯峰
@param conn: 数据库连接
@param servername: 服务器呢名称
@param finaldata: 从哪个日期之前的数据都要删除
@return:
"""
# 通过日期获得当日日志数量
def getLogNumByDate(conn,date):
"""
@param conn:
@param date:
@return:
"""
cursor = conn.cursor()
wherequery = f"detect_date = '{date}'"
query = f"SELECT COUNT(*) FROM serverhealthlog WHERE {wherequery}"
# print(query)
cursor.execute(query)
count = cursor.fetchone()[0]
# 关闭连接
cursor.close()
return count
# 测试用例
def test():
conn = connect_user_db()
date = '2024-6-2'
print(getLogNumByDate(conn,date))
# test()
# 断开数据库连接函数
def disconnect_db(conn):
"""
@author: 原凯峰
@param conn:
@return:
"""
if conn.is_connected():
cursor = conn.cursor()
cursor.close()
conn.close()
print("Database connection closed.")
# 示例使用
# if __name__ == "__main__":
# # 连接数据库
# conn = connect_user_db()
# if conn:
# # 插入用户数据
# insert_user_data(conn, 'username1', 'real_name1', 'ID1', 'password1', 'tel1')
#
# # 查询用户
# select_users(conn)
#
# # 更新用户信息
# # update_user(conn, 'username1', 'new_email1')
#
# # 删除用户
# # delete_user(conn, 'username1')
#
# # 断开数据库连接
# disconnect_db(conn)

@ -0,0 +1,83 @@
#!/usr/bin/env python
# encoding: utf-8
# @author: 原凯峰
# @contact: 2894340009@qq.com
# @software: pycharm
# @file: MachineLearningDivider.py
# @time: 2024/6/26 8:21
# @desc:利用随机森林法进行模型训练,能够通过平均响应时间、故障率等数据计算出服务器的健康状态
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, accuracy_score
import pickle
def trainmodel():
# 假设我们有以下数据集
X = [
[0.3, 0.005], # 服务器特征:平均响应时间和故障率
[2.5, 0.03],
[0.7, 0.045],
[1.2, 0.002],
[3.5, 0.1],
[1.3, 0.05],
[0.01, 0.15], # 服务器特征:平均响应时间和故障率
[5, 0.03],
[0.7, 0.015],
[1.4, 0.02],
[0.15, 0.2],
[1.3, 0.005],
]
y = ['良好', '一般', '一般', '良好', '', '一般', '一般', '', '良好', '', '', '良好'] # 对应的健康状态标签
# 将健康状态标签转换为数值
label_mapping = {'一般': 0, '良好': 1, '': 2}
y_encoded = [label_mapping[label] for label in y]
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y_encoded, test_size=0.4, random_state=42)
# 选择模型,这里使用随机森林分类器
model = RandomForestClassifier(n_estimators=100, random_state=42)
# 训练模型
model.fit(X_train, y_train)
# 预测测试集
y_pred = model.predict(X_test)
# 评估模型
print(classification_report(y_test, y_pred))
print("Accuracy:", accuracy_score(y_test, y_pred))
# 保存模型
with open('server_health_model.pkl', 'wb') as file:
pickle.dump(model, file)
# trainmodel()
# 定义一个函数来加载模型并进行预测
def load_model_and_predict(new_data):
with open('../LogAnalyze/server_health_model.pkl', 'rb') as file:
loaded_model = pickle.load(file)
predictions = loaded_model.predict(new_data)
return predictions
# 定义一个函数来将预测结果转换为健康等级
def predict_health_status(new_data):
label_mapping = {'一般': 0, '良好': 1, '': 2}
predictions = load_model_and_predict(new_data)
# 创建逆向映射字典
inverse_label_mapping = {value: key for key, value in label_mapping.items()}
# 使用逆向映射字典转换预测结果
health_status = [inverse_label_mapping[pred] for pred in predictions]
return health_status
# 测试函数
def testcase():
new_data = [[0.4, 0.01]] # 新的服务器数据
health_status = predict_health_status(new_data)
print("预测的健康状态:", health_status)
# testcase()

@ -0,0 +1,59 @@
#!/usr/bin/env python
# encoding: utf-8
# @author: 原凯峰
# @contact: 2894340009@qq.com
# @software: pycharm
# @file: ServerHealthLogAnalyzer.py
# @time: 2024/6/20 16:57
# @desc: 用于对服务器健康信息的数据分析和日志信息的数据分析
from DbProcessor.DatabaseOp import *
class ServerHealthLogAnalyzer():
def __init__(self):
self.serverList = select_server_health()
self.analyzeReturn = self.returnMessageProvider()
def returnMessageProvider(self):
"""
@todo 能够将每一个服务器的日志分析结果存放进dict中方便后续使用
@author: 原凯峰
@return: 存放有服务器健康状态分析的字典
"""
serverHealthDict = {}
for serverName in self.serverList:
aba= self.logAnalyzer(serverName)
return serverHealthDict
def logAnalyzer(self,serverName):
"""
@todo 需要处理日志信息并且将日志信息进行处理形成一个统计性的结论似乎可以借助某些在线应用的api来辅助进行日志分析
@author: 原凯峰
@param serverName:
@return: 存有分析结果的字符串
"""
serverHealthLog = select_server_health_log(serverName)
analyzeResult = ""
return analyzeResult
"""
可能可以做的数据分析
故障率
存活率
周期性存活率
平均正常运行时间
平均故障时间
已经正常/故障运行的时间
"""

@ -0,0 +1,60 @@
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# 测试样例数据
data = {
'server_name': ['Server1', 'Server1', 'Server2', 'Server2',
'Server1', 'Server1', 'Server2', 'Server2'],
'check_time': ['2024-03-01 10:00', '2024-03-01 11:00', '2024-03-31 12:00',
'2024-04-15 13:00', '2024-06-01 14:00', '2024-06-30 15:00',
'2024-12-25 16:00', '2024-12-31 17:00'],
'status': ['Normal', 'Error', 'Normal', 'Warning',
'Normal', 'Error', 'Warning', 'Normal']
}
# 创建DataFrame
df = pd.DataFrame(data)
df['check_time'] = pd.to_datetime(df['check_time'])
# 添加季节性、月度、周度、日度和小时特征
df['season'] = df['check_time'].dt.to_period('Q').astype(str)
df['month'] = df['check_time'].dt.month_name()
df['day_of_week'] = df['check_time'].dt.day_name()
df['day'] = df['check_time'].dt.day
df['hour'] = df['check_time'].dt.hour
# 定义服务器存活状态
df['is_failure'] = df['status'].apply(lambda x: 1 if x not in ['Normal'] else 0)
# 按时间粒度分组并计算故障次数和总检查次数
grouped = df.groupby(['server_name', 'season', 'month', 'day_of_week', 'day', 'hour'])['is_failure'].agg(Total='sum').reset_index()
# 计算故障率
grouped['failure_rate'] = grouped['Total'] / grouped.groupby(['server_name', 'season', 'month', 'day_of_week', 'day', 'hour']).cumcount() + 1
# 为了可视化我们使用pivot来重塑数据
pivot_season = grouped.pivot_table(index=['server_name', 'season'], columns='hour', values='failure_rate', fill_value=0)
pivot_month = grouped.pivot_table(index=['server_name', 'month'], columns='day_of_week', values='failure_rate', fill_value=0)
pivot_week = grouped.pivot_table(index=['server_name', 'day_of_week'], columns='day', values='failure_rate', fill_value=0)
pivot_day = grouped.pivot_table(index=['server_name', 'day'], columns='hour', values='failure_rate', fill_value=0)
# 可视化季节性故障率
sns.heatmap(pivot_season, annot=True, cmap='YlGnBu')
plt.title('Seasonal Failure Rates by Server and Hour')
plt.show()
# 可视化月度故障率
sns.heatmap(pivot_month, annot=True, cmap='YlGnBu')
plt.title('Monthly Failure Rates by Server and Day of Week')
plt.show()
# 可视化周度故障率
sns.heatmap(pivot_week, annot=True, cmap='YlGnBu')
plt.title('Weekly Failure Rates by Server and Day')
plt.show()
# 可视化日度故障率
sns.heatmap(pivot_day, annot=True, cmap='YlGnBu')
plt.title('Daily Failure Rates by Server and Hour')
plt.show()

@ -0,0 +1,86 @@
# encoding: utf-8
# @author: 原凯峰
# @contact: 2894340009@qq.com
# @software: pycharm
# @file: BackendProcessor.py
# @time: 2024/6/19 9:22
# @desc:
from DbProcessor.DatabaseOp import *
import LogAnalyze.ServerHealthLogAnalyzer as Analyzer
import json
#TODO 还没写
class BackendProcessor():
def __init__(self,receivedMessage):
self.receivedMessage = receivedMessage
self.messageType = self.getreceivedMessageType()
self.returnMessage = self.dataProcessor()
def getreceivedMessageType(self):
"""
@author: 原凯峰
@return: messageType
"""
try:
# 由于后端json中涉及到“type”字段所以采用kind作为关键词
messageType = self.receivedMessage["kind"]
print(f"this is a {messageType} message")
return messageType
except Exception as e:
print(f"An error occurred: {e}")
# 进行错误处理,比如记录日志或者设置默认值
return None
def dataProcessor(self):
"""
@author: 原凯峰
@return:
"""
# 如果是登录信息
if self.messageType == "server_health_list":
serverNum, serverList = self.serverHealthMessageParser(self.receivedMessage)
conn = connect_user_db()
for serverInfo in serverList:
# 需要填入数据库的消息
server_name =serverInfo["name"]
upstream = serverInfo["upstream"]
status = 0
if serverInfo["status"] == 'up':
status = 1
detect_date = serverInfo["last_check_time"]#TODO 这个字段和下面这个字段都需要后续修改名字。
responseTime = serverInfo["last_response_time"]#
protocol = serverInfo["type"]
# 先判断是否该服务器已经存在;
if not is_exist_server(conn, server_name):
insert_server_data(conn,server_name, status, upstream, detect_date, responseTime, protocol)
returnMessage = " success!"
else:
update_server_list(conn,server_name, status, upstream, detect_date, responseTime, protocol)
returnMessage = "Server already exists. "
insert_serverhealthlog_data(conn,server_name,status,upstream,detect_date,responseTime,protocol)
def serverHealthMessageParser(self,serversHealthList):
"""
@param serversHealthList: 包含有服务器健康信息的json
@return:serverList ,存放有服务器健康状态的数组
"""
try:
servers = serversHealthList["servers"]
num = servers["total"]
serverList = servers["server"]
return num, serverList
except Exception as e:
print("find an error while parsing server health list!!")
return 0,[]
def backendTest():
json_str = '{"source": "backend", "kind": "server_health_list", "servers": {"total":2,"generation":1, "server":[{"index":0,"type":"tcp","last_response_time":"30","name":"1.205.204.0","status":"up","upstream":"cluster","last_check_time":"2024-6-5"}]}}'
data_dict = json.loads(json_str)
a = BackendProcessor(data_dict)
# backendTest()

@ -0,0 +1,378 @@
# encoding: utf-8
# @author: 原凯峰
# @contact: 2894340009@qq.com
# @software: pycharm
# @file: FrontendProcessor.py
# @time: 2024/6/19 9:22
# @desc:
from DbProcessor.DatabaseOp import *
from LogAnalyze import MachineLearningDivider as mldivider
from datetime import datetime, timedelta
import json
class FrontendProcessor():
def __init__(self,receivedMessage):
self.receivedMessage = receivedMessage
self.messageType = self.getreceivedMessageType()
self.returnMessage = self.dataProcessor()
def getreceivedMessageType(self):
"""
@author: 原凯峰
@return: messageType
"""
try:
messageType = self.receivedMessage["type"]
print(f"this is a {messageType} message")
return messageType
except Exception as e:
print(f"An error occurred: {e}")
# 进行错误处理,比如记录日志或者设置默认值
return None
def dataProcessor(self):
"""
@disc: 这个函数是这个类的核心处理函数处理来自前端的所有请求并且返回响应信息
@author: 原凯峰
@return:
"""
# 如果是登录信息
if self.messageType == "register_message":
conn = connect_user_db()
# 需要填入数据库的消息
username = self.receivedMessage["username"]
password = self.receivedMessage["password"]
real_name = self.receivedMessage["real_name"]
ID = self.receivedMessage["ID"]
tel = self.receivedMessage["tel"]
# 先判断是否改用户已经存在;
if not select_exist_user(conn,username):
insert_user_data(conn,username,real_name,ID,password,tel)
returnMessage = "RegistOP success!"
return returnMessage
else:
returnMessage = "Username already exists or Database error. "
return returnMessage
elif self.messageType == "getallserverstatus":
# 获取所有服务器的状态信息,主要用于服务器列表界面的展示
return self.getAllServerStatus()
elif self.messageType == "getserverinfo_message":
# 获取某个服务器的某些数据,故障率、平均响应时间等,
serverName = self.receivedMessage["server_name"]
serverInfo = self.getServerInfo(serverName)
return serverInfo
elif self.messageType == "get_overall_message":
overAllMessage = self.caculateOverallMessage()
return overAllMessage
elif self.messageType == "get_net_point_message":
# 前端像我请求网络环境中的所有信息
backMessage=self.getNetPointInfo()
# self.returnMessage == f"{backMessage}"
elif self.messageType == "alt_backend_config":
# 下面这个判断用于接收并且处理前端传输过来的更改后端配置文件的请求。
# TODO这个函数的实现可能可以采用以下这种实现方式向后端发送更改信息 不着急写
"""
@想法 是否可以采用ssh远程操控 或者说仅仅担任一个消息中转的作用
@疑惑是否需要建立一个记录这个更改操作的数据库表名为 altconfighistory
"""
conn = connect_user_db()
# 需要填入数据库的消息
username = self.receivedMessage["username"]
password = self.receivedMessage["password"]
json_example = '{"source":"backend","config":"this is a test config file"} '
def getNetPointInfo(self):
"""
@todo 获取当前网络节点所有的节点信息这个不着急写
@return: 所需要的信息字段
"""
rez = '{"servers":"{[{"name":"one","status":"alive","ip":"192.168.0.0.132:8080"},{"name":"one","status":"alive","ip":"192.168.0.0.132:8080"}]}", "gateways":"{["name":"gateway1",abc]}"}'
return rez
def getServerInfo(self,serverName):
"""
@date6.25 14:58
@param serverName:
@return: 返回统计好的服务器的基本信息
"""
conn = connect_user_db()
serverHealthLog = select_server_health_log(conn,serverName)
ResponseTimeList = []
DisabledTime = 0
AbledTime = 0
logNum = len(serverHealthLog)
DetectTimeList = []
# 遍历每一条数据
for serverlog in serverHealthLog:
# 判断该条数据中该服务器是否存活
if serverlog["status"] == '1':
AbledTime += 1
else:
DisabledTime += 1
serverlog.pop('status')
serverlog.pop('server_name')
serverlog.pop('protocol')
serverlog.pop('health_id')
serverlog.pop('upstream')
ResponseTimeList.append(int(serverlog["responseTime"]))
DetectTimeList.append(serverlog['detect_date'])
print(ResponseTimeList)
# 故障率
DisabledRate = float(DisabledTime)/(DisabledTime + AbledTime)
# 响应时间类的统计数据
AverageResponseTime = sum(ResponseTimeList)/float(logNum)
MinResponseTime = min(ResponseTimeList)
MaxResponseTime = max(ResponseTimeList)
stats = {
"servername": serverName,
"DisabledRate": DisabledRate,
"AverageResponseTime": AverageResponseTime,
"MinResponseTime": MinResponseTime,
"MaxResponseTime": MaxResponseTime,
"ResponseTimeArray": ResponseTimeList,
"Time": DetectTimeList
}
# 使用json.dumps将字典转换为JSON格式的字符串
backMessage = json.dumps(stats)
return backMessage
def getAllServerStatus(self):
"""
给列表页返回信息
@return:
"""
conn = connect_user_db()
allServerStatusList = select_server_health_list(conn)
for ServerStatus in allServerStatusList:
ServerStatus.pop('upstream')
if ServerStatus['status'] == '1':
ServerStatus['status'] = '存活'
else:
ServerStatus['status'] = '死亡'
ServerStatus['address'] = self.queryIpLocation(ServerStatus['server_name'])
return allServerStatusList
def queryIpLocation(self, ip_address):
"""
@disc: 返回IP的所在地
@param ip_address:
@return:
"""
ip_data_file = '../china_ip_address.txt'
result = None
with open(ip_data_file, 'r', encoding='utf-8') as f:
for line in f:
if line.strip(): # 确保行非空
parts = line.split()
if len(parts) >= 3:
start_ip = parts[0]
end_ip = parts[1]
location_info = ' '.join(parts[2:])
if ip_address >= start_ip and ip_address <= end_ip:
result = location_info.split('')[1].strip() # 获取中国的地区信息
break
return result
def caculateOverallMessage(self):
"""
@todo 计算服务器的地区分布并且获得统计性数据 利用机器学习算法计算服务器的存活程度 计算平均存活率
@return:返回包含以上所有数据的json格式数据
"""
conn = connect_user_db()
serverList = select_server_health_list(conn)
print(serverList)
provinceDict = {}
healthDict= {}
healthCnt = 0 # 统计总服务器列表中的健康状态信息,设计所有的服务器,而不是某个服务器的将抗日志统计
# 前端总揽界面所需要的前三个服务器的七天内的序列数据直接通过重用类中本身就有的getServerInfo函数进行获取
datasets = []#todo
# 以后考虑把这几个字段放在数据库里,入库的时候就算好
cnt = 3
for serverInfo in serverList:
province = self.queryIpLocation(serverInfo['server_name'])
disableRate = self.getDisabledRate(conn,serverInfo['server_name'])
avgReponsetime = self.getAvgResponseTime(conn,serverInfo['server_name'])[0]
if cnt:
server_dict = json.loads(self.getServerInfo(serverInfo['server_name']))
timeArray = server_dict['ResponseTimeArray']
length = min(6,len(timeArray))
parse_server_dict = {
'label': serverInfo['server_name'],
'data' : timeArray[:length]
}
datasets.append(parse_server_dict)
cnt -= 1
# 处理健康情况信息
if int(serverInfo['status']):
healthCnt += 1
# 处理省份信息
if province in provinceDict:
tmp = provinceDict[province]
provinceDict[province] = tmp+1 #计数加一
else:
provinceDict[province] = 1
# 存活度信息
testdata = [[avgReponsetime/1000, disableRate]]
health = mldivider.predict_health_status(testdata)[0]
# 处理存活度信息
if health in healthDict:
tmp = healthDict[health]
healthDict[health] = tmp+1 #计数加一
else:
healthDict[health] = 1
provinceDistribution = self.getDictRate(provinceDict,len(serverList))
healthDistribution = self.getDictRate(healthDict,len(serverList))
overallHealthRate = float(healthCnt)/len(serverList)
# 日志统计数据
dateArray, logNumArray = self.getLogNumOnDate(conn)
datadict = {
'labels':['周一','周二','周三','周四','周五','周六','周日'],
'datasets':datasets
}
overallMessage = {
'AveSurRate': overallHealthRate,
'TimeArray': dateArray,
'DataArray': logNumArray,
'data1': provinceDistribution,
'data2': healthDistribution,
'data': datadict
}
return overallMessage
def getLogNumOnDate(self,conn):
"""
从数据库中获取关于服务器健康状态的日志信息返回结果为每一天的日志信息数量这里的时间格式需要进行自己的定义
@param conn:
@return: 可以用于建立柱形图的信息
"""
dateArray = []
logNumArray = []
# 定义时间格式
date_format = "%Y-%m-%d"
# 计算当前日期之前15天的日期
for day in range(1,16):
delta = timedelta(days=-day)
previous_date = (datetime.now() + delta).strftime(date_format)
# 去除前导零
previous_date = previous_date.replace("-0", "-")
dateArray.append(previous_date)
logNum = getLogNumByDate(conn,previous_date)
logNumArray.append(logNum)
return dateArray, logNumArray
def getDisabledRate(self,conn,serverName):
"""
@disc 为了更加方便调用把这个功能单独拿出来
@param serverName:
@return: 返回故障率
"""
serverHealthLog = select_server_health_log(conn, serverName)
DisabledTime = 0
AbledTime = 0
# 遍历每一条数据
for serverlog in serverHealthLog:
# 判断该条数据中该服务器是否存活
if serverlog["status"] == '1':
AbledTime += 1
else:
DisabledTime += 1
# 故障率
DisabledRate = float(DisabledTime) / (DisabledTime + AbledTime)
return DisabledRate
def getAvgResponseTime(self,conn,serverName):
"""
获取某个服务器的平均响应时间
@param serverName:
@return:
"""
serverHealthLog = select_server_health_log(conn, serverName)
ResponseTimeList = []
logNum = len(serverHealthLog)
DetectTimeList = []
# 遍历每一条数据
for serverlog in serverHealthLog:
# 判断该条数据中该服务器是否存活
ResponseTimeList.append(int(serverlog["responseTime"]))
DetectTimeList.append(serverlog['detect_date'])
# 响应时间类的统计数据
AverageResponseTime = sum(ResponseTimeList) / float(logNum)
MinResponseTime = min(ResponseTimeList)
MaxResponseTime = max(ResponseTimeList)
return (AverageResponseTime, MinResponseTime, MaxResponseTime)
def getDictRate(self, Dict, num):
"""
返回比率
@param dict:
@return:
"""
ret = []
for key in Dict.keys():
rateDict = {}
rateDict['value'] = Dict[key]/float(num)
rateDict['name'] = key
ret.append(rateDict)
return ret
def test_case_serverinfo():
di = {"source":"frontend" , "type": "getserverinfo_message","server_name":"1.205.204.0"}
a = FrontendProcessor(di)
print(a.returnMessage)
def test_case_serverlist():
di = {"source":"frontend" , "type": "getallserverstatus"}
a = FrontendProcessor(di)
print(a.returnMessage)
def test_case_overallMessage():
di = {"source":"frontend" , "type": "get_overall_message"}
a = FrontendProcessor(di)
print(a.returnMessage)
# test_case_serverlist()
# test_case_serverinfo()
test_case_overallMessage()

@ -0,0 +1,59 @@
# encoding: utf-8
# @author: 原凯峰
# @contact: 2894340009@qq.com
# @software: pycharm
# @file: PreDataProcessor.py
# @time: 2024/6/19 9:22
# @desc:
import json
from MessageHandler.FrontendProcessor import FrontendProcessor
from MessageHandler.BackendProcessor import BackendProcessor
class preDataProcessor():
def __init__(self,rawData):
self.rawData = rawData
self.processedData = self.preDataProcess()
self.returnMessage = self.todo()
def preDataProcess(self):
"""
@author: 原凯峰
@return:processedData处理过后的数据
@todo 前端可以用这个但是后端不太能用
"""
print("preDataProcessing")
processedData = parseJsonToDict(self.rawData)
return processedData
def todo(self):
"""
@author: 原凯峰
@return:前后端信息处理模块的返回信息
"""
if self.processedData["source"]=="frontend":
print("this is a frontend message")
frontProsece = FrontendProcessor(self.processedData)
return frontProsece.returnMessage
elif self.processedData["source"]=="backend":
#对于网关信息的处理
print("this is a backend message")
backendProcess = BackendProcessor(self.processedData)
#这个信息只是一个能够拿到种类的深度,如果想要活得更都的数据,需要在后端信息处理模块里面进行深度解包
return backendProcess.returnMessage
def parseJsonToDict(json_data):
"""
@author: 原凯峰
@param json_data:
@return: 将json信息解析厚的字典
"""
try:
# 使用json.loads()方法将JSON字符串解析为字典
data_dict = json.loads(json_data)
return data_dict
except json.JSONDecodeError as e:
# 如果解析失败,抛出异常
raise ValueError(f"Invalid JSON data: {e}")

@ -0,0 +1,22 @@
from datetime import datetime, timedelta
# 定义时间格式
date_format = "%Y-%m-%d"
# 获取当前日期,并按照定义的格式转换
current_date = datetime.now().strftime(date_format)
# 去除前导零
current_date = current_date.replace("-0", "-")
# 打印当前日期
print("当前日期:", current_date)
for day in range(1,16):
# 计算当前日期之前15天的日期
delta = timedelta(days=-day)
previous_date = (datetime.now() + delta).strftime(date_format)
# 去除前导零
previous_date = previous_date.replace("-0", "-")
print(previous_date)
# 打印之前15天的日期
print("之前15天的日期:", previous_date)

@ -0,0 +1,58 @@
# !/usr/bin/env python
# encoding: utf-8
# @author: 原凯峰
# @contact: 2894340009@qq.com
# @software: pycharm
# @file: tryselect.py
# @time: 2024/6/22 11:32
# @desc:
import mysql.connector
from mysql.connector import Error
import json
# 数据库配置信息
host = ''
database = 'nginxdb'
user = 'rtsw'
password = '123456'
# SQL查询语句
sql_query = "SELECT * FROM tasks" # 替换成你的表名和查询条件
# 连接到数据库
try:
connection = mysql.connector.connect(host=host,
database=database,
user=user,
password=password)
if connection.is_connected():
cursor = connection.cursor()
# 执行查询语句
cursor.execute(sql_query)
# 获取所有查询结果
rows = cursor.fetchall()
# 将查询结果转换为字典列表
# 假设你的表有列名为'id', 'name', 'age'等
columns = [i[0] for i in cursor.description] # 获取列名
data_list = [dict(zip(columns, row)) for row in rows] # 将每行数据转换为字典
# 将字典列表转换为JSON格式
json_data = json.dumps(data_list, ensure_ascii=False)
print(json_data) # 打印JSON格式的数据
print(data_list[0]["subject"])
except Error as e:
print("Error while connecting to MySQL", e)
finally:
# 关闭数据库连接
if connection.is_connected():
cursor.close()
connection.close()
print("MySQL connection is closed")

@ -0,0 +1,21 @@
CREATE TABLE `Servers` (
`server_name` VARCHAR(32) PRIMARY KEY,
`status VARCHAR(32) NOT NULL`,
`upstream` VARCHAR(32),
`detect_date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`responseTime` varchar(255) NOT NULL COMMENT '响应时间',
`protocol` varchar(32) NOT NULL COMMENT '通信协议名称',
) DEFAULT CHARACTER SET = utf8mb4 COMMENT = '服务器列表';
CREATE TABLE `ServerHealthLog` (
`health_id` INT AUTO_INCREMENT PRIMARY KEY,
`server_name` VARCHAR(32),
`upstream` VARCHAR(32),
`detect_date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`status` VARCHAR(32) NOT NULL,
`responseTime` varchar(255) NOT NULL COMMENT '响应时间',
`protocol` varchar(32) NOT NULL COMMENT '通信协议名称',
FOREIGN KEY (`server_name`) REFERENCES Servers(`server_name`),
INDEX `check_time_index` (`check_time`)
) DEFAULT CHARACTER SET = utf8mb4 COMMENT = '服务器历史信息记录表';

@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS `user` (
`username` varchar(255) NOT NULL,
`real_name` varchar(255) NOT NULL COMMENT '真名',
`ID` varchar(255) NOT NULL COMMENT '身份证号',
`password` varchar(255) NOT NULL COMMENT '密码',
`tel` varchar(255) NOT NULL COMMENT '电话号码',
PRIMARY KEY (`id`),
) DEFAULT CHARACTER SET = utf8mb4 COMMENT = '用户信息列表';

File diff suppressed because it is too large Load Diff

@ -0,0 +1,187 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
<!-- 引入格式文件-->
<!-- <link rel="stylesheet" href="html&css.css"> -->
</head>
<body>
<style>
*{
margin: 0px;/*所有的外边距为0*/
padding: 0px;/*所有的内边距为0*/
box-sizing: border-box;/*规定两个并排的带边框的框*/
}
table{
text-align: center;
}
body{
background: url("./assets/images/button.jpg")no-repeat center;
padding-top: 25px;
}
.rg_layout{
width: 900px;
height: 500px;
border: 8px solid #EEEEEE;/*solid 定义实线*/
background-color: white;
margin: auto;
}
.rg_left{
float: none;
text-align: center;
margin: 15px;
}
.rg_left>p:first-child{
color: #FFD026;
font-size: 20px;
}
.rg_left>p:last-child{
color: #A6A6A6;
font-size: 20px;
}
.rg_center{
float: left;
}
.rg_right{
float: none;
margin: 250px;
padding-left: 10px;
white-space:nowrap;
}
.rg_right p{
font-size: 15px;
}
.rg_right p a{
color: coral;
}
.td_left{
padding-left: 250px;
width: 100px;
text-align: center;
height: 45px;
white-space:nowrap;
}
.td_right{
padding-left: 40px;
text-align: center;
white-space:nowrap;
}
.bt_center{
padding-left: 310px;
}
#username,#real_name,#ID,#password,#tel,#birthday,#checkcode{
width: 251px;
height: 32px;
border: 1px solid #A6A6A6;
/*设置边框圆角*/
border-radius: 5px;
padding-left: 10px;
}
#checkcode{
width: 110px;
}
#img_check{
height: 32px;
vertical-align: middle;/*设置图片的位置垂直居中*/
}
#btn_sub{
width: 100px;
height: 40px;
background-color: #FFD026;
border: 1px solid #FFD026;
padding-left: 10px;
}
</style>
<div class="rg_layout">
<div class="rg_left">
<p>新用户注册</p>
<p>USER REGISTER</p>
</div>
<div class="rg_center">
<div class="rg_form">
<form class="ant-form" action="#" method="post">
<table>
<tr><!--label 标签的作用是当点击文字也会跳到文本输出框-->
<!--for属性与ID属性对应规定 label 绑定到哪个表单元素。-->
<td class="td_left"><label for="username">用户名</label> </td>
<td class="td_right"><input type="text" name="username" id="username"> </td>
</tr>
<tr>
<td class="td_left"><label for="real_name">姓名</label> </td>
<td class="td_right"><input type="text" name="real_name" id="real_name"> </td>
</tr>
<tr><!--label 标签的作用是当点击文字也会跳到文本输出框-->
<td class="td_left"><label for="ID">身份证号</label> </td>
<td class="td_right"><input type="text" name="ID" id="ID"> </td>
</tr>
<tr>
<td class="td_left"><label for="password">密码</label> </td>
<td class="td_right"><input type="password" name="password" id="password"> </td>
</tr>
<tr>
<td class="td_left"><label for="tel">再次输入密码</label> </td>
<td class="td_right"><input type="password" name="tel" id="tel"> </td>
</tr>
<tr>
<td colspan="2" align="center" class="bt_center">
<input type="submit" value="注册" id="btn_sub">
</td>
</tr>
</table>
</form>
</div>
</div>
<div class="rg_right">
<p><a href="LoginUI.html">返回登录界面</a></p>
</div>
</div>
</body>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 获取表单元素
var form = document.querySelector('.ant-form');
// 为表单添加提交事件监听器
form.addEventListener('submit', function(e) {
e.preventDefault(); // 阻止表单的默认提交行为
// 收集表单数据
var formData = {
//question_kind: document.getElementsByName('question_kind').value,
ID:document.getElementById('ID').value,
password: document.getElementById('password').value,
real_name:document.getElementById('real_name').value,
source:"frontend",
tel:document.getElementById('tel').value,
type:"register_message",
username: document.getElementById('username').value,
};
console.log(formData);
fetch('http://47.96.136.178:8080', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData) // 将表单数据转换为JSON字符串
})
.then(response => response.json()) // 转换响应为JSON
.then(data => {
console.log('Success:', data);
alert('反馈成功提交!');
})
.catch((error) => {
console.error('Error:', error);
alert('提交失败,请稍后重试!');
});
});
});
</script>
</html>

@ -0,0 +1,131 @@
# encoding: utf-8
# @author: 原凯峰
# @contact: 2894340009@qq.com
# @software: pycharm
# @file: Connector.py
# @time: 2024/6/19 9:20
# @desc:
import socket
import threading
import sys
from http.server import HTTPServer, BaseHTTPRequestHandler
from Server import *
# 全局变量
sockets = {}
socket_lock = threading.Lock()
exit_flag = False
# 维护连接的函数
def KeepConnection(sock, ip, port):
"""
@author: 原凯峰
@param sock:
@param ip:
@param port:
@return:
"""
while not exit_flag:
data = sock.recv(1024)
if not data:
print(f"Gateway disconnected from {ip}:{port}")
break
print(f"Received from gateway ({ip}:{port}): {data.decode()}")
with socket_lock:
del sockets[sock]
# 连接到网关的函数
def ConnectToGateway(ip, port):
"""
@author: 原凯峰
@param ip:
@param port:
@return:
"""
global exit_flag
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, port))
with socket_lock:
sockets[sock] = (ip, port)
print(f"Connected to gateway at {ip}:{port}")
threading.Thread(target=KeepConnection, args=(sock, ip, port)).start()
def StartHttpServer():
"""
@author: 原凯峰
@return:
"""
global exit_flag
server_address = ('', 8080)
httpd = HTTPServer(server_address, CORSHTTPRequestHandler)
print(f'Starting httpd server on port 8080...')
try:
while not exit_flag:
httpd.handle_request() # 使用 handle_request 替代 serve_forever 以便可以检查 exit_flag
except KeyboardInterrupt:
pass
finally:
httpd.server_close()
print("HTTP server stopped")
# 发送消息到特定网关的函数
def SendMessageToGateway(ip, port, message):
"""
@author: 原凯峰
@param ip:
@param port:
@param message:
@return:
"""
with socket_lock:
# 查找特定的网关连接
for sock, (stored_ip, stored_port) in sockets.items():
if stored_ip == ip and stored_port == port:
try:
# 发送消息,这里假设消息是字符串格式
sock.sendall(message.encode('utf-8'))
print(f"Message sent to {ip}:{port}: {message}")
except socket.error as e:
print(f"Error sending message to {ip}:{port}: {e}")
return # 找到并发送消息后退出函数
# 如果没有找到连接
print(f"No connection found for {ip}:{port}")
# 示例发送消息到IP地址和端口
# 假设我们已经连接到了这个网关
def main():
global exit_flag
exit_flag = False # 初始化exit_flag
t = threading.Thread(target=StartHttpServer)
t.start()
while not exit_flag:
command = input("Enter command (/connect_gateway/exit): ")
# if command == "start_http_server":
# t = threading.Thread(target=StartHttpServer)
# t.start()
if command == "connect_gateway":
ip = input("Enter the gateway IP address: ")
port = int(input("Enter the gateway port: "))
ConnectToGateway(ip, port)
elif command == "exit":
exit_flag = True
print("Exiting program...")
break
else:
print("Unknown command")
# StartHttpServer函数修改
if __name__ == "__main__":
main()

@ -0,0 +1,167 @@
#!/usr/bin/env python
# encoding: utf-8
# @author: 原凯峰
# @contact: 2894340009@qq.com
# @software: pycharm
# @file: KernelToController.py
# @time: 2024/7/2 15:16
# @desc:
import requests
import socket
import json
import time
from datetime import datetime
class CustomEncoder(json.JSONEncoder):
def __init__(self, *args, **kwargs):
super(CustomEncoder, self).__init__(*args, **kwargs)
self.prefix = {'number': '1', 'source': 'backend', 'kind': 'server_health_list'}
def encode(self, obj):
if not isinstance(obj, dict):
raise TypeError("Object must be a dict.")
# 将prefix添加到原始字典的前面
encoded_dict = {**self.prefix, **obj}
return super(CustomEncoder, self).encode(encoded_dict)
def calResponseTime(time_str1, time_str2, time_format):
# 将字符串时间转换为datetime对象
time1 = datetime.strptime(time_str1, time_format)
time2 = datetime.strptime(time_str2, time_format)
time_difference = time2 - time1
seconds_difference = time_difference.total_seconds()
return seconds_difference
# 定义时间格式
time_format = "%a, %d %b %Y %H:%M:%S GMT"
# 目标URL
url = 'http://127.0.0.1/status?format=json'
# 发送数据的IP地址和端口
target_ip = '47.96.136.178'
target_port = 8080
# 定义一个数组来存储last_check_time的值
last_check_times = []
last_receive_times = []
last_response_times = []
tmp = ''
pos = 0
while True:
# 从URL获取数据
response = requests.get(url)
data = response.json()
tip = 0
pos = pos + 1
# 检查 'servers' 和 'server' 键是否存在
if 'servers' in data and 'server' in data['servers']:
# 遍历服务器数据
for server in data['servers']['server']:
# 将对应的值添加到数组中
if (pos == 1):
# 数组初添加
last_check_times.append(server['last_check_time'])
else:
# 修正处理json数据
server['last_check_time'] = tmp
# 存放到数组中
last_check_times[tip] = tmp
# 修正调整
if (server['last_receive_time'] == ''):
server['last_receive_time'] = 'Null'
if (pos == 1):
last_receive_times.append(server['last_receive_time'])
else:
last_receive_times[tip] = server['last_receive_time']
tip = tip + 1
print("last_check_times:", last_check_times)
print("last_receive_times:", last_receive_times)
##分析计算出服务器响应时间:
for i in range(len(last_check_times)):
# 初次添加
if (pos == 1):
if (last_receive_times[i] == 'Null'):
last_response_times.append('Null')
if (last_receive_times[i] != 'Null'):
responseTime = calResponseTime(last_check_times[i], last_receive_times[i], time_format)
last_response_times.append(responseTime)
else:
if (last_receive_times[i] == 'Null'):
last_response_times[i] = 'Null'
if (last_receive_times[i] != 'Null'):
responseTime = calResponseTime(last_check_times[i], last_receive_times[i], time_format)
last_response_times[i] = responseTime
# 加入到发送数据中:
for server, responseTime in zip(data['servers']['server'], last_response_times):
server['last_response_time'] = responseTime
for i in range(len(last_check_times)):
if (last_receive_times[i] != 'Null'):
tmp = last_receive_times[i]
last_check_times[i] = last_receive_times[i]
# 打印数组内容,查看存储的值
print("last_response_times:", last_response_times)
# 使用自定义的编码器将数据转换为JSON格式的字符串
json_data = json.dumps(data, cls=CustomEncoder)
print(json_data)
# 目标服务器的IP地址和端口
target_url = 'http://47.96.136.178:8080'
# 发送POST请求
# 指定发送的内容类型为JSON
headers = {'Content-Type': 'application/json'}
response = requests.post(target_url, data=json_data, headers=headers)
# 检查请求是否成功
if response.status_code == 200:
print("数据成功发送。")
else:
print("数据发送失败,状态码:", response.status_code)
print("数据已发送到IP{},端口:{}".format(target_ip, target_port))
# 等待2.5秒
time.sleep(2.5)
# 读取文件
def read_log(file_path):
with open(file_path, 'r') as file:
# 读取所有行
log_lines = [line.strip() for line in file]
return log_lines
# # 指定文件路径
# file_path = '/usr/local/nginx/logs/access.log'
#
# # 指定目标IP和端口
# targeturl = 'http://47.96.136.178:8080'
# 构造JSON数据并发送
# def send_json(url, data):
# headers = {'Content-Type': 'application/json'}
# # 将数据构造为JSON格式
# json_data = json.dumps({"logs": data})
# response = requests.post(url, data=json_data, headers=headers)
# return response
# try:
# # 读取日志文件并转换为JSON
# log_data = read_log(file_path)
#
# # 发送数据
# response = send_json(targeturl, log_data)
#
# # 打印响应状态码和内容
# print(f'Status Code: {response.status_code}')
# print(f'Response Content: {response.text}')
# except Exception as e:
# print(f'An error occurred: {e}')

@ -0,0 +1,53 @@
# encoding: utf-8
# @author: 原凯峰
# @contact: 2894340009@qq.com
# @software: pycharm
# @file: Server.py
# @time: 2024/6/19 9:22
# @desc:
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
from MessageHandler.PreDataProcessor import *
import time
class CORSHTTPRequestHandler(BaseHTTPRequestHandler):
def do_OPTIONS(self):
self.send_response(204)
self.send_header('Content-type', 'text/plain')
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
self.end_headers()
def do_POST(self):
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length)
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()
print("Request line:", self.requestline)
print("Headers:", self.headers)
print("Body:", post_data.decode('utf-8'))
# 处理程序
MessageProcessor = preDataProcessor(post_data)
# response = {"POST": "request received"}
# self.wfile.write(str(response).encode('utf-8'))
# time.sleep(1)
backMessage =MessageProcessor.returnMessage
response = {"POST": backMessage}
self.wfile.write(str(json.dumps(response)).encode('utf-8'))
# self.wfile.write("{\"POST\": \"request received\"}".encode('utf-8'))
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()
self.wfile.write(b"Hello, world!")

@ -0,0 +1,60 @@
#!/usr/bin/env python
# encoding: utf-8
# @author: 原凯峰
# @contact: 2894340009@qq.com
# @software: pycharm
# @file: aiohttpserver.py
# @time: 2024/6/19 23:11
# @desc:
import asyncio
import aiohttp
from aiohttp import web
async def process_data(data):
# 这里模拟异步数据处理,例如通过网络请求或数据库操作
await asyncio.sleep(1) # 模拟异步操作的延时
return f"Processed: {data}"
# 定义CORS中间件
async def add_cors_headers(request, handler):
# 设置CORS相关的响应头
response = handler(request) # 先调用handler处理请求获取response
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
# 检查请求方法是否为OPTIONS
if request.method == 'OPTIONS':
# OPTIONS请求返回204状态码不返回body
return web.Response(status=204, headers=response.headers)
return response
# 创建应用
app = web.Application(middlewares=[add_cors_headers])
# 定义路由和视图函数
async def handle_options(request):
return web.Response(status=204)
async def handle_post(request):
data = await request.post()
post_data = await data.text() # 异步读取POST数据
processed_data = await process_data(post_data)
return web.json_response({
"POST": "request received",
"processed_data": processed_data
})
async def process_data(data):
await asyncio.sleep(1) # 模拟异步操作的延时
return f"Processed: {data}"
# 添加路由
app.add_routes([web.route('OPTIONS', '/', handle_options),
web.route('POST', '/', handle_post)])
if __name__ == '__main__':
web.run_app(app, host='127.0.0.1', port=8080)

@ -0,0 +1,23 @@
def query_ip_location(ip_address, ip_data_file):
result = None
with open(ip_data_file, 'r', encoding='utf-8') as f:
for line in f:
if line.strip(): # 确保行非空
parts = line.split()
if len(parts) >= 3:
start_ip = parts[0]
end_ip = parts[1]
location_info = ' '.join(parts[2:])
if ip_address >= start_ip and ip_address <= end_ip:
result = location_info.split('')[1].strip() # 获取中国的地区信息
break
return result
# 示例用法
ip_data_file = 'china_ip_address.txt'
ip_address_to_query = '1.173.45.67' # 替换为你想要查询的IP地址
location = query_ip_location(ip_address_to_query, ip_data_file)
if location:
print(f"{ip_address_to_query} 所在的省级地域是:{location}")
else:
print(f"未找到 {ip_address_to_query} 的地理位置信息。")

@ -0,0 +1,363 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" rel="stylesheet" type="text/css" />
<script>
var data=[
{
message:'192.172.0.1 is Master,192.173.0.2 is Backup'
}
];
  renderEl(data.message);
paintVis(data.message);
function renderEl(arr) {
        let str = '';
        str += `
           <table>
<caption>
当前网络中网关情况:
</caption>
<thead>
<tr>
<th scope="col">服务器IP</th>
<th scope="col">服务器状态</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">${arr.substr(0,arr.indexOf("Master")-3)}</th>
<td>Master</td>
</tr>
<tr>
<th scope="row">${arr.substr(arr.indexOf("Master")+6,arr.indexOf("Backup")-3)}</th>
<td>Backup</td>
</tr>
</table>
`;
const el = document.getElementById('wrap');
        el.innerHTML = str;
}
function paintVis(arr){
var nodes = new vis.DataSet([
{ id: 1, label: 'keepalived:vrrp\n 192.168.229.130',color: {background: 'lightgreen'}},
{ id: 2, label: arr.substring(0,arr.indexOf("Master")-3),color: {background: 'lightgreen'}},
{ id: 3, label: arr.substring(arr.indexOf("Master")+6,arr.indexOf("Backup")-3),color: {background: 'grey'}},
{ id: 4, label: 'web Server\n 192.168.229.129.81',color: {background: 'lightgreen'}},
{ id: 5, label: 'web Server\n 192.168.229.129.81',color: {background: 'grey'}},
{ id: 6, label: '客户端',color: {background: 'lightgreen'} },
]);
var edges = new vis.DataSet([
{ from: 6, to: 1 , color: {color:'#00ff00'}},
{ from: 1, to: 2 , color: {color:'#00ff00'}},
{ from: 1, to: 3 , color: {color:'grey'}},
{ from: 2, to: 4 , color: {color:'#00ff00'}},
{ from: 2, to: 5 , color: {color:'#00ff00'}},
{ from: 3, to: 4 , color: {color:'grey'}},
{ from: 3, to: 5 , color: {color:'#00ff00'}},
]);
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {
nodes: {
shape:'dot',
font: {
color: '#000', // 字体的颜色
size: 10 // 显示字体大小
},
scaling: {
min: 20,
max: 40 // 缩放效果比例
},
borderWidth: 1,
color: {
border: 'white',
// 若是引用图标,背景颜色
}
},
groups: {
ws: { // 系统定义的形状 dot等 这些官网都可以找到
shape: 'square',
color: 'white'
}
},
layout: {
randomSeed: 1 // 配置每次生成的节点位置都一样参数为数字1、2等
},
physics: {
// barnesHut: { gravitationalConstant: -30000 },
barnesHut: {
gravitationalConstant: 0,
springConstant: 0,
springLength: 0
},
stabilization: true
// { iterations: 2500 }
},
interaction: {
// navigationButtons: true,
hover: false, // 鼠标移过后加粗该节点和连接线
selectConnectedEdges: false, // 选择节点后是否显示连接线
hoverConnectedEdges: false, // 鼠标滑动节点后是否显示连接线
tooltipDelay: 200,
zoomView: false // 是否能缩放画布
},
edges: {
label:'Solid',
smooth: {type: "discrete"},
color: { // 连接线的样式
hover: '#848484',
inherit: 'from',
opacity: 1.0
},
shadow: true, // 连接线阴影配置
smooth: true // 是否显示方向箭头
// arrows: {to : true }//箭头指向from节点
}
};
var network = new vis.Network(container, data, options);
}
</script>
<style>
table{
width: 50%;
border-collapse: collapse;
margin: auto;
}
table caption{
font-size: large;
font-weight: bold;
margin: 1em 0;
}
th,td{
border: 1px solid #999;
text-align: center;
padding: 20px 0;
}
table thead tr{
background-color: #008c8c;
color: #fff;
}
table tbody tr:nth-child(odd){
background-color: #eee;
}
table tbody tr:hover{
background-color: #ccc;
}
table tbody tr td:first-child{
color: #f40;
}
table tfoot tr td{
text-align: right;
padding-right: 20px;
}
#dropdownMenu {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.dropdown-item {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown-item:hover {
background-color: #f1f1f1;
}
</style>
<header>
<div style="text-align: center; padding-right: 10px; flex: 1 1 0%;font-size: large;background-color: rgb(227, 234, 234);">主备切换</div>
</header>
<body>
<table>
<caption>
当前网络中网关情况:
</caption>
<div id="wrap"></div>
</body>
<div id="dropdownMenu" class="dropdown-content">
<a href="#" class="dropdown-item" id="toggleOpen">开启</a>
<a href="#" class="dropdown-item" id="toggleClose">关闭</a>
</div>
<h1>网络拓扑图<button id="submitBtn">提交</button></h1>
<div id="doubleClickArea">
<div id="mynetwork" style="width:auto; height:500px; border:1px solid lightgray;"></div>
</div>
<script>
var nodes = new vis.DataSet([
{ id: 1, label: 'keepalived:vrrp\n 192.168.229.130',color:'lightgreen'},
{ id: 2, label: 'nginx负载均衡\n 192.168.229.128:80',color:'lightgreen'},
{ id: 3, label: 'nginx负载均衡\n 192.168.229.129.80',color: 'grey'},
{ id: 4, label: 'web Server\n 192.168.229.129.81',color:'lightgreen'},
{ id: 5, label: 'web Server\n 192.168.229.129.81',color: 'grey'},
{ id: 6, label: '客户端',color:'lightgreen' },
]);
var edges = new vis.DataSet([
{ id: 7,from: 6, to: 1 , color: '#00ff00'},
{ id: 8,from: 1, to: 2 , color: '#00ff00'},
{ id: 9,from: 1, to: 3 , color: 'grey'},
{ id: 10,from: 2, to: 4 , color: '#00ff00'},
{ id: 11,from: 2, to: 5 , color: '#00ff00'},
{ id: 12,from: 3, to: 4 , color: 'grey'},
{ id: 13,from: 3, to: 5 , color: '#00ff00'},
]);
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {
nodes: {
shape:'dot',
font: {
color: '#000', // 字体的颜色
size: 10 // 显示字体大小
},
scaling: {
min: 20,
max: 40 // 缩放效果比例
},
borderWidth: 1,
color: {
border: 'white',
// 若是引用图标,背景颜色
}
},
groups: {
ws: { // 系统定义的形状 dot等 这些官网都可以找到
shape: 'square',
color: 'white'
}
},
layout: {
randomSeed: 1 // 配置每次生成的节点位置都一样参数为数字1、2等
},
physics: {
// barnesHut: { gravitationalConstant: -30000 },
barnesHut: {
gravitationalConstant: 0,
springConstant: 0,
springLength: 0
},
stabilization: true
// { iterations: 2500 }
},
interaction: {
// navigationButtons: true,
hover: true, // 鼠标移过后加粗该节点和连接线
selectConnectedEdges: false, // 选择节点后是否显示连接线
hoverConnectedEdges: false, // 鼠标滑动节点后是否显示连接线
tooltipDelay: 200,
zoomView: false // 是否能缩放画布
},
edges: {
label:'Solid',
smooth: {type: "discrete"},
color: { // 连接线的样式
inherit: 'from',
},
shadow: false, // 连接线阴影配置
smooth: true // 是否显示方向箭头
// arrows: {to : true }//箭头指向from节点
}
};
var network = new vis.Network(container, data, options);
network.on('click', function (event) {
nodeId = event.nodes[0]; // 获取被点击的节点ID
nodeData = nodes.get(nodeId); // 根据节点ID获取节点数据
if (nodeData) {
console.log('Clicked on node: ' + nodeData.id + '\n' +
'Entity Info: ' + nodeData.label+ '\n' +
'Color Info:' + nodeData.color);
// 可以在这里添加更多的逻辑来处理点击事件
}
});
var doubleClickArea = document.getElementById('doubleClickArea');
var dropdownMenu = document.getElementById('dropdownMenu');
// 为双击区域添加双击事件监听器
doubleClickArea.addEventListener('dblclick', function(event) {
// 显示下拉菜单
var nodeToUpdate = nodes.get(nodeId);
if (nodeToUpdate.color === 'grey') {
nodeToUpdate.color = '#00ff00';
} else {
nodeToUpdate.color = 'grey';
}
nodes.update([nodeToUpdate]);
});
function updateEdgeColor() {
// 获取所有节点的颜色
for(var i=1;i<=6;i++){
for(var j=1;j<=6;j++)
{
var node1Color =nodes.get(i).color;
var node2Color =nodes.get(j).color;
var edgeColor = ((node1Color =="lightgreen") && (node2Color =="lightgreen")) ? 'green' : 'grey';
var edge = edges.get({ from: i, to: j });
if (edge) {
edge.color = { color: edgeColor };
console.log("Update")
edges.update(edge);
}
}
}
// 更新边的颜色
for(var i=0;i<=6;i++)
{
for(var j=0;j<=6;j++)
{
var edge = edges.get({ from: i, to: j });
if (edge) {
edge.color = { color: edgeColor };
console.log("Update")
edges.update(edge);
}
}
}
}
setInterval(updateEdgeColor, 3000); // 每3000毫秒3秒更新一次
var submitButton = document.getElementById('submitBtn');
// 为提交按钮添加点击事件监听器
submitButton.addEventListener('click', function() {
// 从Vis.js网络图中获取当前的nodes信息
var currentNodes = nodes.get();
// 将nodes信息转换为JSON格式
var nodesJson = JSON.stringify(currentNodes);
// 使用fetch API发送数据到后端服务器
fetch('YOUR_BACKEND_ENDPOINT', { // 替换为你的后端服务器端点
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: nodesJson
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
});
</script>

@ -0,0 +1,686 @@
`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Title</title>
<link rel="stylesheet" type="text/css" href="msgList.css">
<link rel="stylesheet" href="./assets/css/style.css">
<script type="text/javascript" src="./assets/js/jquery.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="./echarts.min.js"></script>
</head>
<style>
#pie {
width: 400px;
height: 400px;
}
.mainbody{
position: absolute;
left: 190px;
}
.wrap{
width: 260px;
height: 100%;
background-color: #dce0e9;
position: fixed;
}
.wrap-hidden{
transform: translateX(-150%);
}
.header{
width: 100%;
height: 65px;
background-color: #adadad;
font-size: 24px;
color: #fff;
text-align: center;
line-height: 65px;
}
.nav{
width:250px;
margin: 10px 5px 0;
}
.list{
margin-bottom: 5px;
}
.list h2{
position: relative;
padding: 15px 0;
background-color: #3889d4;
text-align: center;
font-size: 16px;
color: #fff;
transition: .5s;
}
.list h2.on{
background-color: #393c4a;
}
.list i{
position: absolute;
right: 10px;
top: 16px;
border: 8px solid transparent;
border-left-color: #fff;/*triangle*/
transform:rotate(0deg);
transform-origin: 1px 8px;
transition: .5s;
}
.list i.on{
transform:rotate(90deg);
}
.hide{
overflow: hidden;
height: 0;
transition: .5s;
}
.hide h5{
padding: 10px 0;
background-color: #282c3a;
text-align: center;
color:#fff;
border-bottom:#42495d;
div{
display: block;
}
.h1, .h2, .h3, .h4, .h5, .h6, a, abbr, body, cite, dd, dl, dt, h1, h2, h3, h4, h5, h6, iframe, input, li, object, ol, p, pre, span, ul {
font-family: 'Microsoft YaHei','SF Pro Display',Roboto,Noto,Arial,'PingFang SC',sans-serif;
}
a{
text-decoration: none;
cursor: pointer;
}
ul, li, ol, dl, dt, dd {
list-style: none;
}
div, figure, footer, header, hgroup, html, iframe, img, mark, menu, nav, object, section, span, table, tr, td, th, tbody, tfoot, thead, video {
border: 0;
margin: 0;
padding: 0;
}
.my_msg_list{
position:inherit;
margin-top: 50px;
width: 1300px;
min-height: 400px;
margin-bottom: 20px;
}
.my_msg_list_view{
position: relative;
margin-left: 100px;
background-color: #fff;
padding: 24px 16px;
-webkit-box-shadow: 0 2px 4px 0 rgba(0,0,0,0.28);
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.28);
min-height: 520px;
box-sizing: border-box;
}
.my_msg_list_box{
border: 0;
margin: 0;
padding: 0;
box-sizing: border-box;
}
.my_msg_list_con{
border: 0;
margin: 0;
padding: 0;
box-sizing: border-box;
}
.my_msg_list_title{
width: 100%;
margin: 0;
font-size: 14px;
color: #3d3d3d;
margin-bottom: 8px;
display: block;
overflow: hidden;
zoom: 1;
box-sizing: border-box;
}
.fr{
float: right!important;
display: inline-block;
color: #4a90e2;
}
.line{
display: inline-block;
height: 12px;
margin: 2px 12px;
border-right: 1px solid #979797;
}
.msg_list{
padding: 0 0 0 15px;
min-height: 370px;
box-sizing: border-box;
}
.msg_list_ul{
font-size: 14px;
vertical-align: baseline;
margin: 0;
padding: 0;
}
.msg_list_ul_li{
position: relative;
padding: 16px 0;
border-bottom: 1px solid #e0e0e0;
}
.msg_type{
display: inline-block;
height: 40px;
line-height: 40px;
padding: 0 5px;
color: #4d4d4d;
font-size: 25px;
text-align: center;
background-color: #fff;
border: 1px solid #e0e0e0;
vertical-align: top;
}
.msg_info_box{
width: 100%;
color: #4d4d4d;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
}
.msg_title{
display: inline-block;
width: 85%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
}
.options-f{
width: 16%;
height: 20px;
margin: 0;
margin-top: -20px;
padding: 0;
}
.msg_delete{
width: 10px;
height: 10px;
float: right;
}
.msg_content{
margin-top: 15px;
margin-bottom: -16px;
padding: 15px;
background-color: #f7f7f7;
font-size: 14px;
color: #4d4d4d;
line-height: 22px;
}
.page-box{
width: 100%;
margin: 32px 0 20px;
text-align: center;
border-top-color: initial;
border-right-color: initial;
border-bottom-color: initial;
border-left-color: initial;
}
.ule {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
}
.lie {
width: 12%;
display: inline-block;
font: 13px sans-serif;
}
.lie a {
display: block;
color: rgb(39, 124, 184);
text-align: center;
padding: 14px 70px;
text-decoration: none;
}
.lie a:hover {
background-color: #e3e3f5;
}
.ula {
width: 100%;
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
}
.lia {
width: 12%;
display: inline-block;
font: 13px sans-serif;
}
.lia a {
font-size: larger;
color: rgb(0, 0, 0);
text-align: center;
padding: 14px 50px;
text-decoration: none;
}
.lia a:hover {
background-color: #b7b7b7;
}
.square{
width:200px;
height:5px;
border:1px solid transparent;
background: #06b81a;
}
.modal {
display: none;
position: fixed;
z-index: 999;
left: 0;
top: 0;
width: 100px;
height: 100px;
overflow: auto;
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 50%;
max-width: 600px; /* 限制图表的最大宽度 */
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
}
#chart-container {
width: 500px;
height: 800px;
margin: auto;
}
.circle-tag {
width: 20px;
height: 20px;
border-radius: 100%;
background-color: #3498db;
color: white;
text-align:left;
font-size: 16px;
font-family: Arial, sans-serif;
display: grid;
}
</style>
<header class="top-navigation">
<div class="container">
<a class="logo" aria-label="MDN homepage"><svg id="mdn-docs-logo" x="0" y="0" viewBox="0 0 694.9 10.4" style="enable-background:new 0 0 694.9 104.4" role="img"><title>MDN Web Docs</title>
<button title="Open main menu" type="button" class="button action has-icon main-menu-toggle" aria-haspopup="true" aria-label="Open main menu" aria-expanded="true"><span class="button-wrap"><span class="icon icon-menu "></span><span class="visually-hidden"><a href="MainPageUI.html">Open main menu</a></span></span></button>
</div>
</header>
<body>
<button id="toggleSidebar">隐藏/显示 侧边栏</button>
<div class="wrap">
<div class="header">消息过滤器</div>
<div class="nav">
<ul>
<li class="list">
<h2><i></i>服务器</h2>
<div class="hide">
<h5>北京</h5>
<h5>长沙</h5>
<h5>上海</h5>
</div>
</li>
<li class="list">
<h2><i></i>响应时间</h2>
<div class="hide">
<h5>"<=100ms"</h5>
<h5>"<=1500ms"</h5>
<h5>">1500ms"</h5>
</div>
</li>
<li class="list">
<h2><i></i>当前服务器状态</h2>
<div class="hide">
<h5>正常</h5>
<h5>受损</h5>
<h5>繁忙</h5>
</div>
</li>
<li class="list">
<h2><i></i>返回消息报头</h2>
<div class="hide">
<h5>TCP</h5>
</div>
</li>
</ul>
</div>
</div>
<script>
(function () {
var oList = document.querySelectorAll('.list h2'),
oHide = document.querySelectorAll('.hide'),
oIcon = document.querySelectorAll('.list i'),
lastIndex = 0;
for(var i=0;i<oList.length;i++){
oList[i].index = i;
oList[i].isClick = false;
oList[i].initHeight = oHide[i].clientHeight;
oHide[i].style.height = '0';
oList[i].onclick = function () {
if(this.isClick){
oHide[this.index].style.height = '0';
oIcon[this.index].className = '';
oList[this.index].className = '';
oList[this.index].isClick = false;
}
else{
oHide[lastIndex].style.height = '0';
oIcon[lastIndex].className = '';
oList[lastIndex].className = '';
oHide[this.index].style.height = '220px';
oIcon[this.index].className = 'on';
oList[this.index].className = 'on';
oList[lastIndex].isClick = false;
oList[this.index].isClick = true;
lastIndex = this.index;
}
}
}
})();
</script>
<div class="mainbody">
<div class="chart-container">
<div class="chart-card">
<h4 class="h3">消息类别统计表</h4>
<table class="card-table">
<tbody class="table-body flex-center">
<div id="graph"></div>
</tbody>
</table>
<span class="tooltip text" data-tooltip></span>
<div class="wrapper flex-center">
<div class="card-meta">
<p class="text">最近7天总共有</p>
<data class="meta-value" value="478.33">478条</data>
</div>
<div class="card-meta">
<data class="meta-value small" value="2.4">+2.4%</data>
<p class="text">from last month</p>
</div>
</div>
</div>
</div>
<div class="piechart" id="pie"></div>
<script>
</script>
<!-- 假设这是您的消息列表容器 -->
<div id="my_msg_list">
<div class="my_msg_list_view">
<div class="my_msg_list_box">
<div class="my_msg_list_con">
<div class="my_msg_list_title">
<span >消息列表:</span>
<a class="fr">清空所有消息</a>
<span class="line fr"></span>
<a class="fr">全部标记为已读</a>
</div>
<div class="ule">
<div class="lie"><a href="#home">服务器列表</a></div>
<div class="lie"><a href="#location">地区</a></div>
<div class="lie"><a href="#news">距离上次响应时间</a></div>
<div class="lie"><a href="#contact">当前服务器状态</a></div>
<div class="lie"><a href="#about">返回消息报头</a></div>
</div>
<div id="mylist"></div>
<!-- 消息列表将在这里动态生成 -->
<div class="page-box">
</div>
</div>
</div>
</div>
</div>
</div>
</html>
<script>
// 假设这是您接收到的JSON数据
var jsonData = [
{
"server": "127.0.0.1",
"location":"北京",
"responseTime": "100ms",
"status": "正常",
"protocol": "TCP",
"date": "2024-07-01",
"value":200
},
{
"server": "127.0.0.2",
"location":"上海",
"responseTime": "1300ms",
"status": "受损",
"protocol": "TCP",
"date": "2024-07-01",
"value":30
},
{
"server": "127.0.0.3",
"location":"广州",
"responseTime": "70ms",
"status": "繁忙",
"protocol": "TCP",
"date": "2024-07-01",
"value":50
}
];
var jsonData2 = [
{
"server": "127.0.0.1",
"location":"北京",
"responseTime": "70ms",
"status": "正常",
"protocol": "TCP",
"date": "2024-07-01",
"value":250
},
{
"server": "127.0.0.2",
"location":"上海",
"responseTime": "150ms",
"status": "正常",
"protocol": "TCP",
"date": "2024-07-01",
"value":70
},
{
"server": "127.0.0.3",
"location":"广州",
"responseTime": "70ms",
"status": "繁忙",
"protocol": "TCP",
"date": "2024-07-01",
"value":50
}
];
var jsonData3 = [
{
"server": "127.0.0.1",
"location":"北京",
"responseTime": "75ms",
"status": "正常",
"protocol": "TCP",
"date": "2024-07-01",
"value":300
},
{
"server": "127.0.0.2",
"location":"上海",
"responseTime": "120ms",
"status": "正常",
"protocol": "TCP",
"date": "2024-07-01",
"value":100
},
{
"server": "127.0.0.3",
"location":"广州",
"responseTime": "100ms",
"status": "正常",
"protocol": "TCP",
"date": "2024-07-01",
"value":60
}
];
// 函数用于更新消息列表
function updateMessageList(data) {
var msgListContainer = document.getElementById('mylist');
msgListContainer.innerHTML = ''; // 清空现有内容
data.forEach(function(item) {
var msgItem = document.createElement('div');
msgItem.className = 'msg_item';
msgItem.innerHTML = `
<li class="msg_list_ul_li">
<div class="ula">
<div class="lia"><a href="test.html"><div class="circle-tag"></div><span></span>${item.server}</a></div>
<div class="lia"><a href="#location">${item.location}</a></div>
<div class="lia"><a href="#news">${item.responseTime}</a></div>
<div class="lia"><a href="#contact">${item.status}</a></div>
<div class="lia"><a href="#about">${item.protocol}</a></div>
</div>
<em class="data-time" style="float: right;padding-right:10px">${item.date}</em>
</li>
`;
msgListContainer.appendChild(msgItem);
});
}
function updateGraph(data) {
var msgListContainer = document.getElementById('graph');
msgListContainer.innerHTML = ''; // 清空现有内容
data.forEach(function(item) {
var msgItem = document.createElement('div');
msgItem.className = 'msg_item';
msgItem.innerHTML = `
<tr class="table-row flex-center">
<th class="table-heading" scope="col">${item.server}</th>
<td class="table-data">
<div class="chart-bar" data-chart-bar="&{item.server}">${item.value}</div>
</td>
</tr>
`;
msgListContainer.appendChild(msgItem);
});
}
var pie = echarts.init(document.getElementById('pie'));
// 饼状图配置项
var pieOption = {
title: {
text: '数据统计饼状图'
},
tooltip: {
show: true,
trigger: "item",
backgroundColor: "#1677FF",
formatter: "{a}{b}<br/>{c}次({d}%)"
},
color: ['#3e87ff', '#65b2f3', '#b9cfec'],
series: [
{
name: '服务器名',
type: 'pie',
radius: '50%',
center: ['50%', '50%'],
// 初始化为空数组数据将根据jsonData动态设置
data: [],
itemStyle: {
normal: {
label: {
show: true
},
labelLine: {
show: true
}
},
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
// 将jsonData转换为饼状图的数据格式
function generatePieData(jsonData) {
return jsonData.map(function (item) {
return {
value: item.value,
name: item.server
};
});
}
function updatePieChart(jsonData) {
pieOption.series[0].data = generatePieData(jsonData);
pie.setOption(pieOption);
}
//侧边栏隐藏显示切换
document.addEventListener('DOMContentLoaded', function () {
var toggleSidebarButton = document.getElementById('toggleSidebar');
var sidebar = document.querySelector('.wrap');
toggleSidebarButton.addEventListener('click', function () {
sidebar.classList.toggle('wrap-hidden');
});
});
function updateAll(){
updatePieChart(jsonData);// 调用函数以更新消息列表
updateGraph(jsonData)
updateMessageList(jsonData);
setTimeout(function(){
updateAll2();
},5000);
}
function updateAll2(){
updatePieChart(jsonData2);// 调用函数以更新消息列表
updateGraph(jsonData2)
updateMessageList(jsonData2);
setTimeout(function(){
updateAll3();
},5000)
}
function updateAll3(){
updatePieChart(jsonData3);// 调用函数以更新消息列表
updateGraph(jsonData3)
updateMessageList(jsonData3);
}
updateAll();
</script>
</body>
</html>

@ -0,0 +1,132 @@
<style>
.loader {
background: #ffffff;
background: radial-gradient(#ffffff, #ffffff);
bottom: 0;
left: 0;
overflow: hidden;
position: fixed;
right: 0;
top: 0;
z-index: 99999;
}
.loader-inner {
bottom: 0;
height: 60px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap {
animation:
spin 2000ms cubic-bezier(.175, .885, .32, 1.275) infinite
;
box-sizing: border-box;
height: 50px;
left: 0;
overflow: hidden;
position: absolute;
top: 0;
transform-origin: 50% 100%;
width: 100px;
}
.loader-line {
border: 4px solid transparent;
border-radius: 100%;
box-sizing: border-box;
height: 100px;
left: 0;
margin: 0 auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap:nth-child(1) { animation-delay: -50ms; }
.loader-line-wrap:nth-child(2) { animation-delay: -100ms; }
.loader-line-wrap:nth-child(3) { animation-delay: -150ms; }
.loader-line-wrap:nth-child(4) { animation-delay: -200ms; }
.loader-line-wrap:nth-child(5) { animation-delay: -250ms; }
.loader-line-wrap:nth-child(1) .loader-line {
border-color: hsl(0, 80%, 60%);
height: 90px;
width: 90px;
top: 7px;
}
.loader-line-wrap:nth-child(2) .loader-line {
border-color: hsl(60, 80%, 60%);
height: 76px;
width: 76px;
top: 14px;
}
.loader-line-wrap:nth-child(3) .loader-line {
border-color: hsl(120, 80%, 60%);
height: 62px;
width: 62px;
top: 21px;
}
.loader-line-wrap:nth-child(4) .loader-line {
border-color: hsl(180, 80%, 60%);
height: 48px;
width: 48px;
top: 28px;
}
.loader-line-wrap:nth-child(5) .loader-line {
border-color: hsl(240, 80%, 60%);
height: 34px;
width: 34px;
top: 35px;
}
@keyframes spin {
0%, 15% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
</style>
<div class="loader">
<div class="loader-inner">
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
</div>
</div>
<style>
.login {
position: absolute;
top: 50%;
left: 75%;
margin: -150px 0 0 -150px;
width:300px;
height:300px;
}
</style>
<html>
<body>
<h1>welcome</h1>
</body>
<script>
setTimeout(()=>location.href="LoginUI.html",5000);
</script>
</html>

@ -0,0 +1,199 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>LoginUI</title>
<script type="text/javascript">
function submits(btn){
var userName = document.getElementById("username").value;
var pwd = document.getElementById("pwd").value;
console.log(userName)
if (userName == "admin" && pwd == "admin") {
window.location.href="MainPageUI.html";
window.event.returnValue=false;
}
else {
alert("用户名或密码不正确!");
}
}
</script>
<style>
/* 让页面所有元素的padding和margin都设置为0 */
/*{margin:0;padding:0;box-sizing:border-box;}*/
h3{
right: 0;
}
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 150px 150px;
grid-gap: 10px;
}
/* 设置背景图,字体设置为微软雅黑 */
body{background:url(bg.jpg);font-family: "微软雅黑", sans-serif;}
/* 引用图片高度设置为28px就是页面最上方像屋檐一样的黑色图 */
.headtop{background:url(dove.png);height:28px;}
/* 整个登录框的css并使用绝对定位居中 */
.login {
position: absolute;
top: 50%;
left: 75%;
margin: -150px 0 0 -150px;
width:300px;
height:300px;
}
.login h1 { color:#555555; text-shadow: 0px 10px 8px #CDC673; letter-spacing:2px;text-align:center;margin-bottom:20px; }
input{
grid-column: 2;
grid-row: 1/3;
padding:10px;
width:100%;
color:white;
margin-bottom:10px;
background-color:#555555;
border: 1px solid black;
border-radius:4px;
letter-spacing:2px;
}
.imgBox{
padding-top: 180px;
border-top: 2px solid cadetblue;
width: 100%;
height: 450px;
margin: 0 auto;
}
.imgBox img{
width: 100%;
height: 450px;
margin: 0 auto;
padding-top: 30px;
}
.img1{
display: block;
}
.img2{
display: none
}
.img3{
display: block;
}
.box1 {
grid-column: 2;
grid-row: 1/3;
}
label{
color: #ffffff;
font-weight: bold;
font-size: 20px;
margin-left: 40px;
}
.box2 {
grid-column: 1;
grid-row: 1 / 3;
}
/* 登录按钮的csscursor:pointer当鼠标移到按钮上面时变成小手形状 */
form button{
width: 107%;
padding:10px;
background-color:#CDC673;
border:1px solid black;
border-radius:4px;
cursor:pointer;
}
</style>
</head>
<body style="background-image:url('./assets/images/R-C\ \(1\).png'); background-repeat:no-repeat; background-position:center center; background-attachment:fixed; background-size:cover;">
<div class="wrapper">
<div class="box1">
<div class="headtop"></div>
<div class="login">
<h1 style="font-size: 25px;">//欢迎来到HADG的登入界面//</h1>
<h1 style="font-size: 15px;">请核实您登入的身份</h1>
<form action="" method="post">
<label for="username">用户名</label><br>
<input type="text" name="username" id="username" class="input" value="" placeholder="用户名admin"><br>
<label for="pwd">密码</label><br>
<input type="password" name="" id="pwd" class="input" value="" placeholder="密码admin">
<button type="submit" class="submit" onclick="submits(this)">开始登录</button>
</form>
<td class="login_td" align="right" width=71><a
href="RegisterUI.html"
>新用户注册</a></td>
</div>
</div>
<div class="imgBox">
<img class="img-slide img1"
src="./assets/images/img1.jpg"
alt="1"
/>
<img class="img-slide img2"
src="./assets/images/img2.jpg"
alt="2"
/>
</div>
</div>
</div>
</body>
<script type="text/javascript">
var index=0;
//效果
function ChangeImg() {
index++;
var a=document.getElementsByClassName("img-slide");
if(index>=a.length) index=0;
for(var i=0;i<a.length;i++){
a[i].style.display='none';
}
a[index].style.display='block';
}
//设置定时器,每隔两秒切换一张图片
setInterval(ChangeImg,8000);
</script>
</html>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 获取表单元素
var form = document.querySelector('.ant-form');
// 为表单添加提交事件监听器
form.addEventListener('submit', function(e) {
e.preventDefault(); // 阻止表单的默认提交行为
// 收集表单数据
var formData = {
//question_kind: document.getElementsByName('question_kind').value,
type:"login_message",
username: document.getElementById('username').value,
password: document.getElementById('password').value,
};
console.log(formData);
// 使用fetch API发送数据到后端
fetch('http://localhost:8080/xmy', {
method: 'POST', // 或者 'PUT'
headers: {
'Content-Type': 'application/json',
// 如果需要认证添加Authorization头部
// 'Authorization': 'Bearer your_token_here'
},
body: JSON.stringify(formData) // 将表单数据转换为JSON字符串
})
.then(response => response.json()) // 转换响应为JSON
.then(data => {
console.log('Success:', data);
alert('登录成功提交!');
location.href = "./MainPageUI.html";
})
.catch((error) => {
console.error('Error:', error);
alert('登录失败,请检查用户名和密码!');
});
});
});
</script>

@ -0,0 +1,339 @@
<!DOCTYPE html>
<!-- 声明文档类型-->
<html lang="en">
<!-- 确定语言形态 -->
<style>
#pie {
width: 400px;
height: 400px;
}
.downorder{
width: 100px;
position: relative;
height: auto;
margin: auto;
}
.downorder:hover a{
display: block;
}
.order{
position: relative;
text-align: center;
display: inline-block;
font-size: 16px;
padding: 15px;
background-color: rgb(1, 1, 1);
color: aliceblue;
}
.order:hover{
background-color: rgb(0, 0, 0);
color: rgb(6, 80, 238);
}
.downtext{
position: relative;
text-align: center;
display: inline-block;
font-size: 10px;
background-color: rgba(182, 182, 182,0.75);
color: aliceblue;
}
.downtext a{
/* display: block; */
display: none;
padding: 15px;
}
.downtext a:hover{
background-color: rgba(182, 182, 182,0.25);
color: rgb(58, 76, 243);
}
/* 遮罩层 */
#overlay {
position: fixed;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
font-size: 16px;
/* IE9以下不支持rgba模式 */
background-color: rgba(0, 0, 0, 0.5);
/* 兼容IE8及以下 */
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#7f000000,endColorstr=#7f000000);
display: none;
}
/* 弹出框主体 */
.popup {
background-color: #ffffff;
max-width: 400px;
min-width: 200px;
height: 240px;
border-radius: 5px;
margin: 100px auto;
text-align: center;
}
/* 弹出框的标题 */
.popup_title {
height: 60px;
line-height: 60px;
border-bottom: solid 1px #cccccc;
}
/* 弹出框的内容 */
.popup_content {
height: 50px;
line-height: 50px;
padding: 15px 20px;
}
/* 弹出框的按钮栏 */
.popup_btn {
padding-bottom: 10px;
}
/* 弹出框的按钮 */
.popup_btn button {
color: #778899;
width: 40%;
height: 40px;
cursor: pointer;
border: solid 1px #cccccc;
border-radius: 5px;
margin: 5px 10px;
color: #ffffff;
background-color: #337ab7;
}
</style>
<script type="text/javascript" src="echarts.js"></script>
<head>
<meta charset="UTF-8">
<!--控制网页的编码格式 utf-8 国际性编码-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!--控制视口比例以及缩放-->
<title>首页</title>
<!-- 先引入重置样式表和公共样式表以及主页样式表 -->
<link rel="stylesheet" href="./css/index.css">
<link rel="stylesheet" href="./css/public.css">
<link rel="stylesheet" href="./css/reset.css">
<!-- 这个顺序引入更规范 -->
</head>
<body>
<!-- 这是网页的头部版心盒子 -->
<div class="header_con">
<!-- h1里面放logo哦 -->
<h1>
<img
width="150px"
height="80px"
src="./assets/images/Nginx.jpg" alt="">
</h1>
<!-- 头部右侧表单标签-->
<form action="">
<input type="text" class="search" value="SEARCH...">
<div>
<input type="button" class="btn">
</div>
</form>
</div>
<!-- 导航栏平铺部分:会显示黑色 -->
<div id="nav">
<!-- 导航栏版心部分 -->
<div class="nav_con">
<ul>
<li>
<div class="downorder">
<button class="order">
首页
</button>
<div class="downtext">
<a href="">查看主动探测</a>
<a href="">查看流量控制</a>
<a href="">查看Nginx日志</a>
</div>
</div></li>
<li>
<button class="order"
id="showPopup" onclick="showPopup()">系统设置</button>
<div id="overlay">
<div class="popup">
<p class="popup_title">系统设置</p>
<p class="popup_content">当前系统版本1.13</p>
<div class="popup_btn">
<button onclick="hidePopup()">确认</button>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
<!-- banner的平铺部分 -->
<div id="banner">
<div class="banner_con">
<a href="./index.html">
<img src="./assets/images/R-C.png"
height="466px"
width="1000px"
>
</a>
</div>
</div>
<!-- 新闻列表的版心部分 -->
<div class="news_con">
<!-- 最左侧的盒子 -->
<div class="news_l">
<h3 class="news_title">版本更新情况</h3>
<ul class="news_list">
<li>
<a>alpha 0.11 更新ui版本</a>
<span>2024-05-05</span>
</li>
<li>
<a>alpha 0.10 更新跳转其他界面逻辑</a>
<span>2024-05-03</span>
</li>
<li>
<a>alpha 0.09 更新LoginUI设计</a>
<span>1998-09-15</span>
</li>
</ul>
</div>
<!-- 中间的盒子-->
<div class="news_c">
<h3 class="news_title">服务器列表</h3>
<p class="txt1">北京 ip192.168.20.2</p>
<p class="txt1">广州 ip192.168.21.4</p>
<p class="txt1">长沙 ip192.168.23.4</p>
</div>
<!-- 右边的盒子 -->
<div class="news_r">
<h3 class="news_title">最近操作</h3>
<p class="txt3">开启主备切换服务</p>
<p class="txt3">开启Nginx服务</p>
<a href="#"><img src="./images/btn_img_05.jpg" alt=""></a>
</div>
</div>
<!-- 市场项目那一部分 -->
<div class="case_con">
<h3>当前可用服务</h3>
<div class="case_box">
<dl>
<dt><a href="DetectUI.html"><img src="./assets/images/R-C green.png" alt=""></a></dt>
<dd>查看主动探测</dd>
</dl>
<dl>
<dt><img src="./assets/images/R-C red.png" alt=""></dt>
<dd>查看流量控制</dd>
</dl>
<dl>
<dt><img src="./assets/images/R-C pink.png" alt=""></dt>
<dd>启用主备切换</dd>
</dl>
<dl>
<dt><img src="./assets/images/R-C blue.png"></dt>
<dd>查看Nginx日志</dd>
<script>
const util = require('util');
const child_process = require('child_process');
// 调用util.promisify方法返回一个promise,如const { stdout, stderr } = await exec('rm -rf build')
const exec = util.promisify(child_process.exec);
const appPath = join(__dirname, 'app');
const runClean = async function () {
// cwd指定子进程的当前工作目录 这里的rm -rf build为删除指定目录下的一个文件夹
await exec(`rm -rf build`, { cwd: appPath });
await exec(`rm -rf test`, { cwd: appPath });
runClean();
}
</script>
</dl>
</div>
</div>
<!-- 产品中心那一部分的平铺-->
<div id="links">
<!-- 这个顺序引入更规范 -->
<div class="links_con">
<!-- 版心部分 -->
<!-- 左边的盒子 -->
<div class="links_l">
<h3 class="links_title">技术支持</h3>
<ul class="links_list">
<li>
<a href="#">国防科技大学信息中心</a>
</li>
<li>
<a href="#">全军指挥控制中心</a>
</li>
<li>
<a href="#">国防科技大学网络安全小组</a>
</li>
<li>
<a href="#">软体生物开发小组</a>
</li>
<li>
<a href="#">国防科技大学软件体系结构课程</a>
</li>
</ul>
</div>
<!-- 中间的盒子 -->
<div class="links_c">
<h3 class="links_title">开发者联系方式</h3>
<ul class="links_list">
<li>
<a href="#">liuyuyang21a@gfkd.mtn</a>
</li>
<li>
<a href="#">yuankaifeng21@gfkd.mtn</a>
</li>
<li>
<a href="#">xumingyang21@gfkd.mtn</a>
</li>
<li>
<a href="#">dongjiaqi21@gfkd.mtn</a>
</li>
</ul>
</div>
<!-- 右边的盒子 -->
<div class="links_r">
<h3 class="links_title">HADG</h3>
<h3 class="links_a"> 旨在为全军指挥信息系统提供坚实保障,开发更高效的网关服务</h3>
<div class="map">
<img
width="150px"
height="100px"
src="./assets/images/nginx.gif">
</div>
</div>
</div>
</div>
<!-- 页脚 -->
<div class="footer_con">
<!-- 页脚左边的盒子 -->
<p class="footer_l">
<a href="./table.html">意见反馈</a>
<a href="#">用户协议</a>
<a href="#">交流QQ群</a>
<a href="#" class="footer-right">湘ICP备20002562号-1</a>
</p>
<!-- 页脚右边的盒子 -->
<p class="footer_r">
国防科技大学软件体系结构课程徐明洋小组开发
</p>
</div>
</body>
<script>
function showPopup(){
var overlay = document.getElementById("overlay");
overlay.style.display = "block";
}
function hidePopup(){
var overlay = document.getElementById("overlay");
overlay.style.display = "none";
}
</script>
</html>

@ -0,0 +1,183 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
<!-- 引入格式文件-->
<!-- <link rel="stylesheet" href="html&css.css"> -->
</head>
<body>
<style>
*{
margin: 0px;/*所有的外边距为0*/
padding: 0px;/*所有的内边距为0*/
box-sizing: border-box;/*规定两个并排的带边框的框*/
}
table{
text-align: center;
}
body{
background: url("./assets/images/button.jpg")no-repeat center;
padding-top: 25px;
}
.rg_layout{
width: 900px;
height: 500px;
border: 8px solid #EEEEEE;/*solid 定义实线*/
background-color: white;
margin: auto;
}
.rg_left{
float: none;
text-align: center;
margin: 15px;
}
.rg_left>p:first-child{
color: #FFD026;
font-size: 20px;
}
.rg_left>p:last-child{
color: #A6A6A6;
font-size: 20px;
}
.rg_center{
float: left;
}
.rg_right{
float: none;
margin: 250px;
padding-left: 10px;
white-space:nowrap;
}
.rg_right p{
font-size: 15px;
}
.rg_right p a{
color: coral;
}
.td_left{
padding-left: 250px;
width: 100px;
text-align: center;
height: 45px;
white-space:nowrap;
}
.td_right{
padding-left: 40px;
text-align: center;
white-space:nowrap;
}
.bt_center{
padding-left: 310px;
}
#username,#real_name,#ID,#password,#tel,#birthday,#checkcode{
width: 251px;
height: 32px;
border: 1px solid #A6A6A6;
/*设置边框圆角*/
border-radius: 5px;
padding-left: 10px;
}
#checkcode{
width: 110px;
}
#img_check{
height: 32px;
vertical-align: middle;/*设置图片的位置垂直居中*/
}
#btn_sub{
width: 100px;
height: 40px;
background-color: #FFD026;
border: 1px solid #FFD026;
padding-left: 10px;
}
</style>
<div class="rg_layout">
<div class="rg_left">
<p>新用户注册</p>
<p>USER REGISTER</p>
</div>
<div class="rg_center">
<div class="rg_form">
<form class="ant-form" action="#" method="post">
<table>
<tr><!--label 标签的作用是当点击文字也会跳到文本输出框-->
<!--for属性与ID属性对应规定 label 绑定到哪个表单元素。-->
<td class="td_left"><label for="username">用户名</label> </td>
<td class="td_right"><input type="text" name="username" id="username"> </td>
</tr>
<tr>
<td class="td_left"><label for="real_name">姓名</label> </td>
<td class="td_right"><input type="text" name="real_name" id="real_name"> </td>
</tr>
<tr><!--label 标签的作用是当点击文字也会跳到文本输出框-->
<td class="td_left"><label for="ID">身份证号</label> </td>
<td class="td_right"><input type="text" name="ID" id="ID"> </td>
</tr>
<tr>
<td class="td_left"><label for="password">密码</label> </td>
<td class="td_right"><input type="password" name="password" id="password"> </td>
</tr>
<tr>
<td class="td_left"><label for="tel">再次输入密码</label> </td>
<td class="td_right"><input type="password" name="tel" id="tel"> </td>
</tr>
<tr>
<td colspan="2" align="center" class="bt_center">
<input type="submit" value="注册" id="btn_sub">
</td>
</tr>
</table>
</form>
</div>
</div>
<div class="rg_right">
<p><a href="LoginUI.html">返回登录界面</a></p>
</div>
</div>
</body>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 获取表单元素
var form = document.querySelector('.ant-form');
// 为表单添加提交事件监听器
form.addEventListener('submit', function(e) {
e.preventDefault(); // 阻止表单的默认提交行为
// 收集表单数据
var formData = {
//question_kind: document.getElementsByName('question_kind').value,
ID:document.getElementById('ID').value,
password: document.getElementById('password').value,
real_name:document.getElementById('real_name').value,
source:"frontend",
tel:document.getElementById('tel').value,
type:"register_message",
username: document.getElementById('username').value,
};
console.log(formData);
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData) // 将表单数据转换为JSON字符串
})
.then(response => response.json()) // 转换响应为JSON
.then(data => {
console.log('Success:', data);
alert('反馈成功提交!');
})
.catch((error) => {
console.error('Error:', error);
alert('提交失败,请稍后重试!');
});
});
});
</script>
</html>

@ -0,0 +1,41 @@
<div class="sidebar">
<div class="menu-item">北京</div>
<div class="menu-item">长沙</div>
<div class="menu-item">上海</div>
<!-- 更多菜单项... -->
</div>
<button id="toggleIndent">切换缩进</button>
<style>
/* 初始的侧边栏样式 */
.sidebar {
width: 200px; /* 侧边栏宽度 */
background-color: #f4f4f4; /* 侧边栏背景颜色 */
padding: 10px; /* 侧边栏内边距 */
}
/* 菜单项样式 */
.menu-item {
padding: 8px 20px; /* 菜单项内边距 */
margin-bottom: 5px; /* 菜单项之间的间隔 */
background-color: #ddd; /* 菜单项背景颜色 */
cursor: pointer; /* 鼠标悬停时显示为指针 */
transition: background-color 0.3s; /* 背景颜色变化的过渡效果 */
}
/* 缩进效果的样式 */
.indented {
margin-left: 20px; /* 缩进的距离 */
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
var toggleIndentButton = document.getElementById('toggleIndent');
var menuItems = document.querySelectorAll('.menu-item');
toggleIndentButton.addEventListener('click', function () {
menuItems.forEach(function (item) {
item.classList.toggle('indented');
});
});
});
</script>

@ -0,0 +1,289 @@
/*-----------------------------------*\
#style.css
\*-----------------------------------*/
/**
* copyright 2022 codewithsadee
*/
/*-----------------------------------*\
#CUSTOM PROPERTY
\*-----------------------------------*/
:root {
/**
* colors
*/
--medium-slate-blue: hsl(240, 73%, 65%);
--space-cadet_10: hsl(226, 54%, 26%, 0.1);
--space-cadet: hsl(226, 54%, 26%);
--ghost-white: hsl(227, 69%, 97%);
--cool-gray: hsl(226, 19%, 63%);
--cultured: hsl(0, 0%, 95%);
--white: hsl(0, 0%, 100%);
/**
* typography
*/
--ff-dm-sans: 'Roboto', sans-serif;
--ff-helvetica: 'Helvetica', sans-serif;
--fs-1: 3rem;
--fs-2: 2.4rem;
--fs-3: 1.5rem;
--fs-4: 1.2rem;
--fw-500: 500;
--fw-600: 600;
--fw-700: 700;
/**
* shadow
*/
--shadow: 1px 1px 3px hsla(0, 0%, 0%, 0.15);
/**
* radius
*/
--radius-5: 5px;
--radius-15: 15px;
/**
* transition
*/
--transition-1: 0.25s ease;
--transition-2: 1s ease;
}
/*-----------------------------------*\
#RESET
\*-----------------------------------*/
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
span,
data { display: block; }
img { height: auto; }
table,
tbody,
tr,
th,
td {
all: unset;
}
html {
font-family: var(--ff-dm-sans);
font-size: 10px;
}
body {
background-color: var(--ghost-white);
color: var(--cool-gray);
font-size: 1.6rem;
padding-inline: 15px;
min-height: 100vh;
}
/*-----------------------------------*\
#REUSED STYLE
\*-----------------------------------*/
.flex-center {
display: flex;
justify-content: center;
align-items: center;
}
.balance-card,
.chart-card {
width: 300px;
height: 150px;
position: relative;
padding: 5px;
border-radius: var(--radius-10);
}
.text { font-size: var(--fs-3); }
.h2 { font-size: var(--fs-2); }
/*-----------------------------------*\
#BALANCE CARD
\*-----------------------------------*/
.chart-container {
width: 100%;
max-width: 540px;
margin-inline: 100px;
left: 50px;
}
.balance-card {
background-color: var(--medium-slate-blue);
color: var(--white);
justify-content: space-between;
margin-block-end: 15px;
}
.balance-card .text {
font-weight: unset;
margin-block-end: 5px;
}
.balance-card .h2 { font-weight: var(--fw-700); }
.balance-card .logo { width: 60px; }
/*-----------------------------------*\
#CHART CARD
\*-----------------------------------*/
.chart-card {
position: relative;
margin-right: 30px;
background-color: var(--white);
}
.chart-card .h2 {
color: var(--space-cadet);
font-weight: var(--fw-500);
margin-block-end: 50px;
}
.chart-card .card-table {
display: block;
padding-block-end: 24px;
border-block-end: 1px solid var(--space-cadet_10);
margin-block-end: 24px;
}
.chart-card .table-body {
justify-content: space-evenly;
align-items: stretch;
gap: 12px;
}
.chart-card .table-row {
flex-direction: column-reverse;
justify-content: flex-start;
gap: 10px;
min-height: calc(150px + 31px);
}
.chart-card .table-heading {
color: var(--space-cadet);
font-family: var(--ff-helvetica);
font-size: var(--fs-4);
}
.chart-card .table-data {
min-width: 20px;
height: 100%;
background-color: var(--cultured);
cursor: pointer;
}
.chart-card .chart-bar {
background-color: var(--medium-slate-blue);
height: 50%;
width: 100%;
transform-origin: bottom;
transition: transform var(--transition-2);
}
.chart-card .chart-bar:hover { opacity: 0.75; }
.tooltip {
position: fixed;
top: 0;
left: 50%;
transform: translateX(-50%);
background-color: var(--white);
color: var(--space-cadet);
font-family: var(--ff-helvetica);
font-weight: var(--fw-600);
padding: 8px;
border: 1px solid var(--cultured);
border-radius: var(--radius-5);
box-shadow: var(--shadow);
pointer-events: none;
opacity: 0;
transition: var(--transition-1);
}
.tooltip.active { opacity: 1; }
.chart-card .wrapper {
justify-content: space-between;
align-items: flex-start;
}
.chart-card .meta-value {
color: var(--space-cadet);
font-weight: var(--fw-500);
margin-block-start: 5px;
}
.chart-card .meta-value:not(.small) { font-size: var(--fs-1); }
.chart-card .card-meta:last-child {
align-self: flex-end;
text-align: right;
}
.piechart{
margin-top: -180px;
left: 600px;
width: 150px;
height: 150px;
position: fixed;
padding: 5px;
border-radius: var(--radius-10);
}
/*-----------------------------------*\
#MEDIA QUERIES
\*-----------------------------------*/
/**
* responsive for large than 768px screen
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 533 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

@ -0,0 +1,4 @@
<svg width="61" height="42" viewBox="0 0 61 42" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M40.7182 41C51.9195 41 60.9999 32.0457 60.9999 21C60.9999 9.9543 51.9195 1 40.7182 1C29.5169 1 20.4365 9.9543 20.4365 21C20.4365 32.0457 29.5169 41 40.7182 41Z" fill="#1E2F65"/>
<path d="M20.4366 40.1666C31.1712 40.1666 39.8732 31.5854 39.8732 21C39.8732 10.4145 31.1712 1.83331 20.4366 1.83331C9.70207 1.83331 1 10.4145 1 21C1 31.5854 9.70207 40.1666 20.4366 40.1666Z" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 516 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@ -0,0 +1,20 @@
[
{
"server": "shanghai",
"stat": "busy",
"amount": 70,
"recentTime":70
},
{
"server": "changsha",
"stat": "busy",
"amount": 50,
"recentTime": 1300
},
{
"server": "beijing",
"stat": "busy",
"amount": 56,
"recentTime": 70
}
]

File diff suppressed because one or more lines are too long

@ -0,0 +1,149 @@
'use strict';
/**
* import json data
*/
import data from './data.json' assert { type: 'json' };
/**
* -> select all DOM elements
*/
const tooltip = document.querySelector("[data-tooltip]");
const chartBars = document.querySelectorAll("[data-chart-bar]");
/**
* add event on element
*/
const addEventOnElem = function (elem, type, callback) {
if (elem.length > 1) {
for (let i = 0; i < elem.length; i++) {
elem[i].addEventListener(type, callback);
}
} else {
elem.addEventListener(type, callback);
}
}
/**
* -> get the max day amount from data
*/
let maxDayAmount = 0;
for (let i = 0; i < data.length; i++) {
if (data[i].amount > maxDayAmount) {
maxDayAmount = data[i].amount;
}
}
/**
* -> get chart bars height as array
* -> set the height of all bars in chart
*/
const setChartBarsHeight = function (height) {
for (let i = 0; i < height.length; i++) {
chartBars[i].style.transform = `scaleY(${height[i] / 100})`;
}
}
/**
* -> get the day amount from data
* -> find the percentage of every number
* -> push all number in chartBarsHeight
*/
const charBarsHeight = [];
for (let i = 0; i < data.length; i++) {
const dayAmount = data[i].amount;
const percentOfNum = dayAmount / maxDayAmount * 100;
charBarsHeight.push(percentOfNum);
}
setChartBarsHeight(charBarsHeight);
/**
* -> get top, left, and chart bar width
* -> get tooltip height
* -> set the gap between chart bar and tooltip
* -> set the tooltip position
*/
const setTooltipPos = function (top, left, chartBarWidth) {
const tooltipHeight = tooltip.offsetHeight;
const gap = 8;
tooltip.style.top = `${top - tooltipHeight - gap}px`;
tooltip.style.left = `${left + chartBarWidth / 2}px`;
}
/**
* when chart bar is hover
* -> add active class in tooltip
* -> get chart bar top position from window
* -> get chart bar left position from window
* -> get chart bar width
* -> call setTooltipPos and pass the chart bar top,
* left position and width
*/
const chartBarOnHover = function () {
tooltip.classList.add("active");
const barTopPos = this.getBoundingClientRect().top;
const barLeftPos = this.getBoundingClientRect().left;
const barWidth = this.offsetWidth;
setTooltipPos(barTopPos, barLeftPos, barWidth);
}
addEventOnElem(chartBars, "mouseover", chartBarOnHover);
/**
* -> hide tooltip when leave cursor from chart bar
*/
const hideTooltip = function () {
tooltip.classList.remove("active");
}
addEventOnElem(chartBars, "mouseleave", hideTooltip);
/**
* -> add tooltip value when hover on any bar chart
*/
const addTooltipValue = function () {
for (let i = 0; i < data.length; i++) {
if (data[i].server === this.dataset.chartBar) {
tooltip.innerHTML = data[i].amount.toString();
break;
}
}
}
addEventOnElem(chartBars, "mouseover", addTooltipValue);

File diff suppressed because one or more lines are too long

@ -0,0 +1,235 @@
@charset "utf-8";
/* 统一板块宽度和左右居中 */
.banner_con,
.news_con,
.case_con,
.links_con,
.footer_con {
width: 1002px;
margin: 0 auto;
}
#banner {
height: 465px;
background: gray url("../images/banner1_02_02.jpg") no-repeat center;
}
#banner .banner_con {
height: 465px;
/* background: pink; */
margin: 0 auto;
}
.news_con {
height: 243px;
background: white;
}
.news_title {
/* background: cadetblue; */
font-size: 18px;
color: #3f434f;
line-height: 18px;
padding-top: 36px;
}
.news_list {
/* background: cornflowerblue; */
margin-top: 23px;
}
.news_list li {
width: 437px;
height: 25px;
background: url("../images/ico_05.jpg") no-repeat left;
padding-left: 14px;
/* margin-top: 23px;不能给li加哦 要给他爹,不然每个儿子顶部都会空出来*/
}
.news_list li a {
float: left;
font-size: 12px;
color: #565656;
line-height: 25px;
}
.news_list li span {
float: right;
color: #9a9a9a;
font-size: 12px;
}
.news_l {
width: 480px;
height: 243px;
/* background: rebeccapurple; */
float: left;
padding-left: 21px;
}
.news_c {
width: 194px;
height: 243px;
background: #f1f1f1;
float: left;
padding: 0 27px 0 20px;
}
.news_c .txt1 {
font-size: 12px;
color: #555555;
line-height: 25px;
margin-top: 34px;
/* 行高自己去量哦 */
}
.news_c .txt2 {
font-size: 12px;
color: #979797;
line-height: 25px;
margin-top: 15 px;
/* 行高自己去量哦 */
}
.news_r {
width: 180px;
height: 243px;
background: #fbfbfb url("../images/ma_05.jpg") no-repeat right bottom;
float: left;
padding: 0 38px 0 24px;
}
.news_r .txt3 {
font-size: 12px;
color: #585858;
line-height: 24px;
margin: 21px 0 22px 0;
}
.case_con {
height: 304px;
/* background: goldenrod; */
}
.case_con h3 {
font-size: 18px;
color: #3f434f;
/* background: pink; */
padding: 28px 0 18px 22px;
}
.case_con .case_box {
height: 240px;
/* background: orange; */
}
.case_box dl {
width: 210px;
/* 这是由图片尺寸为210得出的这样文本就会屈居于一处 */
/* background: burlywood; */
float: left;
margin: 0 20px;
}
/* 这里很重要!一定要设置宽高,也就是图片尺寸得出,这样以后图片更换,结构就不会乱! */
.case_box dl dt {
width: 190px;
height: 190px;
}
.case_box dl dd {
font-size: 24px;
color: #4f4f4f;
line-height: 24px;
margin-top: 13px;
float: center;
left: 10px;
}
/* 上面给dt这个容器指定了宽高现在让img跟随这个容器的宽高 */
.case_box dl dt img {
width: 100%;
height: 100%;
}
#links {
background: #e5e5e5;
}
.links_con {
height: 250px;
/* */
}
.links_con .links_title {
color: #5d5d5d;
line-height: 16px;
border-bottom: 1px solid #c1c1c1;
padding: 31px 0 11px 13px;
}
.links_con .links_l {
width: 452px;
height: 250px;
background: #e5e5e5;
float: left;
margin-left: 20px;
}
.links_con .links_list {
/* background: cornsilk; */
height: 170px;
padding-left: 5px;
padding-top: 15px;
}
.links_con .links_list li {
width: 136px;
height: 24px;
background: url("../images/btn_img_13.jpg") no-repeat left center;
font-size: 12px;
line-height: 24px;
padding-left: 13px;
float: left;
}
.links_con .links_list li a {
color: #5f5f5f;
white-space:nowrap;
}
.links_con .links_c {
width: 153px;
height: 250px;
background: #e5e5e5;
float: left;
margin: 0 50px;
}
.links_con .links_a {
width: 265px;
height: 24px;
font-size: 14px;
color: #8f8585;
}
.links_con .links_c .links_list li {
width: 130px;
}
.links_con .links_r {
width: 256px;
height: 250px;
background: #e5e5e5;
float: left;
}
.links_con .links_r .map {
text-align: center;
padding-top: 11px;
}

@ -0,0 +1,363 @@
@charset "UTF-8";
/* CSS Document */
.bg{
margin:0 auto;
width:100%;
min-height:100vh;
background:url(../images/bg2.jpg) no-repeat;
background-size: cover;
padding-top:0rem;
padding:0rem 0.2rem;
}
/*.conIn{
display:flex;
display: -webkit-flex;}*/
.title{
width:100%;
font-size:0.12rem;
line-height:0.3rem;
color:rgba(14,253,255,1);
text-align:center;
font-weight:bold;
}
.border_bg_leftTop{
position:absolute;
left:-0.008rem;
top:-0.04rem;
width:0.37rem;
height:0.05rem;
display:block;
background: url(../images/title_left_bg.png) no-repeat;
background-size:cover;}
.border_bg_rightTop{
position:absolute;
right:-0.01rem;
top:-0.01rem;
width:0.1rem;
height:0.1rem;
display:block;
background:url(../images/border_bg.jpg) no-repeat;
background-size:cover;}
.border_bg_leftBottom{
position:absolute;
left:-0.008rem;
bottom:-0.008rem;
width:0.1rem;
height:0.1rem;
display:block;
background:url(../images/border_bg.jpg) no-repeat;
background-size:cover;}
.border_bg_rightBottom{
position:absolute;
right:-0.01rem;
bottom:-0.01rem;
width:0.08rem;
height:0.08rem;
display:block;
background:url(../images/title_right_bg.png) no-repeat;
background-size:cover;}
.leftMain{
width:75%;
float:left;
padding-right:0.1rem;
padding-top:0.1rem;
}
.rightMain{
width:25%;
float:left;
padding-top:0.1rem;}
.leftMain_top{
width:100%;
padding-bottom:0.1rem;}
.leftMain_top ul{
display:flex;
display: -webkit-flex;
}
.leftMain_top ul li{
float:left;
width:25%;
padding-right:0.1rem;}
.leftMain_top ul li:last-child{
padding:0;}
.leftMain_top ul li .liIn{
border:0.008rem solid rgba(14,253,255,0.5);
width:100%;
min-height:60px;
position:relative;
padding:0.08rem 0.05rem;
}
.leftMain_top ul li .liIn h3{
font-size:0.08rem;
color:#fff;
margin-bottom:0.05rem;
}
.leftMain_top ul li .liIn .shu{
font-size:0.12rem;
color:rgba(14,253,255,1);
font-family:dig;
margin-bottom:0.02rem;}
.leftMain_top ul li .liIn .shu i{
font-size:0.04rem;
margin-left:0.06rem;
font-style:normal;}
.leftMain_top ul li .liIn .zi{
font-size:0.04rem;
color:#fff;
position:relative;
z-index:10;}
.leftMain_top ul li .liIn .zi .span1{
margin-right:0.1rem;}
.leftMain_middle{
width:100%;
padding-bottom:0.1rem;
display:flex;
display: -webkit-flex;}
.leftMain_middle .leftMain_middle_left{
width:60%;
padding-right:0.1rem;}
.leftMain_middle .leftMain_middle_left .leftMain_middle_leftIn{
border:0.008rem solid rgba(14,253,255,0.5);
width:100%;
min-height:60px;
position:relative;
padding:0.08rem 0.05rem;
}
.leftMain_middle .leftMain_middle_left .leftMain_middle_leftIn h3{
font-size:0.08rem;
color:#fff;
margin-bottom:0.05rem;
}
.leftMain_middle .leftMain_middle_left .leftMain_middle_leftIn .biaoge{
min-height:200px;}
.leftMain_middle .leftMain_middle_right{
width:40%;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn{
border:0.008rem solid rgba(14,253,255,0.5);
width:100%;
min-height:60px;
position:relative;
padding:0.08rem 0.05rem;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn h3{
font-size:0.08rem;
color:#fff;
margin-bottom:0.05rem;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge{
min-height:200px;}
/*左边中间部分排行榜*/
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai{
width:100%;
overflow:hidden;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn{
display:flex;
display: -webkit-flex;
align-items:center;
color:#fff;
font-size:0.06rem;
height:0.18rem;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn .liIn_left{
width:25%;
position:relative;
padding-left:0.14rem;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn .liIn_left .bot{
width:0.08rem;
height:0.08rem;
background:#f78cf3;
border-radius:1000px;
display:block;
position:absolute;
left:0.02rem;
top:0;
bottom:0;
margin:auto 0;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn2 .liIn_left .bot{
background:#e7feb8;}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn3 .liIn_left .bot{
background:#fdea8a;}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn4 .liIn_left .bot{
background:#8ff9f8;}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn5 .liIn_left .bot{
background:#d890fa;}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn6 .liIn_left .bot{
background:#05d1fc;}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn .liIn_left zi{
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn .liIn_line{
width:58%;
height:0.08rem;
background:rgba(255,255,255,0.5);
border-radius:2000px;}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn .liIn_line .line_lineIn{
width:100%;
height:0.08rem;
background:#f78cf3;
border-radius:100px;
-webkit-animation: widthMove1 2s ease-in-out ;}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn2 .liIn_line .line_lineIn{
background:#e7feb8;
-webkit-animation: widthMove2 2s ease-in-out ;}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn3 .liIn_line .line_lineIn{
background:#fdea8a;
-webkit-animation: widthMove3 2s ease-in-out ;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn4 .liIn_line .line_lineIn{
background:#8ff9f8;
-webkit-animation: widthMove4 2s ease-in-out ;}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn5 .liIn_line .line_lineIn{
background:#d890fa;
-webkit-animation: widthMove5 2s ease-in-out ;}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn6 .liIn_line .line_lineIn{
background:#05d1fc;
-webkit-animation: widthMove6 2s ease-in-out ;}
@-webkit-keyframes widthMove1 {
0% {width:0%; }
100% { width:98.5%; }
}
@-webkit-keyframes widthMove2 {
0% {width:0%; }
100% { width:88.5%; }
}
@-webkit-keyframes widthMove3 {
0% {width:0%; }
100% { width:68.5%; }
}
@-webkit-keyframes widthMove4 {
0% {width:0%; }
100% { width:40.5%; }
}
@-webkit-keyframes widthMove5 {
0% {width:0%; }
100% { width:22.5%; }
}
@-webkit-keyframes widthMove6 {
0% {width:0%; }
100% { width:10.5%; }
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn .num{
width:17%;
font-family:dig;
padding-left:0.02rem;}
/*左边底部*/
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_bi ul{
display:flex;
display: -webkit-flex;
flex-wrap:wrap;
width:100%;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_bi ul li{
width:33.3%;
text-align:center;
margin-bottom:0.05rem;}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_bi ul li .shu{
font-size:0.14rem;
color:rgba(14,253,255,1);
font-family:dig;
padding:0.12rem 0 0.02rem;
font-weight:normal;}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_bi ul li .zi{
font-size:0.06rem;
color:#fff;}
/*右边部分*/
.rightMain .rightMain_top{
width:100%;
padding-bottom:0.1rem;
}
.rightMain .rightMain_topIn{
border:0.008rem solid rgba(14,253,255,0.5);
width:100%;
min-height:60px;
position:relative;
padding:0.08rem 0.05rem;
}
.rightMain .rightMain_topIn h3{
font-size:0.08rem;
color:#fff;
margin-bottom:0.05rem;
}
.rightMain .rightMain_topIn .biaoge{
min-height:200px;}
.rightMain .rightMain_bottom{
width:100%;
}
.rightMain .rightMain_bottomIn{
border:0.008rem solid rgba(14,253,255,0.5);
width:100%;
min-height:60px;
position:relative;
padding:0.08rem 0.05rem;
}
.rightMain .rightMain_bottomIn h3{
font-size:0.08rem;
color:#fff;
margin-bottom:0.05rem;
}
/*右下角表格*/
.rightMain .rightMain_bottomIn .biaoge{
min-height:200px;}
.rightMain .rightMain_bottomIn .biaoge_list{
overflow:hidden;
position: relative;}
.rightMain .rightMain_bottomIn .biaoge_list .biaoge_listIn .ul_list{
overflow:hidden;
position: relative;}
.rightMain .rightMain_bottomIn .biaoge_list .biaoge_listIn .ul_listIn{
-webkit-animation: 14s gundong linear infinite normal;
animation: 14s gundong linear infinite normal;
position: relative;}
@keyframes gundong {
0% {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
100% {
-webkit-transform: translate3d(0, -30vh, 0);
transform: translate3d(0, -30vh, 0);
}
}
.rightMain .rightMain_bottomIn .biaoge_list ul{
display:flex;
display: -webkit-flex;
width:100%;
}
.rightMain .rightMain_bottomIn .biaoge_list .ul_title{
background: linear-gradient(left, rgba(255,255,255,0.1), rgba(255,255,255,0.5), rgba(255,255,255,0.1));
background: -ms-linear-gradient(left, rgba(255,255,255,0.1), rgba(255,255,255,0.5), rgba(255,255,255,0.1));
background: -webkit-linear-gradient(left, rgba(255,255,255,0.1), rgba(255,255,255,0.5), rgba(255,255,255,0.1));
background: -moz-linear-gradient(left, rgba(255,255,255,0.1), rgba(255,255,255,0.5), rgba(255,255,255,0.1));
}
.rightMain .rightMain_bottomIn .biaoge_list .ul_con{
border-bottom:0.008rem solid rgba(14,253,255,0.5);}
.rightMain .rightMain_bottomIn .biaoge_list ul li{
width:20%;
text-align:center;
color:#fff;
font-size:0.06rem;
height:0.2rem;
line-height:0.2rem;}
.rightMain .rightMain_bottomIn .biaoge_list ul li:frist-child{
text-align:left;}

@ -0,0 +1,138 @@
@charset "utf-8";
/* 公共区域版心宽度一样,左右居中 */
/* .header-wrap {
width: 1100px;
height: 62px;
margin: 0 auto;
} */
.header_con {
width: 1002px;
height: 100px;
/* background: pink; */
/* 左右居中 */
margin: 0 auto;
}
.header_con h1 {
width: 604px;
height: 10px;
/* background: orange; */
float: left;
padding: 34px 0 0 20px;
}
.header_con form {
width: 227px;
height: 61px;
/* background: orangered; */
float: left;
padding-top: 39px;
padding-right: 21px;
}
.header_con .search {
width: 195px;
height: 26px;
background: #f1f1f1;
border: 1px solid #e5e5e5;
/* 清除右侧边框 */
border-right: none;
float: left;
color: #888888;
}
.header_con .btn {
width: 30px;
height: 26px;
border: none;
background: #f1f1f1 url("../images/search_03.jpg") no-repeat center;
}
.header_con form div {
width: 30px;
height: 26px;
border: 1px solid #e5e5e5;
border-left: none;
float: left;
/* 给btn套盒子的时候也要加浮动 */
}
#nav {
height: 58px;
background: black;
}
#nav .nav_con {
width: 1002px;
height: 58px;
background: black;
margin: 0 auto;
}
/* 导航横向排列 */
#nav .nav_con li {
width: 498px;
height: 58px;
float: left;
background: black;
/* 左右居中 */
text-align: center;
/* 上下居中 */
line-height: 58px;
border-left: 1px solid #4a4a4a;
font-size: 12px;
}
.nav_con li a {
color: white;
}
.margin-left {
margin-left: 25px;
border-left: none!important;
}
/* 公共样式的footer */
.footer_con {
height: 82px;
/* background: #cccccc; */
}
.footer_con .footer_l {
height: 58px;
float: left;
/* background: red; */
padding-top: 24px;
}
.footer_con .footer_l a {
font-size: 12px;
float: left;
color: #868686;
border-right: 1px solid #868686;
/* padding:字体和边框的距离哈 */
padding: 0 7px;
padding-left: 15px;
}
.footer_con .footer_l .footer-right {
border-right: none!important;
}
.footer_con .footer_r {
height: 57px;
color: #8a8a8a;
font-size: 12px;
padding-top: 25px;
/* background: pink; */
padding-right: 21px;
float: right;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,93 @@
.loader {
background: #000;
background: radial-gradient(#222, #000);
bottom: 0;
left: 0;
overflow: hidden;
position: fixed;
right: 0;
top: 0;
z-index: 99999;
}
.loader-inner {
bottom: 0;
height: 60px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap {
animation:
spin 2000ms cubic-bezier(.175, .885, .32, 1.275) infinite
;
box-sizing: border-box;
height: 50px;
left: 0;
overflow: hidden;
position: absolute;
top: 0;
transform-origin: 50% 100%;
width: 100px;
}
.loader-line {
border: 4px solid transparent;
border-radius: 100%;
box-sizing: border-box;
height: 100px;
left: 0;
margin: 0 auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap:nth-child(1) { animation-delay: -50ms; }
.loader-line-wrap:nth-child(2) { animation-delay: -100ms; }
.loader-line-wrap:nth-child(3) { animation-delay: -150ms; }
.loader-line-wrap:nth-child(4) { animation-delay: -200ms; }
.loader-line-wrap:nth-child(5) { animation-delay: -250ms; }
.loader-line-wrap:nth-child(1) .loader-line {
border-color: hsl(0, 80%, 60%);
height: 90px;
width: 90px;
top: 7px;
}
.loader-line-wrap:nth-child(2) .loader-line {
border-color: hsl(60, 80%, 60%);
height: 76px;
width: 76px;
top: 14px;
}
.loader-line-wrap:nth-child(3) .loader-line {
border-color: hsl(120, 80%, 60%);
height: 62px;
width: 62px;
top: 21px;
}
.loader-line-wrap:nth-child(4) .loader-line {
border-color: hsl(180, 80%, 60%);
height: 48px;
width: 48px;
top: 28px;
}
.loader-line-wrap:nth-child(5) .loader-line {
border-color: hsl(240, 80%, 60%);
height: 34px;
width: 34px;
top: 35px;
}
@keyframes spin {
0%, 15% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}

@ -0,0 +1,76 @@
@charset "utf-8";
/* 重置样式表 */
* {
margin: 0;
padding: 0;
}
/* 统一页面文本 */
body {
font-size: 16px;
font-family: "微软雅黑";
}
/* 清除列表符号 */
ul,
ol,
li {
list-style: none;
}
/* 清除下划线 */
u,
a {
text-decoration: none;
}
/* 清除倾斜 */
i,
em {
font-style: normal;
}
/* 清除加粗 */
b,
strong {
font-weight: normal;
}
/* 清除文本默认大小和加粗 */
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: 16px;
font-weight: normal;
}
/* 边框清零 */
img {
border: none;
}
/* 清除聚焦时候的边框 */
input {
outline: none;
}

@ -0,0 +1,64 @@
body{
background: url("ab.jpg") no-repeat center;
background-size: cover;
height: 100vh;
width: 100%;
}
.login{
color: #988fc7;
float: right;
width: 100px;
height: 40px;
border-radius: 50%;
justify-content: center;
align-items: center;
transition: 0.4s;
}
.search-box{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
background:#2f3640;
height: 38px;
border-radius: 60px;
padding: 10px;
}
.search-box:hover > .search-txt{
width: 240px;
padding: 0 6px;
}
.search-box:hover > .search-btn{
background: white;
}
.search-btn{
color: #988fc7;
float: right;
width: 40px;
height: 40px;
border-radius: 50%;
background: #2f3640;
display: flex;
justify-content: center;
align-items: center;
transition: 0.4s;
}
.search-txt{
border:none;
background: none;
outline: none;
float: left;
padding: 0;
color: white;
font-size: 16px;
transition: 0.4s;
line-height: 40px;
width: 0px;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save