0

您好,我正在尝试开发带有嵌入式数据库的 3 层服务器。

我的问题是我能够将数据保存在 gdbm 数据库中,但是当我尝试从其他函数检索数据时,它总是返回空值。我还指出了一个问题,即在我保存数据时键值的空终止(通过 gdb 输出验证)不以 \0 结尾,但在检索数据时它以 \0 终止我不太确定这一点理论不知道怎么解决。

我尝试过的事情:

  • 尝试手动添加空字符但没有奏效
  • 厌倦了从键中删除空字符,但它仍然不起作用。
  • 试图从相同的结构中获取密钥,希望问题可能是由于格式不同但没有奏效
  • 试图替换空字符但没有帮助,因为我不知道我做错了什么以及为什么在保存数据时没有空字符。

我附上了重现相同错误希望的最少代码,因此有人会指出我的错误,同时我仍会尝试解决此问题,但您的指南可能会有所帮助。

源代码

#include <gdbm.h>
#include <string.h>
#include <stdio.h>

#define STR_SIZE 20
#define BUFFER_SIZE 256
typedef struct UserData
{
    char name[STR_SIZE];
    char accountNumber[STR_SIZE];
    char password[STR_SIZE];
    long balence;
} userData;

void simulateSelect(GDBM_FILE dbFile);
void simulateInsert(GDBM_FILE dbFile);

int main(int argc, char **argv)
{
    GDBM_FILE dbFile = gdbm_open("newSampleDB", 0, GDBM_WRCREAT | GDBM_READER, 0660, 0);
    simulateInsert(dbFile);
    simulateSelect(dbFile);
    return 0;
}

void simulateInsert(GDBM_FILE dbFile)
{
    //RPC call data sent to server [function mode [data for function call]
    char *request = "signup user fawad 10120 11223 120";

    //server receiving end
    char buffer[BUFFER_SIZE];
    char name[STR_SIZE];
    char id[STR_SIZE];
    char pass[STR_SIZE];
    char bal[STR_SIZE];
    char temp[STR_SIZE];
    char mode[STR_SIZE];
    //parse cliet request and slect one of the avaiable opertaion
    sscanf(request, "%s %s %s %s %s %s", temp, mode, name, id, pass, bal);
    bzero(buffer, BUFFER_SIZE);
    //forward request to database server
    sprintf(buffer, "insert %s %s %s %s %s", mode, name, id, pass, bal);
    // databse server receiving end
    userData data;
    bzero(name, STR_SIZE);
    bzero(id, STR_SIZE);
    bzero(pass, STR_SIZE);
    //parse request and take actoin
    sscanf(buffer, "%s %s %s %s %s %li", temp, temp, name, id, pass, &data.balence);
    strcpy(data.name, name);
    strcpy(data.accountNumber, id);
    strcpy(data.password, pass);
    //save data in database
    datum key;
    // i have checked through gdb at this point key.dptr does not have null termination i.e. \0
    // key.dptr = 10120
    key.dptr = data.accountNumber;
    key.dsize = STR_SIZE + 1;
    datum _data;
    _data.dptr = (char *)&data;
    _data.dsize = sizeof(data);
    int res = gdbm_store(dbFile, key, _data, GDBM_INSERT);
    printf("Indert Status = %d", res);
    //works fine here and data is retrived
    datum data3 = gdbm_fetch(dbFile, key);
    userData *data1 = (userData *)(data3.dptr);
    sprintf(buffer, "1 %s %s %s %li", data1->name, data1->accountNumber, data1->password, data1->balence);
    fprintf(stdout, "%s", buffer);
}

void simulateSelect(GDBM_FILE dbFile)
{
    //client again initiates request to login
    char *request = "login user 10120 11223";
    //server end
    char buffer[BUFFER_SIZE];
    char id[STR_SIZE];
    char pass[STR_SIZE];
    char temp[STR_SIZE];
    char mode[STR_SIZE];
    bzero(buffer, BUFFER_SIZE);
    //parse request and select operatoin
    sscanf(request, "%s %s %s %s", temp, mode, id, pass);
    //send request to database server
    sprintf(buffer, "select %s %s", mode, id);
    //databse server end
    bzero(id, STR_SIZE);
    //parse request
    sscanf(buffer, "%s %s %s", temp, mode, id);
    // userData d;
    // strcpy(d.accountNumber, id);
    datum _data;
    datum key;
    // at this point key.dptr have null termiantion i.e key.dptr= 10120\0
    key.dptr = id;
    // key.dptr = d.accountNumber;
    key.dsize = STR_SIZE + 1;
    _data = gdbm_fetch(dbFile, key);
    userData *data = (userData *)(_data.dptr);
    // ((userData *)res.dptr)->name)
    sprintf(buffer, "1 %s %s %s %li", data->name, data->accountNumber, data->password, data->balence);
    fprintf(stdout, "%s", buffer);
}
4

1 回答 1

0

问题很可能是您使用数组的整个(以及更多!)accountNumber作为键,甚至是字符串空终止符之外的部分,这些部分将未初始化并具有不确定的值。

因此,您在写入时使用的密钥可能与您在读取数据时使用的密钥不完全相同。

解决方案是确保在将字符串复制到其中之前,accountNumber将初始化所有数组(如 中所示)。memset(data.accountNumber, 0, sizeof data.accountNumber)


例如的问题

bzero(id, STR_SIZE);
// ...
strcpy(data.accountNumber, id);

strcpy不会复制超出字符串空终止符的数据,因此它不会复制完整的数组id,只复制其中的一小部分。这将使剩余的元素data.accountNumber未初始化。

您必须初始化data.accountNumber自己。

于 2021-03-01T19:12:11.930 回答