Skip to content

Instantly share code, notes, and snippets.

@michelesr
Last active August 8, 2024 20:19
Show Gist options
  • Save michelesr/8b18eb4929d7e50eefa3c849738068cb to your computer and use it in GitHub Desktop.
Save michelesr/8b18eb4929d7e50eefa3c849738068cb to your computer and use it in GitHub Desktop.
Example epoll event loop based TCP server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/epoll.h>
#define BUFFER_SIZE 256
#define PORT 4000
#define IP_ADDRESS "127.0.0.1"
#define MAX_EVENTS 10
int main() {
int server_fd, client_fd, epoll_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[BUFFER_SIZE];
// Create a socket
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// Set address and port number for the server
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
inet_pton(AF_INET, IP_ADDRESS, &server_addr.sin_addr);
// Bind the socket to the address and port
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// Listen for incoming connections
if (listen(server_fd, 3) < 0) {
perror("listen failed");
exit(EXIT_FAILURE);
}
printf("Server listening on %s:%d...\n", IP_ADDRESS, PORT);
// Create an epoll instance
epoll_fd = epoll_create1(0);
if (epoll_fd < 0) {
perror("epoll creation failed");
exit(EXIT_FAILURE);
}
// Add the server socket to the epoll instance
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = server_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) < 0) {
perror("epoll_ctl failed");
exit(EXIT_FAILURE);
}
while (1) {
// Wait for events on the epoll instance
struct epoll_event events[MAX_EVENTS];
int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (num_events < 0) {
perror("epoll_wait failed");
exit(EXIT_FAILURE);
}
// Handle each event
for (int i = 0; i < num_events; i++) {
if (events[i].data.fd == server_fd) {
// Accept a new connection
client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);
if (client_fd < 0) {
perror("accept failed");
continue;
}
printf("Connection accepted from client IP address %s and port %d...\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// Add the client socket to the epoll instance
event.events = EPOLLIN;
event.data.fd = client_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event) < 0) {
perror("epoll_ctl failed");
continue;
}
} else {
// Read from the client
int bytes_read = read(events[i].data.fd, buffer, BUFFER_SIZE);
if (bytes_read < 0) {
perror("read failed");
continue;
} else if (bytes_read == 0) {
printf("Client disconnected...\n");
close(events[i].data.fd);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
continue;
}
printf("Received message from client: %s\n", buffer);
// Check for newline character
if (buffer[0] == '\n') {
printf("Client sent newline, closing connection...\n");
close(events[i].data.fd);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
continue;
}
// Write back to the client
int bytes_written = write(events[i].data.fd, buffer, bytes_read);
if (bytes_written < 0) {
perror("write failed");
continue;
}
}
}
}
return 0;
}
@michelesr
Copy link
Author

michelesr commented Aug 8, 2024

Before line 105 it should probably terminate the string before printing it to avoid printing after the end of the message:

buffer[bytes_read] = '\0';

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment