Last active
November 28, 2022 19:44
-
-
Save rosalogia/d38104430b3fa50297d73a1819474d8c to your computer and use it in GitHub Desktop.
Simple echo server impl. in C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <sys/socket.h> | |
#include <sys/types.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <netdb.h> | |
#include <errno.h> | |
int main() { | |
// First declare some basic known information about our socket | |
// in an addrinfo struct named hints, then use that struct to | |
// infer the remaining addrinfo fields needed to create and bind | |
// our socket | |
struct addrinfo hints, *res; | |
// Clearing the hints struct; this is important! | |
memset(&hints, 0, sizeof(hints)); | |
hints.ai_family = AF_INET; // Use ipv4 addresses | |
hints.ai_socktype = SOCK_STREAM; // Use TCP rather than UDP | |
// Fill *res with a more complete addrinfo based on the hints we provided | |
getaddrinfo("127.0.0.1", "5000", &hints, &res); | |
// Initialize and bind our socket file descriptor using information from our | |
// newly-filled result addrinfo | |
int socket_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); | |
if (socket_fd == -1) { | |
perror("Error while creating socket"); | |
return -1; | |
} | |
if (bind(socket_fd, res->ai_addr, res->ai_addrlen) == -1) { | |
perror("Error occurred while binding socket"); | |
return -1; | |
} | |
if (listen(socket_fd, 20) == -1) { | |
perror("Error occurred while listening on socket"); | |
return -1; | |
} | |
// Declare: | |
// - A sockaddr_storage for storing the address info of the client | |
// - A file descriptor for the client socket | |
// - An integer for storing the number of bytes read from the client | |
// - A socklen_t for storing the size of the client's address | |
// - A char buffer for storing the incoming message | |
struct sockaddr_storage incoming_addr; | |
int incoming_socket, read; | |
socklen_t addr_size = sizeof(incoming_addr); | |
char buff[1024]; | |
// Accept loop | |
while (1) { | |
incoming_socket = accept(socket_fd, (struct sockaddr*) &incoming_addr, &addr_size); | |
if (incoming_socket == -1) { | |
perror("Error occurred while accepting on socket"); | |
continue; | |
} | |
// Let's handle reading/writing in a child process so we | |
// can continue to accept new connections in the parent process | |
if (!fork()) { | |
// We don't need the server's socket fd in this child process | |
close(socket_fd); | |
while (1) { | |
// Read at most 1024 bytes from the client's socket into buff, | |
// with no added flags | |
read = recv(incoming_socket, buff, 1024, 0); | |
if (read < 0) { | |
perror("Error occurred while reading from client"); | |
return -1; | |
} | |
// Reading in 0 bytes means the client has closed the connection | |
if (read == 0) { | |
printf("Client closed the connection\n"); | |
return -1; | |
} | |
if (send(incoming_socket, buff, read, 0) < 0) { | |
perror("Error occurred while writing to client"); | |
return -1; | |
} | |
} | |
close(incoming_socket); | |
} | |
close(incoming_socket); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment