-
-
Save caiorss/ac308ab6a4cd8d92f02b4f9baeb910f3 to your computer and use it in GitHub Desktop.
Unix-domain socket server
This file contains 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
// File: socket-echo-server.cpp | |
// Desc: Simple socket server with a single thread. | |
#include <iostream> | |
#include <string> | |
#include <vector> | |
#include <cassert> | |
#include <cstring> // memcpy | |
// ----- Unix/Linux headers -----// | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <sys/un.h> | |
// ------------- MAIN() ------------------------------// | |
int main(int argc, char** argv) | |
{ | |
std::puts(" [INFO] Program started. "); | |
const char* unix_sock_file = "/tmp/unix-socket-file"; | |
// --- Create socket file descriptor -----------------------// | |
int sockfd = socket ( AF_UNIX, SOCK_STREAM, 0); | |
assert( sockfd != - 1); | |
struct sockaddr_un sa; | |
sa.sun_family = AF_UNIX; | |
strcpy( sa.sun_path, unix_sock_file); | |
// Remove file if it exists. | |
unlink(unix_sock_file); | |
// ----- Bind to unix domain socket and wait for client connections ---------// | |
if( ::bind(sockfd, (sockaddr *) &sa, sizeof(sa)) == -1) | |
{ | |
int err = errno; | |
fprintf(stderr, "Error: unable to bind socket \n"); | |
fprintf(stderr, " [ERROR] => %s", strerror(err)); | |
return EXIT_FAILURE; | |
} | |
// Enables binding to the same address | |
int enable_reuseaddr = 1; | |
if ( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable_reuseaddr, sizeof(int)) < 0 ) | |
{ | |
fprintf(stderr, "Error: unable to set socket option. \n"); | |
return EXIT_FAILURE; | |
} | |
fprintf(stderr, " [TRACE] Listening client connection \n"); | |
int backlog = 5; | |
assert( listen(sockfd, backlog) != -1 ); | |
// --------------- Server Main Loop --------------------------// | |
// Infinite loop where client connections are handled | |
while(true) | |
{ | |
/* [[ ============== BEGIN client loop =========== ]] */ | |
struct sockaddr_un client_sa; | |
socklen_t addrlen = sizeof(sockaddr_un); | |
fprintf(stderr, " [TRACE] Waiting for client connection. \n"); | |
int sock_client = accept(sockfd, (sockaddr *) &client_sa, &addrlen ); | |
if(sock_client == -1) | |
{ | |
fprintf(stderr, " Error: failure to handle client socket. Check errno \n"); | |
close(sock_client); | |
continue; | |
} | |
const char* welcome_msg = "\n => [INFO] Hello world client side!! \n"; | |
// Send buffer content to client socket | |
send(sock_client, welcome_msg, strlen(welcome_msg), 0); | |
char buffer[300]; | |
while(true){ | |
// Read message from client socket | |
ssize_t n = recv(sock_client, &buffer, 300, 0); | |
if(n == 0){ break; } | |
std::fprintf(stdout, " [INFO] Received: "); | |
::write(STDOUT_FILENO, buffer, n); | |
// Send content back | |
send(sock_client, buffer, n, 0); | |
// Compare 4 first bytes of buffer and 'quit' | |
if( strncmp(buffer, "quit", 4) == 0) | |
{ | |
fprintf(stderr, " [TRACE] Shutdown connection. Ok. \n"); | |
// Close client connection | |
shutdown(sock_client, SHUT_RDWR); | |
close(sock_client); | |
break; | |
} | |
} | |
} /* [[ ============== END client loop =========== ]] */ | |
// Release resource => RAII (Resource-Acquisition-Is-Initialization) fits here. | |
close(sockfd); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment