diff --git a/prak3/src/CMakeLists.txt b/prak3/src/CMakeLists.txt index 80b1cab410fd964f47759529858490f1b5a4c7ef..b010d6ea4e56d13e88928ed60c9fac253da8037c 100644 --- a/prak3/src/CMakeLists.txt +++ b/prak3/src/CMakeLists.txt @@ -1,3 +1,3 @@ -add_executable(client client.cpp) -add_executable(server server.cpp) +add_executable(myclient client.cpp) +add_executable(myserver server.cpp) add_executable(test test.cpp) \ No newline at end of file diff --git a/prak3/src/client.cpp b/prak3/src/client.cpp index 6f81d99ecb97e84e9902c263464c07b300d54521..845861d38e40b654e1e74fc6148cd7dbad1aec4b 100644 --- a/prak3/src/client.cpp +++ b/prak3/src/client.cpp @@ -4,7 +4,9 @@ #include <arpa/inet.h> -#define SERVER_IP "141.100.42.11" +//#define SERVER_IP "141.100.42.11" +#define SERVER_IP "127.0.0.1" + #define PORT 2525 #define BUFFER_SIZE 1024 @@ -79,6 +81,4 @@ int main(int argc, char* argv[]) { // Socket schließen close(sock); return 0; - - } diff --git a/prak3/src/server.cpp b/prak3/src/server.cpp index 2dbb8c3dad6008e691cc26aec90a193ea7a02847..b57852571c41affc7058c7e0d79760923b78d38a 100644 --- a/prak3/src/server.cpp +++ b/prak3/src/server.cpp @@ -1,180 +1,174 @@ #include <iostream> -#include <unordered_map> -#include <vector> #include <thread> -#include <mutex> -#include <condition_variable> -#include <queue> +#include <vector> #include <cstring> #include <unistd.h> #include <arpa/inet.h> -#include <sys/epoll.h> +#include <mutex> -#define PORT 2525 +#define PORT 2525 -#define MAX_EVENTS 10 #define BUFFER_SIZE 1024 -#define THREAD_POOL_SIZE 4 +#define STORE_OPERATION 's' +#define GET_OPERATION 'g' +#define DELETE_OPERATION 'd' -std::unordered_map<std::string, std::string> store; -std::mutex store_mutex; +struct Request { + char operation; + std::string key; + std::string value; +}; -// Task-Queue für Thread-Pool -std::queue<int> task_queue; -std::mutex queue_mutex; -std::condition_variable cv; +std::mutex mtx; +std::vector<Request*> DB; -// Worker-Funktion für Thread-Pool -void worker_thread() { - while (true) { - int client_socket; - { - std::unique_lock<std::mutex> lock(queue_mutex); - cv.wait(lock, [] { return !task_queue.empty(); }); - client_socket = task_queue.front(); - task_queue.pop(); - } - char buffer[BUFFER_SIZE] = {0}; - ssize_t bytes_received = read(client_socket, buffer, BUFFER_SIZE); - - if (bytes_received <= 0) { - close(client_socket); - continue; - } - std::string request(buffer); - if (request.back() != ';') { - std::cerr << "Invalid request format" << std::endl; - continue; + + + Request* parseRequest(const char* buffer) { + // Create a new Request struct + Request* req = new Request(); + + // Copy the input buffer to a mutable string for tokenization + char* input = strdup(buffer); // Duplicate the buffer + if (!input) { + return nullptr; // Handle memory allocation failure + } + + // Tokenize the input string using ',' and ';' as delimiters + char* token = strtok(input, ",;"); + if (token) { + // First token is the operation + req->operation = token[0]; // Extract the first character (s, g, or d) + + // Second token is the key + token = strtok(nullptr, ",;"); + if (token) { + req->key = token; + + // Third token is the value (only for store operation) + if (req->operation == 's') { + token = strtok(nullptr, ",;"); + if (token) { + req->value = token; + } + } } + } + + // Free the duplicated input string + free(input); + + return req; +} + + +void handle_client(int client_socket) { + char buffer[BUFFER_SIZE] = {0}; + + // Nachricht vom Client empfangen + ssize_t bytes_received = read(client_socket, buffer, BUFFER_SIZE); + + + if (bytes_received > 0) { + //std::cout << "Client: " << buffer << std::endl; + Request* request = parseRequest(buffer); std::string response; - char operation = request[0]; - size_t first_comma = request.find(',', 1); - if (first_comma == std::string::npos) { - response = "ERROR: Invalid format;"; - } else { - std::string key = request.substr(2, first_comma - 2); - if (operation == 's') { // Store operation - size_t second_comma = request.find(',', first_comma + 1); - if (second_comma == std::string::npos) { - response = "ERROR: Invalid format;"; - } else { - std::string value = request.substr(first_comma + 1, second_comma - first_comma - 1); - std::lock_guard<std::mutex> lock(store_mutex); - store[key] = value; - response = "STORED;"; - } - } else if (operation == 'g') { // Get operation - std::lock_guard<std::mutex> lock(store_mutex); - auto it = store.find(key); - if (it != store.end()) { - response = "VALUE," + it->second + ";"; - } else { - response = "NOT_FOUND;"; + + if(request->operation == STORE_OPERATION){ + std::lock_guard<std::mutex> lock(mtx); + response = "Key " + request->key +" Not Found for [get]"; + DB.push_back(request); + response = "freue dich :)"; + }else if (request->operation == GET_OPERATION){ + std::lock_guard<std::mutex> lock(mtx); + for (Request* current : DB) { + if(current->key == request->key){ + response = current->value; + break; } - } else if (operation == 'd') { // Delete operation - std::lock_guard<std::mutex> lock(store_mutex); - if (store.erase(key) > 0) { - response = "DELETED;"; - } else { - response = "NOT_FOUND;"; + } + }else if (request->operation == DELETE_OPERATION){ + std::lock_guard<std::mutex> lock(mtx); + response = "Key " + request->key +" Not Found for [delete]"; + for(size_t i=0; i< DB.size();i++){ + if(DB[i]->key == request->key){ + delete DB[i]; + DB.erase(DB.begin() + i); + response = "Key " + request->key +" is deleted"; + break; } - } else { - response = "ERROR: Unknown operation;"; } + }else{ + response = "bad request -_____- !"; } - send(client_socket, response.c_str(), response.length(), 0); + + // send Response + send(client_socket, response.c_str(), strlen(response.c_str()), 0); + } + + // Socket schließen + close(client_socket); } int main() { - int server_fd, epoll_fd; - struct sockaddr_in address{}; + int server_fd, client_socket; + struct sockaddr_in address; socklen_t addrlen = sizeof(address); + std::vector<std::thread> threads; - // Server-Socket erstellen + // Socket erstellen server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd == -1) { perror("Socket failed"); exit(EXIT_FAILURE); } - int opt = 1; - setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); - + // Serveradresse festlegen address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); + // Socket an Port binden if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) { perror("Bind failed"); exit(EXIT_FAILURE); } - if (listen(server_fd, SOMAXCONN) < 0) { + // Server lauscht auf eingehende Verbindungen + if (listen(server_fd, 5) < 0) { perror("Listen failed"); exit(EXIT_FAILURE); } - // Epoll erstellen - epoll_fd = epoll_create1(0); - if (epoll_fd == -1) { - perror("Epoll create failed"); - exit(EXIT_FAILURE); - } - - struct epoll_event event{}; - event.events = EPOLLIN; - event.data.fd = server_fd; - - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1) { - perror("Epoll control failed"); - exit(EXIT_FAILURE); - } - - std::vector<std::thread> thread_pool; - for (int i = 0; i < THREAD_POOL_SIZE; i++) { - thread_pool.emplace_back(worker_thread); - } - - struct epoll_event events[MAX_EVENTS]; + std::cout << "Server listening on port " << PORT << std::endl; while (true) { - int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); - if (num_events == -1) { - perror("Epoll wait failed"); - exit(EXIT_FAILURE); + client_socket = accept(server_fd, (struct sockaddr*)&address, &addrlen); + + if (client_socket < 0) { + perror("Accept failed"); + continue; } - for (int i = 0; i < num_events; i++) { - if (events[i].data.fd == server_fd) { - int client_socket = accept(server_fd, (struct sockaddr*)&address, &addrlen); - if (client_socket < 0) { - perror("Accept failed"); - continue; - } - - struct epoll_event client_event{}; - client_event.events = EPOLLIN; - client_event.data.fd = client_socket; + std::cout << "New client connected" << std::endl; + + // Starte neuen Thread für den Client + threads.emplace_back(handle_client, client_socket); + } - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_socket, &client_event) == -1) { - perror("Epoll add client failed"); - close(client_socket); - } - } else { - { - std::lock_guard<std::mutex> lock(queue_mutex); - task_queue.push(events[i].data.fd); - } - cv.notify_one(); - } - } + // Alle Threads beenden + for (auto& t : threads) { + t.join(); } close(server_fd); return 0; } + + + diff --git a/prak3/src/test.cpp b/prak3/src/test.cpp index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..53ebf9554bcf70157cf5502182d3d55a5442cafa 100644 --- a/prak3/src/test.cpp +++ b/prak3/src/test.cpp @@ -0,0 +1,80 @@ +#include <iostream> +#include <string> +#include <cstring> // for strtok and strchr + +struct Request { + char operation; // Operation: 's' (store), 'g' (get), 'd' (delete) + std::string key; // Key + std::string value; // Value (only for store operation) +}; + +Request* parseRequest(const char* buffer) { + // Create a new Request struct + Request* req = new Request(); + + // Copy the input buffer to a mutable string for tokenization + char* input = strdup(buffer); // Duplicate the buffer + if (!input) { + return nullptr; // Handle memory allocation failure + } + + // Tokenize the input string using ',' and ';' as delimiters + char* token = strtok(input, ",;"); + if (token) { + // First token is the operation + req->operation = token[0]; // Extract the first character (s, g, or d) + + // Second token is the key + token = strtok(nullptr, ",;"); + if (token) { + req->key = token; + + // Third token is the value (only for store operation) + if (req->operation == 's') { + token = strtok(nullptr, ",;"); + if (token) { + req->value = token; + } + } + } + } + + // Free the duplicated input string + free(input); + + return req; +} + +int main() { + // Test cases + const char* storeRequest = "s,myKey,myValue;"; + const char* getRequest = "g,myKey;"; + const char* deleteRequest = "d,myKey;"; + + // Parse requests + Request* storeReq = parseRequest(storeRequest); + Request* getReq = parseRequest(getRequest); + Request* deleteReq = parseRequest(deleteRequest); + + // Print parsed requests + if (storeReq) { + std::cout << "Store Request: Operation=" << storeReq->operation + << ", Key=" << storeReq->key + << ", Value=" << storeReq->value << std::endl; + delete storeReq; + } + + if (getReq) { + std::cout << "Get Request: Operation=" << getReq->operation + << ", Key=" << getReq->key << std::endl; + delete getReq; + } + + if (deleteReq) { + std::cout << "Delete Request: Operation=" << deleteReq->operation + << ", Key=" << deleteReq->key << std::endl; + delete deleteReq; + } + + return 0; +} \ No newline at end of file