/** * Asynchrónny TCP server pomocou select() * * Server prijíma viacero klientov naraz bez blokovania. * Každý klient pošle správu, server ju vráti späť (echo). * * Spustenie: ./server * Klient: ./client alebo telnet 127.0.0.1 8080 */ #include #include #include #include #include #include #include #define PORT 8080 #define MAX_CLIENTS 10 #define BUFFER_SIZE 1024 int main(void) { int server_fd; int client_fds[MAX_CLIENTS]; struct sockaddr_in address; char buffer[BUFFER_SIZE]; // Inicializácia zoznamu klientov for (int i = 0; i < MAX_CLIENTS; i++) { client_fds[i] = -1; } // 1. Otvorenie soketu server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("socket"); exit(EXIT_FAILURE); } // Povolenie opätovného použitia adresy po reštarte int opt = 1; setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); // 2. Väzba na port address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind"); exit(EXIT_FAILURE); } // 3. Počúvanie if (listen(server_fd, 5) < 0) { perror("listen"); exit(EXIT_FAILURE); } printf("Server počúva na porte %d...\n", PORT); while (1) { // Zostav množinu sledovaných deskriptorov fd_set read_fds; FD_ZERO(&read_fds); FD_SET(server_fd, &read_fds); int max_fd = server_fd; for (int i = 0; i < MAX_CLIENTS; i++) { if (client_fds[i] > 0) { FD_SET(client_fds[i], &read_fds); if (client_fds[i] > max_fd) { max_fd = client_fds[i]; } } } // 4. select() — čakaj na aktivitu (asynchrónne) // Vráti sa ihneď, keď je niektorý soket pripravený struct timeval timeout = {5, 0}; // čakaj max 5 sekúnd int activity = select(max_fd + 1, &read_fds, NULL, NULL, &timeout); if (activity < 0) { perror("select"); break; } if (activity == 0) { printf("Žiadna aktivita (timeout)...\n"); continue; } // Nové spojenie na server_fd? if (FD_ISSET(server_fd, &read_fds)) { socklen_t addrlen = sizeof(address); int new_fd = accept(server_fd, (struct sockaddr *)&address, &addrlen); if (new_fd < 0) { perror("accept"); continue; } printf("Nový klient: fd=%d\n", new_fd); // Pridaj klienta do zoznamu for (int i = 0; i < MAX_CLIENTS; i++) { if (client_fds[i] == -1) { client_fds[i] = new_fd; break; } } } // Skontroluj aktivitu existujúcich klientov for (int i = 0; i < MAX_CLIENTS; i++) { int fd = client_fds[i]; if (fd < 0 || !FD_ISSET(fd, &read_fds)) { continue; } // 5. Čítanie správy od klienta int bytes = read(fd, buffer, BUFFER_SIZE - 1); if (bytes <= 0) { // Klient sa odpojil printf("Klient fd=%d sa odpojil.\n", fd); close(fd); client_fds[i] = -1; } else { buffer[bytes] = '\0'; printf("Prijatá správa od fd=%d: %s", fd, buffer); // 6. Echo — odošli správu späť klientovi write(fd, buffer, bytes); } } } close(server_fd); return 0; }