#include #include #include #include #include #include #include #include #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 \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; }