Unix Domain Socket

This commit is contained in:
2024-04-25 11:46:12 +05:30
commit 092dd20556
5 changed files with 395 additions and 0 deletions

24
AF_UNIX/CMakeLists.txt Normal file
View File

@@ -0,0 +1,24 @@
# CMakeList.txt : CMake project for AF_UNIX, include source and define
# project specific logic here.
#
cmake_minimum_required (VERSION 3.8)
# Enable Hot Reload for MSVC compilers if supported.
if (POLICY CMP0141)
cmake_policy(SET CMP0141 NEW)
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
endif()
project ( AF_UNIX VERSION 1.0.0 LANGUAGES C CXX)
set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
# Add source to this project's executable.
add_executable (server "server.c")
add_executable (client "client.c")
# TODO: Add tests and install targets if needed.

101
AF_UNIX/CMakePresets.json Normal file
View File

@@ -0,0 +1,101 @@
{
"version": 3,
"configurePresets": [
{
"name": "windows-base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "cl.exe",
"CMAKE_CXX_COMPILER": "cl.exe"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "x64-debug",
"displayName": "x64 Debug",
"inherits": "windows-base",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "x64-release",
"displayName": "x64 Release",
"inherits": "x64-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "x86-debug",
"displayName": "x86 Debug",
"inherits": "windows-base",
"architecture": {
"value": "x86",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "x86-release",
"displayName": "x86 Release",
"inherits": "x86-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "linux-debug",
"displayName": "Linux Debug",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"vendor": {
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
"sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
}
}
},
{
"name": "macos-debug",
"displayName": "macOS Debug",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"vendor": {
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
"sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
}
}
}
]
}

88
AF_UNIX/client.c Normal file
View File

@@ -0,0 +1,88 @@
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define SOCKET_NAME "/tmp/DemoSocket"
#define BUFFER_SIZE 128
int
main(int argc, char* argv[]) {
struct sockaddr_un addr;
int i;
int ret;
int data_socket;
char buffer[BUFFER_SIZE];
/* Create data socket */
/* Client side don't have any concept of Master socket.
It directly use data socket to communicate with server. */
data_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (data_socket == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
/*
For portability clear the whole structure, since some implementation
have additional (nonstandard) fields in the structure.
*/
memset(&addr, 0, sizeof(struct sockaddr_un));
/* Connect socket to socket address. */
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
ret = connect(data_socket, (const struct sockaddr*)&addr,
sizeof(struct sockaddr_un));
if (ret == -1) {
fprintf(stderr, "The server is down.\n");
exit(EXIT_FAILURE);
}
/* Send arguments */
do {
printf("Enter number to send to server :\n");
scanf("%d", &i);
ret = write(data_socket, &i, sizeof(int));
if (ret == -1) {
perror("write");
exit(EXIT_FAILURE);
}
printf("No of bytes sent = %d, data sent = %d\n", ret, i);
} while (i);
/* Request result */
memset(buffer, 0, BUFFER_SIZE);
strncpy(buffer, "RES", strlen("RES"));
buffer[strlen(buffer)] = '\0';
ret = read(data_socket, buffer, BUFFER_SIZE);
if (ret == -1) {
perror("read");
exit(EXIT_FAILURE);
}
/* Ensure buffer is 0 - terminated */
buffer[BUFFER_SIZE - 1] = 0;
printf("%s\n", buffer);
/* Close socket */
close(data_socket);
exit(EXIT_SUCCESS);
return 0;
}

178
AF_UNIX/server.c Normal file
View File

@@ -0,0 +1,178 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define SOCKET_NAME "/tmp/DemoSocket" /* Unique name of the socket */
#define BUFFER_SIZE 128 /* Size of the buffer which will be used by
for Communication. */
int
main(int argc, char* argv[]) {
/* Structure provided by Unix library for using
it as an identifier for managing the socket */
struct sockaddr_un name;
#if 0
struct sockaddr_un {
/* This member describe what type of data it
will handle. Define the family of the
socket. Here, we are using UNIX DOMAIN socket
so AF_UNIX constant should be used for
classification. */
sa_family_t sun_family; /* AF_UNIX */
/* Hold the name of the socket with the path where it
is created. */
char sun_path[108]; /* pathname */
};
#endif
int ret;
int connection_socket;
int data_socket;
int result;
int data;
char buffer[BUFFER_SIZE];
/* In case the program exited inadvertently on the last run,
remove the socket. */
unlink(SOCKET_NAME);
/* Create Master socket */
/* SOCK_DGRAM for Datagram based communication */
connection_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (connection_socket == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
printf("Master socket created\n");
/* initialize */
memset(&name, 0, sizeof(struct sockaddr_un));
/* Specify the socket Cridentials */
name.sun_family = AF_UNIX;
strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
/* Bind Socket to socket name. */
/* Purpose of bind() system call is that application() dictate the underlying
operating system the criteria of receiving the data. Here, bind() system call
is telling the OS that if sender process sends the data destined to socket
"tmp/DemoSocket", then such data needs to be delievered to this server process
( the server process ) */
ret = bind(connection_socket, (const struct sockaddr* )&name,
sizeof(struct sockaddr_un));
if (ret == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
printf("bind() call succeed\n");
/* Prepare for accepting connections. The backlog size is set to 20.
So, while one request is being processed other requests can be
waiting.
*/
ret = listen(connection_socket, 20);
if (ret == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
/* This is the main loop for handling connections. */
/* All Server process usually runs 24 x 7. Good Servers should always up
running and should never go down. */
for (;;) {
/* Wait for incoming connection. */
printf("Waiting on accept() sys call\n");
data_socket = accept(connection_socket, NULL, NULL);
if (data_socket == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
printf("Connection accepted from client\n");
result = 0;
for (;;) {
/* Prepare the buffer to recv the data*/
memset(buffer, 0, BUFFER_SIZE);
/*Wait for next data packet. */
/* Server is blocked here. Waiting for the data to arrive from client
'read' is a blocking system call. */
printf("Waiting for data from the client\n");
ret = read(data_socket, buffer, BUFFER_SIZE);
if (ret == -1) {
perror("read");
exit(EXIT_FAILURE);
}
/* Add received summand */
memcpy(&data, buffer, sizeof(int));
if (data == 0) break;
result += data;
}
/* Send result. */
memset(buffer, 0, BUFFER_SIZE);
sprintf(buffer, "Result = %d", result);
printf("Sending final result back to client\n");
/* non-blockding system call */
ret = write(data_socket, buffer, BUFFER_SIZE);
if (ret == -1) {
perror("write");
exit(EXIT_FAILURE);
}
/*close socket*/
close(data_socket);
}
/*close the master socket*/
close(connection_socket);
printf("connection closed..\n");
/* Server should release resources before getting terminated.
Unlink the socket. */
unlink(SOCKET_NAME);
exit(EXIT_SUCCESS);
return 0;
}