Skip to content

Instantly share code, notes, and snippets.

@caiorss
Created July 2, 2020 04:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save caiorss/ac308ab6a4cd8d92f02b4f9baeb910f3 to your computer and use it in GitHub Desktop.
Save caiorss/ac308ab6a4cd8d92f02b4f9baeb910f3 to your computer and use it in GitHub Desktop.
Unix-domain socket server
// 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