#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <sys/select.h> #include <arpa/inet.h> #include <sqlite3.h> #include <netinet/in.h>

#define MAX_BUFFER_SIZE 1024

typedef struct { int uid; char device_name[10]; char device_state[10]; char value[10]; char mode[10]; } Status;

typedef struct { int sockfd; struct sockaddr_in client_addr; socklen_t client_addr_len; sqlite3 *db; } ServerContext;

void handleClientRequest(ServerContext *context) { char buffer[MAX_BUFFER_SIZE]; int userid;

// 接收客户端发送的userid
ssize_t recvSize = recv(context->sockfd, &userid, sizeof(int), 0);
if (recvSize == -1) {
    perror("userid接受失败\nrecv");
    return;
}
userid = ntohl(userid); // 将网络字节序转换为主机字节序
printf("客户端已连接\n");
printf("userid:%d",userid);
// 查询数据库获取设备状态信息
char sql[100];
snprintf(sql, sizeof(sql), "SELECT * FROM Status WHERE uid = %d", userid);
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(context->db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
    fprintf(stderr, "无法执行的语句: %s\n", sqlite3_errmsg(context->db));
    return;
}

Status status;
memset(&status, 0, sizeof(Status)); // 清空status结构体
while (sqlite3_step(stmt) == SQLITE_ROW) {
    status.uid = sqlite3_column_int(stmt, 1);
    printf("%d",status.uid);
    const char* device_name = (const char*)sqlite3_column_text(stmt, 2);
    if (device_name != NULL) {
        strncpy(status.device_name, device_name, sizeof(status.device_name) - 1);
        status.device_name[sizeof(status.device_name) - 1] = '\0'; // Ensure null termination
    }
    printf("%s",status.device_name);
    const char* device_state = (const char*)sqlite3_column_text(stmt, 3);
    if (device_state != NULL) {
        strncpy(status.device_state, device_state, sizeof(status.device_state) - 1);
        status.device_state[sizeof(status.device_state) - 1] = '\0'; // Ensure null termination
    }
    const char* value = (const char*)sqlite3_column_text(stmt, 4);
    if (value != NULL) {
        strncpy(status.value, value, sizeof(status.value) - 1);
        status.value[sizeof(status.value) - 1] = '\0'; // Ensure null termination
    }
    const char* mode = (const char*)sqlite3_column_text(stmt, 5);
    if (mode != NULL) {
        strncpy(status.mode, mode, sizeof(status.mode) - 1);
        status.mode[sizeof(status.mode) - 1] = '\0'; // Ensure null termination
    }
}
int columnCount = sqlite3_column_count(stmt);
  printf("列数:%d\n", columnCount);
if (sqlite3_column_count(stmt) == 0) {
      fprintf(stderr, "查询结果为空\n");
      return;
  }
sqlite3_finalize(stmt);

if (strlen(status.device_name) == 0) {
    perror("接收设备状态信息失败");
    return;
}

// 分析设备状态并生成建议
char suggestion[MAX_BUFFER_SIZE];
if (strcmp(status.device_name, "空调") == 0) {
    int temperature = atoi(status.value);
    if (temperature < 24) {
        snprintf(suggestion, sizeof(suggestion), "空调温度过低,建议提高温度至26℃");
    } else {
        snprintf(suggestion, sizeof(suggestion), "空调温度正常");
    }
} else if (strcmp(status.device_name, "加湿器") == 0) {
    int humidity = atoi(status.value);
    if (humidity < 40 || humidity > 70) {
        snprintf(suggestion, sizeof(suggestion), "加湿器湿度过高或过低,建议调整加湿器湿度");
    } else {
        snprintf(suggestion, sizeof(suggestion), "加湿器湿度正常");
    }
} else {
    snprintf(suggestion, sizeof(suggestion), "设备状态未知");
}

// 向客户端发送建议
ssize_t sendSize = send(context->sockfd, suggestion, strlen(suggestion), 0);
if (sendSize == -1) {
    perror("发送失败\nsend");
    return;
}
printf("%s",suggestion);

}

int main() { printf("正在连接中...\n"); int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { perror("连接失败\nsocket"); return 1; }

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(12345);

if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
    perror("连接失败\nbind");
    close(sockfd);
    return 1;
}

if (listen(sockfd, 5) == -1) {
    perror("连接失败\nlisten");
    close(sockfd);
    return 1;
}

sqlite3 *db;
int rc = sqlite3_open("/mnt/g/Qt/Client/Smarthome_Client/database/database.db", &db);
if (rc != SQLITE_OK) {
    fprintf(stderr, "数据库打开失败: %s\n", sqlite3_errmsg(db));
    return 1;
}

ServerContext context;
context.sockfd = sockfd;
context.client_addr_len = sizeof(context.client_addr);
context.db = db;

fd_set readfds;
int maxfd = sockfd;

while (1) {
    FD_ZERO(&readfds);
    FD_SET(sockfd, &readfds);

    int activity = select(maxfd + 1, &readfds, NULL, NULL, NULL);
    if (activity == -1) {
        perror("select");
        break;
    }

    if (FD_ISSET(sockfd, &readfds)) {
        int clientSockfd = accept(sockfd, (struct sockaddr *)&context.client_addr, &context.client_addr_len);
        if (clientSockfd == -1) {
            perror("套接字接收失败\naccept");
            break;
        }

        context.sockfd = clientSockfd;
        handleClientRequest(&context);

        close(clientSockfd);
    }
}
sqlite3_close(db);
close(sockfd);
printf("服务器已关闭\n");

return 0;

}

下面是客户端的代码 #include "procession.h" #include "ui_procession.h" #include #include

Procession::Procession(int userid,QWidget *parent) : QWidget(parent), ui(new Ui::Procession), userid(userid) { ui->setupUi(this); processionWidget(); m_socket = new QTcpSocket(this); //connect(ui->connectBtn, &QPushButton::clicked, this, &Procession::on_connectBtn_clicked); connect(m_socket, &QTcpSocket::readyRead, this, &Procession::readyRead); connect(m_socket, &QTcpSocket::connected, this, &Procession::connected); connect(m_socket, &QTcpSocket::disconnected,this,&Procession::disconnected); connect(m_socket, QOverloadQAbstractSocket::SocketError::of(&QTcpSocket::error), this, &Procession::displayError); }

Procession::~Procession() { delete ui; }

void Procession::processionWidget() { setWindowTitle("服务器通信"); setAutoFillBackground(true); QPalette palette=this->palette(); QPixmap pixmap(":/user/image/image/net.jpg"); palette.setBrush(QPalette::Window, QBrush(pixmap)); setPalette(palette); setFixedSize(600,400); }

void Procession::connected() { ui->message->append("连接成功"); QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out << static_cast(this->userid); if (m_socket->write(block) == -1) { ui->message->append("发送userid失败"); m_socket->close(); } }

void Procession::disconnected() { ui->message->append("连接失败"); m_socket->close(); }

void Procession::readyRead() { QByteArray data = m_socket->readAll(); if (data.isEmpty()) { ui->message->append("读取的数据为空"); return; } // 解析服务器返回的数据 QDataStream in(&data, QIODevice::ReadOnly); QString suggestion; in >> suggestion; // 使用重载的 >> 运算符来读取数据 if (in.status() != QDataStream::Ok) { ui->message->append("解析服务器返回的数据失败"); return; } ui->message->append(suggestion); m_socket->close(); }

void Procession::displayError(QAbstractSocket::SocketError error) { QString errorMessage; switch (error) { case QAbstractSocket::ConnectionRefusedError: errorMessage = "连接被拒绝"; break; case QAbstractSocket::RemoteHostClosedError: errorMessage = "远程主机关闭"; break; case QAbstractSocket::HostNotFoundError: errorMessage = "未找到主机"; break; case QAbstractSocket::SocketTimeoutError: errorMessage = "连接超时"; break; case QAbstractSocket::NetworkError: errorMessage = "网络错误"; break; default: errorMessage = "未知错误"; break; } ui->message->append("连接失败:" + errorMessage); }

void Procession::on_connectBtn_clicked() { if (m_socket->state() == QAbstractSocket::ConnectedState) { m_socket->disconnectFromHost(); // 先关闭套接字 qDebug() << "1"; }

ui->message->append("已经连接上服务器");
QString ip = ui->IP->text();
QString port = ui->port->text();

if (ip.isEmpty() || port.isEmpty()) {
    ui->message->clear();
    ui->message->append("请输入有效的IP地址和端口号");
    return;
}

ui->message->clear();
ui->message->append("正在连接中...");
m_socket->connectToHost(ip, static_cast<quint16>(ui->port->text().toInt()));

}

#ifndef PROCESSION_H #define PROCESSION_H

#include #include #include #include #include

namespace Ui { class Procession; }

class Procession : public QWidget { Q_OBJECT

public: explicit Procession(int userid,QWidget *parent = nullptr); ~Procession(); void processionWidget();

private slots: //void on_pushButton_clicked(); void connected(); void disconnected(); void readyRead(); void displayError(QAbstractSocket::SocketError error);

void on_connectBtn_clicked();

private: Ui::Procession ui; int userid; QTcpSocket m_socket; };

#endif // PROCESSION_H

服务器运行结果 (gdb) r Starting program: /home/SmartHome/Server/main.exec [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 正在连接中... 客户端已连接

Program received signal SIGSEGV, Segmentation fault. __strncpy_avx2 () at ../sysdeps/x86_64/multiarch/strcpy-avx2.S:304 304 ../sysdeps/x86_64/multiarch/strcpy-avx2.S: No such file or directory. 内容:The segmentation fault occurs at the line strncpy(status.device_name, sqlite3_column_text(stmt, 2), sizeof(status.device_name)); in the handleClientRequest function. This error is likely caused by accessing memory that is not allocated or accessing memory beyond its bounds.

To fix this issue, you can check the length of the string returned by sqlite3_column_text and ensure it is not larger than the size of status.device_name before copying it using strncpy. Here's an updated version of the code:

// 查询数据库获取设备状态信息
char sql[100];
snprintf(sql, sizeof(sql), "SELECT * FROM Status WHERE uid = %d", userid);
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(context->db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
    fprintf(stderr, "无法执行的语句: %s\n", sqlite3_errmsg(context->db));
    return;
}

Status status;
memset(&status, 0, sizeof(Status)); // 清空status结构体
while (sqlite3_step(stmt) == SQLITE_ROW) {
    status.uid = sqlite3_column_int(stmt, 1);
    printf("%d",status.uid);
    
    const char* device_name = (const char*)sqlite3_column_text(stmt, 2);
    if (device_name != NULL) {
        strncpy(status.device_name, device_name, sizeof(status.device_name) - 1);
        status.device_name[sizeof(status.device_name) - 1] = '\0'; // Ensure null termination
    }
    printf("%s",status.device_name);
    
    const char* device_state = (const char*)sqlite3_column_text(stmt, 3);
    if (device_state != NULL) {
        strncpy(status.device_state, device_state, sizeof(status.device_state) - 1);
        status.device_state[sizeof(status.device_state) - 1] = '\0'; // Ensure null termination
    }
    
    const char* value = (const char*)sqlite3_column_text(stmt, 4);
    if (value != NULL) {
        strncpy(status.value, value, sizeof(status.value) - 1);
        status.value[sizeof(status.value) - 1] = '\0'; // Ensure null termination
    }
    
    const char* mode = (const char*)sqlite3_column_text(stmt, 5);
    if (mode != NULL) {
        strncpy(status.mode, mode, sizeof(status.mode) - 1);
        status.mode[sizeof(status.mode) - 1] = '\0'; // Ensure null termination
    }
}
int columnCount = sqlite3_column_count(stmt);
printf("列数:%d\n", columnCount);
if (sqlite3_column_count(stmt) == 0) {
    fprintf(stderr, "查询结果为空\n");
    return;
}
sqlite3_finalize(stmt);

By checking the length of the strings before copying, you can prevent the segmentation fault caused by accessing memory beyond its bounds.

智能家居设备状态监测及建议生成服务器

原文地址: https://www.cveoy.top/t/topic/fCxa 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录