diff options
author | scratko <m@scratko.xyz> | 2024-09-13 16:14:33 +0300 |
---|---|---|
committer | scratko <m@scratko.xyz> | 2024-09-13 16:26:40 +0300 |
commit | 0c12d9c3fd09f4881eb80d8f2b632ab3310f6010 (patch) | |
tree | daf816f0108c42ccd39e0aaeef076732e734f1e6 | |
download | multithreading-client-handling-0c12d9c3fd09f4881eb80d8f2b632ab3310f6010.tar.gz multithreading-client-handling-0c12d9c3fd09f4881eb80d8f2b632ab3310f6010.tar.bz2 multithreading-client-handling-0c12d9c3fd09f4881eb80d8f2b632ab3310f6010.zip |
-rw-r--r-- | server.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/server.c b/server.c new file mode 100644 index 0000000..57300eb --- /dev/null +++ b/server.c @@ -0,0 +1,137 @@ +#include <stdio.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <pthread.h> +#include <semaphore.h> +#include <unistd.h> +#include <string.h> + +#ifndef INBUFSIZE +#define INBUFSIZE 1024 +#endif + +#ifndef LISTEN_QLEN +#define LISTEN_QLEN 32 +#endif + +struct thread_data { + int counter; + pthread_mutex_t mutex; + sem_t semaphore; + int fd; +}; + +static void change_counter(char *buffer, pthread_mutex_t *mutex, int *counter, + int fd) +{ + int tmp_counter = 0; + char counter_buffer[13]; + + if(!strcmp(buffer, "up")) { + pthread_mutex_lock(mutex); + ++*counter; + pthread_mutex_unlock(mutex); + write(fd, "Ok\n", strlen("Ok\n")); + } else if(!strcmp(buffer, "down")) { + pthread_mutex_lock(mutex); + --*counter; + pthread_mutex_unlock(mutex); + write(fd, "Ok\n", strlen("Ok\n")); + } else if(!strcmp(buffer, "show")) { + pthread_mutex_lock(mutex); + tmp_counter = *counter; + pthread_mutex_unlock(mutex); + sprintf(counter_buffer, "%d\n", tmp_counter); + write(fd, counter_buffer, strlen(counter_buffer)); + } else + write(fd, "unknown command\n", strlen("unknown command\n")); +} + +static void *worker_thread(void *data) +{ + int data_left, i; + char buffer[INBUFSIZE]; + struct thread_data *local_data = data; + pthread_mutex_t *mutex = &local_data->mutex; + sem_t *semaphore = &local_data->semaphore; + int *counter = &local_data->counter; + int fd = local_data->fd; + char tmp_symbol; + + sem_post(semaphore); + pthread_detach(pthread_self()); + + for(;;) { + data_left = read(fd, buffer, INBUFSIZE); + if(data_left <= 0) + break; + for(i = 0; i < data_left; ++i) { + if(buffer[i] == '\r' || buffer[i] == '\n') { + tmp_symbol = buffer[i]; + buffer[i] = '\0'; + change_counter(buffer, mutex, counter, fd); + if(tmp_symbol == '\r') + ++i; + if(i + 1 != data_left) { + data_left -= i + 1; + memmove(buffer, buffer+i+1, data_left); + i = -1; + } else + break; + } + } + } + close(fd); + return 0; +} + +static void init_data(struct thread_data *data) +{ + data->counter = 0; + pthread_mutex_init(&data->mutex, NULL); + sem_init(&data->semaphore, 0, 0); +} + +int main(int argc, char **argv) +{ + int server_socket, opt; + unsigned short port; + struct sockaddr_in addr; + struct thread_data data; + pthread_t thr; + socklen_t len; + + if(argc != 2) { + fprintf(stderr, "usage: ./program <server port> \n"); + return 1; + } + port = strtol(argv[1], NULL, 10); + server_socket = socket(AF_INET, SOCK_STREAM, 0); + if(server_socket == -1) { + perror("socket"); + return 0; + } + opt = 1; + setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + + if(bind(server_socket, (struct sockaddr*) &addr, sizeof(addr)) == -1) { + perror("bind"); + return 1; + } + + listen(server_socket, LISTEN_QLEN); + len = sizeof(addr); + init_data(&data); + + for(;;) { + data.fd = accept(server_socket, (struct sockaddr*) &addr, &len); + pthread_create(&thr, NULL, worker_thread, &data); + sem_wait(&data.semaphore); + } + return 0; +} |