R
R
Roman Chetverikov2020-07-26 20:01:53
C++ / C#
Roman Chetverikov, 2020-07-26 20:01:53

How to make a simple TCP server with a "key-value" database?

For several days I have been trying to solve a task on client-server interaction in C ++.

Task text
На языке программирования C++ написать TCP сервер key-value БД, использую любую известную вам библиотеку или непосредственно используя socket api операционной системы Linux.
Сервер должен обрабатывать два типа запроса - на установку значения и на чтение значения клиентом.
Клиент устанавливает соединение на указанный порт и IP сервера (например 127.0.0.1:8080) и отправляет ключ/значение. Ключ может быть целым числом, значение в виде строки (к примеру [10, “Значение1”]). Предусмотреть вариант получения значения по ключу со стороны клиента. Ключи и значения можно хранить на сервере в оперативной памяти, например используя std::map.


I already have a client/server architecture that can connect and send text from the client's console to the server. The server, in turn, processes this text and sends it back to the client console.
Server Code
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main()
{
    int sock, listener;
    struct sockaddr_in addr;
    char buf[1024];
    int bytes_read;

    listener = socket(AF_INET, SOCK_STREAM, 0);
    if(listener < 0)
    {
        perror("socket");
        exit(1);
    }
    
    addr.sin_family = AF_INET;
    addr.sin_port = htons(3425);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("bind");
        exit(2);
    }

    listen(listener, 1);
    
    while(1)
    {
        sock = accept(listener, NULL, NULL);
        if(sock < 0)
        {
            perror("accept");
            exit(3);
        }

        while(1)
        {
            bytes_read = recv(sock, buf, 1024, 0);
            if(bytes_read <= 0) break;
            send(sock, buf, bytes_read, 0);
        }
    
        close(sock);
    }
    
    return 0;
}

Client code
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

char message[] = "Hello there!\n";
char buf[sizeof(message)];

int main()
{
    int sock;
    struct sockaddr_in addr;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0)
    {
        perror("socket");
        exit(1);
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons(3425); // или любой другой порт...
    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("connect");
        exit(2);
    }

    send(sock, message, sizeof(message), 0);
    recv(sock, buf, sizeof(message), 0);
    
    printf(buf);
    close(sock);

    return 0;
}


I came to the conclusion that as an option to use an embedded SQLite database. I also found "leveldb" as an option...
I don't know how to embed it into this client-server application in order to complete the task. How exactly to implement the writing and reading of key-value pairs in a TCP application?

Prompt please where to dig and where it is possible to esteem?

Answer the question

In order to leave comments, you need to log in

3 answer(s)
K
K0lya28, 2020-07-26
@roman_chet

Getting and Changing
1) Use map.find() to find a pair in std::map and get an iterator
2) If iterator == map::end(), there is no key
3) Send or change iterator->second
Adding
1) map. insert(make_pair(key, value))

V
Vladimir Korotenko, 2020-07-26
@firedragon

Steal from the radish

K
KupaKupychOfGenius, 2020-07-29
@KupaKupychOfGenius

Eeee, as if the task says how to make storage:
Keys and values ​​can be stored on the server in RAM, for example using std::map.
But first you have to come up with a protocol for communicating between the client and the server, for example, a line like
'set 10 value1' - setting a value with a specific key
'get 10' - getting a value by key 10

int main()
{
    int sock, listener;
    struct sockaddr_in addr;
    char buf[1024];
    int bytes_read;

     //std::map - это контейнер типа key-value, он же хэш в простонародие, он же dictionary, он же словарь
     //вот его мы и объявляем, ключ у него целого типа, а значени - строка
     std::map<unsigned int,std::string>  storage;   
     std::string input_string;   // полученная строка 
     std::string operation;     
     std::string key_as_string;
     std::string value;
     unsigned int key_as_int;            
     ....

 while(1)
        {
            bytes_read = recv(sock, buf, 1024, 0);
            if(bytes_read <= 0) break;
            
             //c std::string работать удобнее
            input_string = buf;
            
            //эту функцию вы уж как-нибудь сами напишите(своруйте с интерентов), в целом такая операция называется split
            parse_input_string(input_string,&operation, &key_as_string,&value); 
            key_as_int = stoi(key_as_string);

             // пришел запрос на получение значения
             if (operation == "get") {
            
                 //ищем ключ, в случае успеха метод find возратит нам итератор на элемент с нашим ключем
                //в противном случае иетратор на элемент заглушку в конце контейнера
                auto it = storage.find(key);  
               //если ключ не найден
               if (it == storage.end()) {        
                   buf = "not found";
               else {
                   strcpy(buf, iterator->second.c_str() );   // получим значение и скопируем его в буфер для отправки клиенту
               }
           } else if (operator == "set")  {
                 // если ключа еще нет, появится новая пара, если есть, то текуще значение затрется новым
                storage[key_as_int] = value;  
                buf = "saved successfully";
           }
            send(sock, buf, bytes_read, 0);
        }

I sketched a schematic code, checks are omitted, the necessary header files are also, I did not check for workability.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question