Update README.md
Browse files
README.md
CHANGED
@@ -349,6 +349,190 @@ Now, your FastAPI webserver has a ping endpoint that returns the current date in
|
|
349 |
|
350 |
</details>
|
351 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
352 |
#### Word games / trivia
|
353 |
|
354 |
```
|
|
|
349 |
|
350 |
</details>
|
351 |
|
352 |
+
<details>
|
353 |
+
<summary>Write a multi-threaded TCP server in C that accepts a "GET [key]" input and "SET [key] [value]" input, and uses a binary tree to get and store the input values.</summary>
|
354 |
+
|
355 |
+
Here's a simple implementation of a multi-threaded TCP server in C that accepts "GET [key]" and "SET [key] [value]" inputs, and uses a binary tree to store the input values.
|
356 |
+
|
357 |
+
```c
|
358 |
+
#include <stdio.h>
|
359 |
+
#include <stdlib.h>
|
360 |
+
#include <sys/socket.h>
|
361 |
+
#include <netinet/in.h>
|
362 |
+
#include <unistd.h>
|
363 |
+
#include <string.h>
|
364 |
+
#include <pthread.h>
|
365 |
+
|
366 |
+
#define MAX_KEY_LEN 256
|
367 |
+
#define MAX_VALUE_LEN 256
|
368 |
+
|
369 |
+
typedef struct Node {
|
370 |
+
char key[MAX_KEY_LEN];
|
371 |
+
char value[MAX_VALUE_LEN];
|
372 |
+
struct Node* left;
|
373 |
+
struct Node* right;
|
374 |
+
} TreeNode;
|
375 |
+
|
376 |
+
TreeNode* tree = NULL;
|
377 |
+
|
378 |
+
void insert(char* key, char* value) {
|
379 |
+
TreeNode* parent = (TreeNode*)malloc(sizeof(TreeNode));
|
380 |
+
if (!parent) {
|
381 |
+
perror("malloc failed");
|
382 |
+
exit(1);
|
383 |
+
}
|
384 |
+
|
385 |
+
strcpy(parent->key, key);
|
386 |
+
strcpy(parent->value, value);
|
387 |
+
|
388 |
+
parent->left = parent->right = NULL;
|
389 |
+
|
390 |
+
if (!tree) {
|
391 |
+
tree = parent;
|
392 |
+
} else {
|
393 |
+
insert(parent->key, parent->value);
|
394 |
+
}
|
395 |
+
}
|
396 |
+
|
397 |
+
char* search(char* key) {
|
398 |
+
TreeNode* current = tree;
|
399 |
+
while (current != NULL) {
|
400 |
+
if (strcmp(key, current->key) == 0) {
|
401 |
+
return current->value;
|
402 |
+
}
|
403 |
+
current = current->right;
|
404 |
+
}
|
405 |
+
|
406 |
+
return NULL;
|
407 |
+
}
|
408 |
+
|
409 |
+
void print_tree() {
|
410 |
+
TreeNode* current = tree;
|
411 |
+
while (current != NULL) {
|
412 |
+
printf("%s = %s\n", current->key, current->value);
|
413 |
+
current = current->right;
|
414 |
+
}
|
415 |
+
}
|
416 |
+
|
417 |
+
void* accept_client(void* args) {
|
418 |
+
int client_socket = *(int*)args;
|
419 |
+
char buffer[1024];
|
420 |
+
|
421 |
+
while (1) {
|
422 |
+
ssize_t bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
|
423 |
+
if (bytes_received <= 0) {
|
424 |
+
close(client_socket);
|
425 |
+
break;
|
426 |
+
}
|
427 |
+
|
428 |
+
char* input = buffer;
|
429 |
+
char* input_token;
|
430 |
+
|
431 |
+
while ((input_token = strtok(input, " \n")) != NULL) {
|
432 |
+
switch (input_token[0]) {
|
433 |
+
case 'G':
|
434 |
+
if (!search(input_token)) {
|
435 |
+
perror("Value not found");
|
436 |
+
exit(1);
|
437 |
+
}
|
438 |
+
printf("%s = %s\n", input_token, search(input_token));
|
439 |
+
break;
|
440 |
+
|
441 |
+
case 'S':
|
442 |
+
if (!strcmp(input_token, "SET")) {
|
443 |
+
char* key = strtok(NULL, " \n");
|
444 |
+
char* value = strtok(NULL, " \n");
|
445 |
+
if (!key || !value) {
|
446 |
+
perror("Invalid input");
|
447 |
+
exit(1);
|
448 |
+
}
|
449 |
+
|
450 |
+
insert(key, value);
|
451 |
+
printf("%s set %s to %s\n", input_token, key, value);
|
452 |
+
} else {
|
453 |
+
perror("Invalid command");
|
454 |
+
exit(1);
|
455 |
+
}
|
456 |
+
break;
|
457 |
+
|
458 |
+
default:
|
459 |
+
perror("Invalid input");
|
460 |
+
exit(1);
|
461 |
+
}
|
462 |
+
|
463 |
+
input = strtok(NULL, " \n");
|
464 |
+
}
|
465 |
+
}
|
466 |
+
|
467 |
+
return NULL;
|
468 |
+
}
|
469 |
+
|
470 |
+
int main() {
|
471 |
+
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
|
472 |
+
if (server_socket < 0) {
|
473 |
+
perror("socket failed");
|
474 |
+
exit(1);
|
475 |
+
}
|
476 |
+
|
477 |
+
struct sockaddr_in server_addr;
|
478 |
+
memset(&server_addr, 0, sizeof(server_addr));
|
479 |
+
server_addr.sin_family = AF_INET;
|
480 |
+
server_addr.sin_port = htons(8080);
|
481 |
+
server_addr.sin_addr.s_addr = INADDR_ANY;
|
482 |
+
|
483 |
+
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
|
484 |
+
perror("bind failed");
|
485 |
+
exit(1);
|
486 |
+
}
|
487 |
+
|
488 |
+
if (listen(server_socket, 5) < 0) {
|
489 |
+
perror("listen failed");
|
490 |
+
exit(1);
|
491 |
+
}
|
492 |
+
|
493 |
+
pthread_t accept_thread;
|
494 |
+
pthread_create(&accept_thread, NULL, accept_client, &server_socket);
|
495 |
+
|
496 |
+
char* client_input;
|
497 |
+
int client_socket = accept(server_socket, (struct sockaddr*)NULL, NULL);
|
498 |
+
if (client_socket < 0) {
|
499 |
+
perror("accept failed");
|
500 |
+
exit(1);
|
501 |
+
}
|
502 |
+
|
503 |
+
while (1) {
|
504 |
+
sleep(1);
|
505 |
+
|
506 |
+
char buffer[1024];
|
507 |
+
ssize_t bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
|
508 |
+
if (bytes_received <= 0) {
|
509 |
+
close(client_socket);
|
510 |
+
break;
|
511 |
+
}
|
512 |
+
|
513 |
+
client_input = buffer;
|
514 |
+
parse_input(client_input);
|
515 |
+
}
|
516 |
+
|
517 |
+
close(client_socket);
|
518 |
+
pthread_join(accept_thread, NULL);
|
519 |
+
|
520 |
+
return 0;
|
521 |
+
}
|
522 |
+
```
|
523 |
+
|
524 |
+
To compile and run this code, save it to a file named `multi_threaded_tcp_server.c`, then use the following commands:
|
525 |
+
|
526 |
+
```sh
|
527 |
+
gcc -o multi_threaded_tcp_server multi_threaded_tcp_server.c
|
528 |
+
./multi_threaded_tcp_server
|
529 |
+
```
|
530 |
+
|
531 |
+
This implementation creates a simple binary tree to store the input values. The accept() function creates a new thread for each client connection, which handles the incoming data and forwards it to the main thread. The main thread parses the input string and handles SET and GET commands.
|
532 |
+
|
533 |
+
Note that this code is not production-ready and should be improved with proper error handling, security checks, and a more efficient data structure for the binary tree.
|
534 |
+
|
535 |
+
</details>
|
536 |
#### Word games / trivia
|
537 |
|
538 |
```
|