diff --git a/prak3/.vscode/launch.json b/prak3/.vscode/launch.json index 70d0d0c3c60c23b8526483ab1e0833ab80114b67..2ad16e4c7ad14d5b1d4ab77d0419db2186392707 100644 --- a/prak3/.vscode/launch.json +++ b/prak3/.vscode/launch.json @@ -42,10 +42,6 @@ "request": "launch", "program": "${workspaceFolder}/build/src/myclient", "args": [ - "store", - "id", - "5" - ], "stopAtEntry": false, "cwd": "${workspaceFolder}", diff --git a/prak3/.vscode/settings.json b/prak3/.vscode/settings.json index d602a9b463e5e42a49332576bf253e3d5d705696..9c57d8b72bbd26fcccc7fe2b7f8c620532a36f19 100644 --- a/prak3/.vscode/settings.json +++ b/prak3/.vscode/settings.json @@ -52,6 +52,7 @@ "stop_token": "cpp", "streambuf": "cpp", "thread": "cpp", - "typeinfo": "cpp" + "typeinfo": "cpp", + "map": "cpp" } } \ No newline at end of file diff --git a/prak3/src/client.cpp b/prak3/src/client.cpp index 845861d38e40b654e1e74fc6148cd7dbad1aec4b..7f648276bc1247e1eb161d09249bfbb61842dc35 100644 --- a/prak3/src/client.cpp +++ b/prak3/src/client.cpp @@ -2,39 +2,38 @@ #include <cstring> #include <unistd.h> #include <arpa/inet.h> +#include <vector> +#include <cstdlib> +#include <ctime> - -//#define SERVER_IP "141.100.42.11" #define SERVER_IP "127.0.0.1" - #define PORT 2525 - #define BUFFER_SIZE 1024 +#define REQUEST_COUNT 70000 -std::string createMessage(const std::string& operation, const std::string& key, const std::string& value = "") { - if (operation == "store") { - return "s," + key + "," + value + ";"; - } else if (operation == "get") { - return "g," + key + ";"; // Klammern entfernt - } else if (operation == "delete") { - return "d," + key + ";"; - } - return ""; +std::string generateRandomKey() { + return "key" + std::to_string(rand() % 1000); } -int main(int argc, char* argv[]) { +std::string generateRandomValue() { + return "value" + std::to_string(rand() % 10000); +} - if (argc < 3 || argc > 4) { - std::cerr << "Usage: " << argv[0] << " <operation> <key> [value]" << std::endl; - return 1; +std::string createRandomMessage() { + char operations[] = {'s', 'g', 'd'}; + char operation = operations[rand() % 3]; + std::string key = generateRandomKey(); + + if (operation == 's') { + return "s," + key + "," + generateRandomValue() + ";"; + } else { + return std::string(1, operation) + "," + key + ";"; } +} - std::string operation = argv[1]; - std::string key = argv[2]; - std::string value = (argc == 4) ? argv[3] : ""; - +int main() { + srand(time(nullptr)); -//######################### Socket Erstellen ######################### int sock; struct sockaddr_in server_address; char buffer[BUFFER_SIZE] = {0}; @@ -49,36 +48,30 @@ int main(int argc, char* argv[]) { // Serveradresse konfigurieren server_address.sin_family = AF_INET; server_address.sin_port = htons(PORT); - - // IP-Adresse konvertieren if (inet_pton(AF_INET, SERVER_IP, &server_address.sin_addr) <= 0) { perror("Invalid address"); exit(EXIT_FAILURE); } -//######################### Verbindung Aufbauen ######################### + // Verbindung zum Server herstellen if (connect(sock, (struct sockaddr*)&server_address, sizeof(server_address)) < 0) { perror("Connection failed"); exit(EXIT_FAILURE); } -//######################### Request abschicken ######################### - // Nachricht basierend auf den Argumenten erstellen - std::string message = createMessage(operation, key, value); - if (message.empty()) { - std::cerr << "Invalid operation! Use 'store', 'get', or 'delete'." << std::endl; - return 1; - } - // Nachricht senden - send(sock, message.c_str(), message.size(), 0); - std::cout << "Message sent: " << message << std::endl; -//######################### Antwort empfangen ######################### - // Antwort empfangen - ssize_t bytes_received = read(sock, buffer, BUFFER_SIZE); - if (bytes_received > 0) { - std::cout << "Server: " << buffer << std::endl; + + for (int i = 0; i < REQUEST_COUNT; i++) { + std::string message = createRandomMessage(); + send(sock, message.c_str(), message.size(), 0); + std::cout << "Sent: " << message << std::endl; + + ssize_t bytes_received = read(sock, buffer, BUFFER_SIZE); + if (bytes_received > 0) { + std::cout << "Server: " << buffer << std::endl; + } + memset(buffer, 0, BUFFER_SIZE); } -//######################### Client Beenden ######################### - // Socket schließen + + std::cout << "Closing connection..." << std::endl; close(sock); return 0; } diff --git a/prak3/src/server.cpp b/prak3/src/server.cpp index 57251b37a77819c65964d56c7b6e1ebead149d83..b83f9c263041ef4c85deff4af950af6c1526b274 100644 --- a/prak3/src/server.cpp +++ b/prak3/src/server.cpp @@ -8,25 +8,17 @@ #include <map> #define PORT 2525 - #define BUFFER_SIZE 1024 #define STORE_OPERATION 's' #define GET_OPERATION 'g' #define DELETE_OPERATION 'd' +//=========== SLOW PARSER ==================== struct Request { char operation; std::string key; std::string value; }; - -std::mutex mtx; -std::map<std::string,std::string> DB; - - - - - Request* parseRequest(const char* buffer) { // Create a new Request struct Request* req = new Request(); @@ -63,52 +55,116 @@ std::map<std::string,std::string> DB; return req; } +//============================================= +std::mutex mtx; +std::map<std::string, std::string> DB; + +// we assume that this function is slow +std::string processRequest_slow(const std::string& request) { + + std::string response; + Request* parsedRequest = parseRequest(request.c_str()); + + std::lock_guard<std::mutex> lock(mtx); + + switch (parsedRequest->operation) { + case STORE_OPERATION: + DB[parsedRequest->key] = parsedRequest->value; + response = "Stored [" + parsedRequest->key + "] = " + parsedRequest->value; + break; + case GET_OPERATION: + if (DB.find(parsedRequest->key) != DB.end()) { + response = "Value of [" + parsedRequest->key + "] is " + DB[parsedRequest->key]; + } else { + response = "Key [" + parsedRequest->key + "] not found"; + } + break; + case DELETE_OPERATION: + if (DB.erase(parsedRequest->key)) { + response = "Deleted key [" + parsedRequest->key + "]"; + } else { + response = "Key [" + parsedRequest->key + "] not found for deletion"; + } + break; + default: + response = "Invalid operation!"; + break; + } -void handle_client(int client_socket) { - char buffer[BUFFER_SIZE] = {0}; + return response; +} + +// there is parsing problem the parced key is always with ; at the end +std::string processRequest(const std::string& request) { + std::string response; - // Nachricht vom Client empfangen - ssize_t bytes_received = read(client_socket, buffer, BUFFER_SIZE); + size_t first = request.find(","); + size_t second = request.find(",", first + 1); + size_t end = request.find(";"); + if (first == std::string::npos || end == std::string::npos) { + return "Bad request!"; + } - if (bytes_received > 0) { - //std::cout << "Client: " << buffer << std::endl; + char operation = request[0]; + std::string key; + std::string value; - Request* request = parseRequest(buffer); - std::string response; + if (second != std::string::npos) { + // Extract key without ';' + key = request.substr(first + 1, second - first - 1); + value = request.substr(second + 1, end - second - 1); + } else { + // Extract key correctly without including ';' + key = request.substr(first + 1, end - first - 1); + } - if(request->operation == STORE_OPERATION){ - std::lock_guard<std::mutex> lock(mtx); - DB[request->key] = request->value; - response = "freue dich :)"; - }else if (request->operation == GET_OPERATION){ - - std::lock_guard<std::mutex> lock(mtx); - auto it = DB.find(request->key); - if (it != DB.end()) { - response = "The Value of the [" + request->key + "] is => " + it->second; - }else{ - response = "Key [" + request->key +"] Not Found"; + std::lock_guard<std::mutex> lock(mtx); + + switch (operation) { + case STORE_OPERATION: + DB[key] = value; + response = "Stored [" + key + "] = " + value; + break; + case GET_OPERATION: + if (DB.find(key) != DB.end()) { + response = "Value of [" + key + "] is " + DB[key]; + } else { + response = "Key [" + key + "] not found"; } - - }else if (request->operation == DELETE_OPERATION){ - std::lock_guard<std::mutex> lock(mtx); - if(DB.erase(request->key) != 0){ - response = "Item with Key [" + request->key +"] is deleted"; - }else{ - response = "Key " + request->key +" Not Found for [delete]"; + break; + case DELETE_OPERATION: + if (DB.erase(key)) { + response = "Deleted key [" + key + "]"; + } else { + response = "Key [" + key + "] not found for deletion"; } - }else{ - response = "bad request -_____- !"; + break; + default: + response = "Invalid operation!"; + break; + } + + return response; +} + +void handle_client(int client_socket) { + char buffer[BUFFER_SIZE] = {0}; + + while (true) { // the Thread is allways active + ssize_t bytes_received = read(client_socket, buffer, BUFFER_SIZE - 1); + if (bytes_received <= 0) { + std::cout << "Client disconnected." << std::endl; + break; } - // send Response - send(client_socket, response.c_str(), strlen(response.c_str()), 0); - + buffer[bytes_received] = '\0'; + std::string response = processRequest(buffer); + + send(client_socket, response.c_str(), response.size(), 0); } - // Socket schließen close(client_socket); } @@ -117,25 +173,21 @@ int main() { struct sockaddr_in address; socklen_t addrlen = sizeof(address); - // Socket erstellen server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd == -1) { perror("Socket failed"); exit(EXIT_FAILURE); } - // 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); } - // Server lauscht auf eingehende Verbindungen if (listen(server_fd, 5) < 0) { perror("Listen failed"); exit(EXIT_FAILURE); @@ -153,13 +205,9 @@ int main() { std::cout << "New client connected" << std::endl; - // Starte neuen Thread für den Client std::thread(handle_client, client_socket).detach(); } close(server_fd); return 0; } - - - diff --git a/prak3/src/test.cpp b/prak3/src/test.cpp index 53ebf9554bcf70157cf5502182d3d55a5442cafa..9bda53a02530edfa6ecefa3261fa381d4cb47110 100644 --- a/prak3/src/test.cpp +++ b/prak3/src/test.cpp @@ -1,14 +1,33 @@ #include <iostream> -#include <string> -#include <cstring> // for strtok and strchr +#include <thread> +#include <vector> +#include <cstring> +#include <unistd.h> +#include <arpa/inet.h> +#include <mutex> +#include <map> + +#define PORT 2525 + +#define BUFFER_SIZE 1024 +#define STORE_OPERATION 's' +#define GET_OPERATION 'g' +#define DELETE_OPERATION 'd' + + + +std::mutex mtx; +std::map<std::string,std::string> DB; + + + struct Request { - char operation; // Operation: 's' (store), 'g' (get), 'd' (delete) - std::string key; // Key - std::string value; // Value (only for store operation) + char operation; + std::string key; + std::string value; }; - -Request* parseRequest(const char* buffer) { + Request* parseRequest(const char* buffer) { // Create a new Request struct Request* req = new Request(); @@ -45,36 +64,102 @@ Request* parseRequest(const char* buffer) { 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; + + if(request->operation == STORE_OPERATION){ + std::lock_guard<std::mutex> lock(mtx); + DB[request->key] = request->value; + response = "freue dich :)"; + }else if (request->operation == GET_OPERATION){ + + std::lock_guard<std::mutex> lock(mtx); + auto it = DB.find(request->key); + if (it != DB.end()) { + response = "The Value of the [" + request->key + "] is => " + it->second; + }else{ + response = "Key [" + request->key +"] Not Found"; + } + + }else if (request->operation == DELETE_OPERATION){ + std::lock_guard<std::mutex> lock(mtx); + if(DB.erase(request->key) != 0){ + response = "Item with Key [" + request->key +"] is deleted"; + }else{ + response = "Key " + request->key +" Not Found for [delete]"; + } + }else{ + response = "bad request -_____- !"; + } + + // send Response + send(client_socket, response.c_str(), strlen(response.c_str()), 0); + + } + + // Socket schließen + close(client_socket); +} + 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; + int server_fd, client_socket; + struct sockaddr_in address; + socklen_t addrlen = sizeof(address); + + // Socket erstellen + server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server_fd == -1) { + perror("Socket failed"); + exit(EXIT_FAILURE); } - if (getReq) { - std::cout << "Get Request: Operation=" << getReq->operation - << ", Key=" << getReq->key << std::endl; - delete getReq; + // 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 (deleteReq) { - std::cout << "Delete Request: Operation=" << deleteReq->operation - << ", Key=" << deleteReq->key << std::endl; - delete deleteReq; + // Server lauscht auf eingehende Verbindungen + if (listen(server_fd, 5) < 0) { + perror("Listen failed"); + exit(EXIT_FAILURE); } + std::cout << "Server listening on port " << PORT << std::endl; + + while (true) { + client_socket = accept(server_fd, (struct sockaddr*)&address, &addrlen); + + if (client_socket < 0) { + perror("Accept failed"); + continue; + } + + std::cout << "New client connected" << std::endl; + + // Starte neuen Thread für den Client + std::thread(handle_client, client_socket).detach(); + } + + close(server_fd); return 0; -} \ No newline at end of file +} + + +