├── DBus ├── CMakeLists.txt ├── process_client.c ├── process_listen_signal.c └── process_server.c ├── FIFO ├── CMakeLists.txt ├── process_read.c └── process_write.c ├── File ├── CMakeLists.txt └── read_write_shared_file.c ├── MessageQueue ├── CMakeLists.txt ├── posix_msgq_multiple_types.c ├── system_v_msgq_multiple_types.c └── system_v_msgq_random_numbers.c ├── Pipe ├── CMakeLists.txt ├── pipe_ls_wc.c ├── pipe_parent_and_child.c └── pipe_same_process.c ├── README.md ├── Semaphore ├── CMakeLists.txt ├── posix_semaphore.c ├── system_v_multiple_semaphores.c └── system_v_semaphore.c ├── SharedMemory ├── CMakeLists.txt ├── posix_memory_mapped_file.c ├── posix_shared_mem.c └── system_v_shared_mem.c ├── Signal ├── CMakeLists.txt ├── process_a.cpp ├── process_b.cpp ├── process_c.cpp └── system_service.cpp └── Socket ├── CMakeLists.txt ├── unix_client.c ├── unix_server.c └── unix_socket_pair.c /DBus/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10...3.28) 2 | project(IPCDBus) 3 | 4 | set(CMAKE_BUILD_TYPE Debug) 5 | 6 | # Find the dbus-1 package 7 | find_package(PkgConfig REQUIRED) 8 | pkg_check_modules(DBUS1 REQUIRED dbus-1) 9 | 10 | function(compile_executables target_name file_path) 11 | add_executable(${target_name} ${file_path}) 12 | 13 | target_link_libraries(${target_name} 14 | PRIVATE 15 | pthread 16 | ${DBUS1_LIBRARIES} 17 | ) 18 | 19 | target_include_directories(${target_name} 20 | PRIVATE 21 | ${DBUS1_INCLUDE_DIRS} 22 | ) 23 | 24 | target_compile_options(${target_name} 25 | PRIVATE 26 | ${DBUS1_CFLAGS_OTHER} 27 | ) 28 | endfunction() 29 | 30 | file(GLOB_RECURSE C_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.c") 31 | file(GLOB_RECURSE CPP_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") 32 | 33 | foreach(file_path ${C_FILES}) 34 | get_filename_component(target_name ${file_path} NAME_WE) 35 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 36 | endforeach() 37 | 38 | foreach(file_path ${CPP_FILES}) 39 | get_filename_component(target_name ${file_path} NAME_WE) 40 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 41 | endforeach() -------------------------------------------------------------------------------- /DBus/process_client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void check_dbus_error(DBusError *error, const char *msg) 7 | { 8 | if (dbus_error_is_set(error)) 9 | { 10 | fprintf(stderr, "%s: %s\n", msg, error->message); 11 | dbus_error_free(error); 12 | exit(1); 13 | } 14 | } 15 | 16 | int main() 17 | { 18 | DBusConnection *conn; 19 | DBusError error; 20 | const char *input = "Hello, D-Bus!"; 21 | int result; 22 | 23 | printf("Starting D-Bus client...\n"); 24 | 25 | dbus_error_init(&error); 26 | 27 | conn = dbus_bus_get(DBUS_BUS_SESSION, &error); 28 | check_dbus_error(&error, "Failed to connect to the D-Bus session bus"); 29 | 30 | while (1) 31 | { 32 | DBusMessage *msg, *reply; 33 | DBusMessageIter args; 34 | 35 | msg = dbus_message_new_method_call( 36 | "com.example.MyService", // Target service name 37 | "/com/example/MyObject", // Object path 38 | "com.example.MyInterface", // Interface name 39 | "GetStringLength" // Method name 40 | ); 41 | 42 | if (!msg) 43 | { 44 | fprintf(stderr, "Error: Out of memory while creating message\n"); 45 | exit(1); 46 | } 47 | 48 | dbus_message_iter_init_append(msg, &args); 49 | if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &input)) 50 | { 51 | fprintf(stderr, "Error: Out of memory while appending arguments\n"); 52 | dbus_message_unref(msg); 53 | exit(1); 54 | } 55 | 56 | reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &error); 57 | check_dbus_error(&error, "Failed to send message and wait for reply"); 58 | 59 | if (dbus_message_get_args(reply, &error, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID)) 60 | { 61 | printf("Client received reply: The length of the string is %d\n", result); 62 | } 63 | else 64 | { 65 | check_dbus_error(&error, "Failed to parse reply arguments"); 66 | } 67 | 68 | dbus_message_unref(msg); 69 | dbus_message_unref(reply); 70 | usleep(100000); 71 | } 72 | 73 | dbus_connection_unref(conn); 74 | 75 | return 0; 76 | } -------------------------------------------------------------------------------- /DBus/process_listen_signal.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define SERVICE_NAME "com.ncmv.signal_service" 10 | #define OBJECT_PATH "/tmp/ncmv/signal_object" 11 | #define INTERFACE_NAME "com.ncmv.signal_interface" 12 | #define SIGNAL_NAME "sample_signal" 13 | 14 | void init_dbus_daemon(void) __attribute__((constructor)); 15 | 16 | void init_dbus_daemon(void) 17 | { 18 | char* dbus_address = getenv("DBUS_SESSION_BUS_ADDRESS"); 19 | if (dbus_address == NULL) 20 | { 21 | fprintf(stderr, "DBUS_SESSION_BUS_ADDRESS is not set. Starting a new session bus.\n"); 22 | system("dbus-daemon --session --fork --print-address > /tmp/dbus_address"); 23 | FILE* fp = fopen("/tmp/dbus_address", "r"); 24 | if (fp == NULL) 25 | { 26 | fprintf(stderr, "Failed to open /tmp/dbus_address\n"); 27 | exit(-1); 28 | } 29 | char address[256]; 30 | if (fgets(address, sizeof(address), fp) != NULL) 31 | { 32 | address[strcspn(address, "\n")] = '\0'; 33 | setenv("DBUS_SESSION_BUS_ADDRESS", address, 1); 34 | } 35 | fclose(fp); 36 | setenv("DBUS_SESSION_BUS_ADDRESS", address, 1); 37 | printf("DBUS_SESSION_BUS_ADDRESS=%s\n", address); 38 | } 39 | } 40 | 41 | void send_signals(DBusConnection* p_con) 42 | { 43 | DBusMessage* p_msg; 44 | DBusMessageIter args; 45 | DBusError d_error; 46 | int serial = 0; 47 | char* signal_value = "Hello, World!"; 48 | 49 | dbus_error_init(&d_error); 50 | 51 | // Create a signal and check for errors 52 | p_msg = dbus_message_new_signal(OBJECT_PATH, INTERFACE_NAME, SIGNAL_NAME); 53 | if (p_msg == NULL) 54 | { 55 | fprintf(stderr, "Message Null\n"); 56 | exit(-1); 57 | } 58 | 59 | // Append arguments onto signal 60 | dbus_message_iter_init_append(p_msg, &args); 61 | if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &signal_value)) 62 | { 63 | fprintf(stderr, "Out Of Memory!\n"); 64 | exit(-1); 65 | } 66 | 67 | // Send the signal and flush the connection 68 | if (!dbus_connection_send(p_con, p_msg, &serial)) 69 | { 70 | fprintf(stderr, "Out Of Memory!\n"); 71 | exit(-1); 72 | } 73 | dbus_connection_flush(p_con); 74 | 75 | printf("Signal Sent\n"); 76 | 77 | // Free the message 78 | dbus_message_unref(p_msg); 79 | } 80 | 81 | void listen_signals(DBusConnection* p_con) 82 | { 83 | DBusMessage* p_msg; 84 | DBusError d_error; 85 | 86 | dbus_error_init(&d_error); 87 | 88 | // Add a rule for which messages we want to see 89 | char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH]; 90 | snprintf(rule, sizeof(rule), "type='signal',interface='%s'", INTERFACE_NAME); 91 | dbus_bus_add_match(p_con, rule, &d_error); 92 | dbus_connection_flush(p_con); 93 | 94 | if (dbus_error_is_set(&d_error)) 95 | { 96 | fprintf(stderr, "Match Error (%s)\n", d_error.message); 97 | exit(-1); 98 | } 99 | 100 | printf("Listening for signals\n"); 101 | 102 | // Loop listening for signals being emitted 103 | while (1) 104 | { 105 | // Non blocking read of the next available message 106 | dbus_connection_read_write(p_con, 0); 107 | p_msg = dbus_connection_pop_message(p_con); 108 | 109 | // Loop again if we haven't read a message 110 | if (p_msg == NULL) 111 | { 112 | usleep(10000); 113 | continue; 114 | } 115 | 116 | // Check if the message is a signal from the correct interface and with the correct name 117 | if (dbus_message_is_signal(p_msg, INTERFACE_NAME, SIGNAL_NAME)) 118 | { 119 | DBusMessageIter args; 120 | char* signal_value; 121 | 122 | // Read the parameters 123 | if (!dbus_message_iter_init(p_msg, &args)) 124 | { 125 | fprintf(stderr, "Message has no arguments!\n"); 126 | } 127 | else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) 128 | { 129 | fprintf(stderr, "Argument is not string!\n"); 130 | } 131 | else 132 | { 133 | dbus_message_iter_get_basic(&args, &signal_value); 134 | printf("Received Signal with value: %s\n", signal_value); 135 | dbus_message_unref(p_msg); 136 | break; 137 | } 138 | } 139 | } 140 | } 141 | 142 | void cleanup(DBusConnection* p_con) 143 | { 144 | if (p_con != NULL) 145 | { 146 | dbus_connection_unref(p_con); 147 | } 148 | dbus_shutdown(); 149 | (void)unsetenv("DBUS_SESSION_BUS_ADDRESS"); 150 | } 151 | 152 | int main() 153 | { 154 | DBusConnection* p_con; 155 | DBusError d_error; 156 | int rc; 157 | 158 | dbus_error_init(&d_error); 159 | 160 | p_con = dbus_bus_get(DBUS_BUS_SESSION, &d_error); 161 | if (dbus_error_is_set(&d_error)) 162 | { 163 | fprintf(stderr, "Connection Error (%s)\n", d_error.message); 164 | dbus_error_free(&d_error); 165 | } 166 | 167 | if (p_con == NULL) 168 | { 169 | fprintf(stderr, "dbus_bus_get() failed\n"); 170 | exit(-1); 171 | } 172 | 173 | pid_t pid = fork(); 174 | if (pid < 0) 175 | { 176 | fprintf(stderr, "fork() failed\n"); 177 | exit(-1); 178 | } 179 | 180 | if (pid == 0) 181 | { 182 | // Child process send signals 183 | send_signals(p_con); 184 | } 185 | else 186 | { 187 | // Parent process listen signals 188 | listen_signals(p_con); 189 | } 190 | 191 | cleanup(p_con); 192 | 193 | return 0; 194 | } -------------------------------------------------------------------------------- /DBus/process_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void init_dbus_daemon(void) __attribute__((constructor)); 8 | 9 | void init_dbus_daemon(void) 10 | { 11 | char* dbus_address = getenv("DBUS_SESSION_BUS_ADDRESS"); 12 | if (dbus_address == NULL) 13 | { 14 | fprintf(stderr, "DBUS_SESSION_BUS_ADDRESS is not set. Starting a new session bus.\n"); 15 | system("dbus-daemon --session --fork --print-address > /tmp/dbus_address"); 16 | FILE* fp = fopen("/tmp/dbus_address", "r"); 17 | if (fp == NULL) 18 | { 19 | fprintf(stderr, "Failed to open /tmp/dbus_address\n"); 20 | exit(-1); 21 | } 22 | char address[256]; 23 | if (fgets(address, sizeof(address), fp) != NULL) 24 | { 25 | address[strcspn(address, "\n")] = '\0'; 26 | setenv("DBUS_SESSION_BUS_ADDRESS", address, 1); 27 | } 28 | fclose(fp); 29 | setenv("DBUS_SESSION_BUS_ADDRESS", address, 1); 30 | printf("DBUS_SESSION_BUS_ADDRESS=%s\n", address); 31 | } 32 | } 33 | 34 | void check_dbus_error(DBusError *error, const char *msg) 35 | { 36 | if (dbus_error_is_set(error)) 37 | { 38 | fprintf(stderr, "%s: %s\n", msg, error->message); 39 | dbus_error_free(error); 40 | exit(1); 41 | } 42 | } 43 | 44 | void handle_method_call(DBusMessage *msg, DBusConnection *conn) 45 | { 46 | DBusMessage *reply; 47 | DBusMessageIter args; 48 | const char *input; 49 | int result; 50 | 51 | if (!dbus_message_iter_init(msg, &args) || dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) 52 | { 53 | fprintf(stderr, "Error: Method call has no arguments or argument is not a string\n"); 54 | return; 55 | } 56 | 57 | dbus_message_iter_get_basic(&args, &input); 58 | printf("Server received method call with input: '%s'\n", input); 59 | 60 | result = strlen(input); 61 | 62 | reply = dbus_message_new_method_return(msg); 63 | if (!reply) 64 | { 65 | fprintf(stderr, "Error: Out of memory while creating reply\n"); 66 | return; 67 | } 68 | 69 | dbus_message_iter_init_append(reply, &args); 70 | if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &result)) 71 | { 72 | fprintf(stderr, "Error: Out of memory while appending arguments to reply\n"); 73 | dbus_message_unref(reply); 74 | return; 75 | } 76 | 77 | if (!dbus_connection_send(conn, reply, NULL)) 78 | { 79 | fprintf(stderr, "Error: Out of memory while sending reply\n"); 80 | } 81 | 82 | dbus_connection_flush(conn); 83 | dbus_message_unref(reply); 84 | } 85 | 86 | int main() 87 | { 88 | DBusConnection *conn; 89 | DBusError error; 90 | DBusMessage *msg; 91 | 92 | printf("Starting D-Bus server...\n"); 93 | dbus_error_init(&error); 94 | 95 | conn = dbus_bus_get(DBUS_BUS_SESSION, &error); 96 | check_dbus_error(&error, "Failed to connect to the D-Bus session bus"); 97 | 98 | int ret = dbus_bus_request_name(conn, "com.example.MyService", DBUS_NAME_FLAG_REPLACE_EXISTING, &error); 99 | check_dbus_error(&error, "Failed to request name on the bus"); 100 | 101 | if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) 102 | { 103 | fprintf(stderr, "Error: Not the primary owner of the name\n"); 104 | exit(1); 105 | } 106 | 107 | printf("Server is running and waiting for method calls...\n"); 108 | 109 | while (1) 110 | { 111 | dbus_connection_read_write(conn, -1); 112 | msg = dbus_connection_pop_message(conn); 113 | 114 | if (msg == NULL) 115 | { 116 | continue; 117 | } 118 | 119 | if (dbus_message_is_method_call(msg, "com.example.MyInterface", "GetStringLength")) 120 | { 121 | handle_method_call(msg, conn); 122 | } 123 | 124 | dbus_message_unref(msg); 125 | } 126 | 127 | return 0; 128 | } -------------------------------------------------------------------------------- /FIFO/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10...3.28) 2 | project(IPCPipe) 3 | 4 | set(CMAKE_BUILD_TYPE Debug) 5 | 6 | function(compile_executables target_name file_path) 7 | add_executable(${target_name} ${file_path}) 8 | 9 | target_link_libraries(${target_name} 10 | PRIVATE 11 | pthread 12 | ) 13 | endfunction() 14 | 15 | file(GLOB_RECURSE C_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.c") 16 | file(GLOB_RECURSE CPP_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") 17 | 18 | foreach(file_path ${C_FILES}) 19 | get_filename_component(target_name ${file_path} NAME_WE) 20 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 21 | endforeach() 22 | 23 | foreach(file_path ${CPP_FILES}) 24 | get_filename_component(target_name ${file_path} NAME_WE) 25 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 26 | endforeach() 27 | -------------------------------------------------------------------------------- /FIFO/process_read.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | const char* FIFO_PATH = "/tmp/sample_fifo"; 10 | const int MESSAGE_SIZE = 1024; 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int fd = open(FIFO_PATH, O_RDONLY); 15 | 16 | char buffer[MESSAGE_SIZE]; 17 | while (1) 18 | { 19 | memset(buffer, 0, sizeof(buffer)); 20 | int read_bytes = read(fd, buffer, sizeof(buffer)); 21 | if (read_bytes == 0) 22 | { 23 | printf("EOF\n"); 24 | break; 25 | } 26 | else if (read_bytes == -1) 27 | { 28 | perror("read"); 29 | break; 30 | } 31 | else 32 | { 33 | if (read_bytes < MESSAGE_SIZE) 34 | { 35 | buffer[read_bytes] = '\0'; 36 | printf("Read %d bytes: %s\n", read_bytes, buffer); 37 | } 38 | } 39 | } 40 | 41 | close(fd); 42 | return 0; 43 | } -------------------------------------------------------------------------------- /FIFO/process_write.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | const char* FIFO_PATH = "/tmp/sample_fifo"; 10 | const int MESSAGE_SIZE = 1024; 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int fifo_status = mkfifo(FIFO_PATH, 0666); 15 | if (fifo_status == -1 && errno != EEXIST) 16 | { 17 | perror("mkfifo"); 18 | return 1; 19 | } 20 | 21 | int fd = open(FIFO_PATH, O_WRONLY); 22 | char buffer[MESSAGE_SIZE]; 23 | while (1) 24 | { 25 | memset(buffer, 0, sizeof(buffer)); 26 | printf("Enter a message: "); 27 | fgets(buffer, sizeof(buffer), stdin); 28 | buffer[strcspn(buffer, "\r\n")] = '\0'; 29 | 30 | int write_bytes = write(fd, buffer, strlen(buffer)); 31 | if (write_bytes == -1) 32 | { 33 | perror("write"); 34 | break; 35 | } 36 | } 37 | 38 | close(fd); 39 | return 0; 40 | } -------------------------------------------------------------------------------- /File/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10...3.28) 2 | project(IPCFile) 3 | 4 | set(CMAKE_BUILD_TYPE Debug) 5 | 6 | function(compile_executables target_name file_path) 7 | add_executable(${target_name} ${file_path}) 8 | 9 | target_link_libraries(${target_name} 10 | PRIVATE 11 | pthread 12 | ) 13 | endfunction() 14 | 15 | file(GLOB_RECURSE C_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.c") 16 | file(GLOB_RECURSE CPP_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") 17 | 18 | foreach(file_path ${C_FILES}) 19 | get_filename_component(target_name ${file_path} NAME_WE) 20 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 21 | endforeach() 22 | 23 | foreach(file_path ${CPP_FILES}) 24 | get_filename_component(target_name ${file_path} NAME_WE) 25 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 26 | endforeach() 27 | -------------------------------------------------------------------------------- /File/read_write_shared_file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | const char* shared_file = "/tmp/shared_file.txt"; 13 | const int MAX_BUF = 1024; 14 | 15 | void signal_handler(int signum, siginfo_t* siginfo, void* context) 16 | { 17 | if (signum == SIGINT) 18 | { 19 | printf("Cleaning up shared file...\n"); 20 | if (remove(shared_file) != 0) 21 | { 22 | perror("remove"); 23 | } 24 | exit(0); 25 | } 26 | } 27 | 28 | void lock_file_wait(int fd) 29 | { 30 | struct flock lock; 31 | memset(&lock, 0, sizeof(lock)); 32 | lock.l_type = F_WRLCK; // Write lock 33 | lock.l_whence = SEEK_SET; // Relative to the start of the file 34 | lock.l_start = 0; // Start from the beginning of the file 35 | lock.l_len = 0; // Lock the whole file 36 | lock.l_pid = getpid(); 37 | 38 | if (fcntl(fd, F_SETLKW, &lock) == -1) 39 | { 40 | perror("fcntl"); 41 | } 42 | } 43 | 44 | void unlock_file(int fd) 45 | { 46 | struct flock lock; 47 | memset(&lock, 0, sizeof(lock)); 48 | lock.l_type = F_UNLCK; 49 | lock.l_whence = SEEK_SET; 50 | lock.l_start = 0; 51 | lock.l_len = 0; 52 | lock.l_pid = getpid(); 53 | 54 | if (fcntl(fd, F_SETLK, &lock) == -1) 55 | { 56 | perror("fcntl"); 57 | } 58 | } 59 | 60 | int main(int argc, char** argv) 61 | { 62 | pid_t pid = fork(); 63 | if (pid < 0) 64 | { 65 | perror("fork"); 66 | exit(1); 67 | } 68 | 69 | if (pid == 0) 70 | { 71 | // Child process (producer) 72 | int fd = open(shared_file, O_RDWR | O_CREAT, 0666); 73 | if (fd < 0) 74 | { 75 | perror("CHILD open"); 76 | exit(1); 77 | } 78 | 79 | int next_number = 0; 80 | while (1) 81 | { 82 | lock_file_wait(fd); 83 | lseek(fd, 0, SEEK_END); // Move to the end of the file before writing 84 | char buf[MAX_BUF]; 85 | sprintf(buf, "%d\n", next_number); 86 | write(fd, buf, strlen(buf)); 87 | printf("Write %d\n", next_number); 88 | next_number++; 89 | unlock_file(fd); 90 | 91 | sleep(1); 92 | } 93 | 94 | close(fd); 95 | exit(0); 96 | } 97 | else 98 | { 99 | // Parent process (consumer) 100 | struct sigaction act; 101 | act.sa_sigaction = signal_handler; 102 | act.sa_flags = SA_SIGINFO; 103 | sigaction(SIGINT, &act, NULL); 104 | 105 | int fd = open(shared_file, O_RDWR | O_CREAT, 0666); 106 | if (fd < 0) 107 | { 108 | perror("PARENT open"); 109 | exit(1); 110 | } 111 | 112 | while (1) 113 | { 114 | lock_file_wait(fd); 115 | lseek(fd, 0, SEEK_SET); // Move to the start of the file before reading 116 | 117 | char buf[MAX_BUF]; 118 | int n = read(fd, buf, MAX_BUF); 119 | if (n > 0 && n < MAX_BUF) 120 | { 121 | buf[n] = '\0'; 122 | printf("Read %s", buf); 123 | } 124 | 125 | if (ftruncate(fd, 0) != 0) 126 | { 127 | perror("ftruncate"); 128 | } 129 | 130 | unlock_file(fd); 131 | 132 | sleep(1); 133 | } 134 | 135 | close(fd); 136 | wait(NULL); 137 | } 138 | 139 | return 0; 140 | } -------------------------------------------------------------------------------- /MessageQueue/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10...3.28) 2 | project(IPCMessageQueue) 3 | 4 | set(CMAKE_BUILD_TYPE Debug) 5 | 6 | function(compile_executables target_name file_path) 7 | add_executable(${target_name} ${file_path}) 8 | 9 | target_link_libraries(${target_name} 10 | PRIVATE 11 | pthread 12 | rt 13 | ) 14 | endfunction() 15 | 16 | file(GLOB_RECURSE C_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.c") 17 | file(GLOB_RECURSE CPP_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") 18 | 19 | foreach(file_path ${C_FILES}) 20 | get_filename_component(target_name ${file_path} NAME_WE) 21 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 22 | endforeach() 23 | 24 | foreach(file_path ${CPP_FILES}) 25 | get_filename_component(target_name ${file_path} NAME_WE) 26 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 27 | endforeach() 28 | -------------------------------------------------------------------------------- /MessageQueue/posix_msgq_multiple_types.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define PATH_MSGQ_TIME "/tmp/mq_time" 12 | #define MAX_NUM_MSG 10 13 | #define MAX_MSG_SIZE 1024 14 | 15 | void signal_handler(int signum, siginfo_t *info, void *ptr) 16 | { 17 | if (signum == SIGINT) 18 | { 19 | unlink(PATH_MSGQ_TIME); 20 | exit(0); 21 | } 22 | } 23 | 24 | int main(int argc, char** argv) 25 | { 26 | // create message queues 27 | struct mq_attr attr; 28 | attr.mq_flags = 0; 29 | attr.mq_maxmsg = MAX_NUM_MSG; 30 | attr.mq_msgsize = MAX_MSG_SIZE; 31 | attr.mq_curmsgs = 0; 32 | 33 | mqd_t mq_time = mq_open(PATH_MSGQ_TIME, O_CREAT | O_RDWR, 0666, &attr); 34 | if (mq_time == -1) 35 | { 36 | perror("mq_open PATH_MSGQ_TIME"); 37 | exit(1); 38 | } 39 | 40 | pid_t pid = fork(); 41 | if (pid == -1) 42 | { 43 | perror("fork"); 44 | exit(1); 45 | } 46 | 47 | if (pid == 0) 48 | { 49 | // Child (sender) 50 | struct sigaction act; 51 | memset(&act, 0, sizeof(act)); 52 | act.sa_sigaction = signal_handler; 53 | act.sa_flags = SA_SIGINFO; 54 | if (sigaction(SIGINT, &act, NULL) == -1) 55 | { 56 | perror("sigaction"); 57 | exit(1); 58 | } 59 | 60 | while (1) 61 | { 62 | char time_buf[MAX_MSG_SIZE]; 63 | memset(time_buf, 0, MAX_MSG_SIZE); 64 | sprintf(time_buf, "%s", ctime(NULL)); 65 | if (mq_send(mq_time, time_buf, MAX_MSG_SIZE, 0) == -1) 66 | { 67 | perror("mq_send PATH_MSGQ_TIME"); 68 | } 69 | 70 | sleep(1); 71 | } 72 | } 73 | else 74 | { 75 | // Parent (receiver) 76 | char buffer[MAX_MSG_SIZE]; 77 | unsigned int prio; 78 | while (1) 79 | { 80 | if (mq_receive(mq_time, buffer, MAX_MSG_SIZE, &prio) == -1) 81 | { 82 | perror("mq_receive PATH_MSGQ_TIME"); 83 | } 84 | printf("Received: %s", buffer); 85 | } 86 | 87 | wait(NULL); 88 | } 89 | return 0; 90 | } -------------------------------------------------------------------------------- /MessageQueue/system_v_msgq_multiple_types.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define PROJECT_ID 0x4321 13 | 14 | #define PATH_MSGQ_TIME "/tmp/msgq_time" 15 | #define PATH_MSGQ_ERROR "/tmp/msgq_error" 16 | #define MSGQ_TYPE_TIME 1 17 | #define MSGQ_TYPE_ERROR 2 18 | #define MAX_MSG_SIZE 256 19 | 20 | struct msgbuf_time 21 | { 22 | long mtype; 23 | time_t mtime; 24 | }; 25 | 26 | struct msgbuf_error 27 | { 28 | long mtype; 29 | char mtext[MAX_MSG_SIZE]; 30 | }; 31 | 32 | key_t key_time; 33 | key_t key_error; 34 | 35 | void init_ipc_keys() __attribute__((constructor)); 36 | 37 | void init_ipc_keys() 38 | { 39 | int fd_time = open(PATH_MSGQ_TIME, O_CREAT | O_RDWR, 0666); 40 | if (fd_time == -1) 41 | { 42 | perror("open PATH_MSGQ_TIME"); 43 | exit(1); 44 | } 45 | close(fd_time); 46 | 47 | key_time = ftok(PATH_MSGQ_TIME, PROJECT_ID); 48 | if (key_time == -1) 49 | { 50 | perror("ftok PATH_MSGQ_TIME"); 51 | exit(1); 52 | } 53 | 54 | int fd_error = open(PATH_MSGQ_ERROR, O_CREAT | O_RDWR, 0666); 55 | if (fd_error == -1) 56 | { 57 | perror("open PATH_MSGQ_ERROR"); 58 | exit(1); 59 | } 60 | close(fd_error); 61 | 62 | key_error = ftok(PATH_MSGQ_ERROR, PROJECT_ID); 63 | if (key_error == -1) 64 | { 65 | perror("ftok PATH_MSGQ_ERROR"); 66 | exit(1); 67 | } 68 | } 69 | 70 | void clean_ipc_keys() 71 | { 72 | if (msgctl(msgget(key_time, IPC_CREAT | IPC_EXCL), IPC_RMID, NULL) == 0) 73 | { 74 | printf("Cleanup msgget(key_time, IPC_CREAT | IPC_EXCL)\n"); 75 | } 76 | 77 | if (unlink(PATH_MSGQ_TIME) == 0) 78 | { 79 | printf("Cleanup %s\n", PATH_MSGQ_TIME); 80 | } 81 | 82 | if (msgctl(msgget(key_error, IPC_CREAT | IPC_EXCL), IPC_RMID, NULL) == 0) 83 | { 84 | printf("Cleanup msgget(key_error, IPC_CREAT | IPC_EXCL)\n"); 85 | } 86 | 87 | if (unlink(PATH_MSGQ_ERROR) == 0) 88 | { 89 | printf("Cleanup %s\n", PATH_MSGQ_ERROR); 90 | } 91 | } 92 | 93 | void signal_handler(int signum, siginfo_t *info, void *ptr) 94 | { 95 | if (signum == SIGINT) 96 | { 97 | clean_ipc_keys(); 98 | exit(0); 99 | } 100 | } 101 | 102 | void* thread_time_func(void* arg) 103 | { 104 | int msgq_time_id = msgget(key_time, IPC_CREAT | 0666); 105 | if (msgq_time_id == -1) 106 | { 107 | perror("msgget key_time"); 108 | return NULL; 109 | } 110 | 111 | struct msgbuf_time msg_time; 112 | while (1) 113 | { 114 | if (msgrcv(msgq_time_id, &msg_time, sizeof(msg_time.mtime), MSGQ_TYPE_TIME, 0) == -1) 115 | { 116 | perror("msgrcv key_time"); 117 | exit(1); 118 | } 119 | 120 | printf("Received time: %s\n", ctime(&msg_time.mtime)); 121 | } 122 | 123 | return NULL; 124 | } 125 | 126 | void* thread_error_func(void* arg) 127 | { 128 | int msgq_error_id = msgget(key_error, IPC_CREAT | 0666); 129 | if (msgq_error_id == -1) 130 | { 131 | perror("msgget key_error"); 132 | return NULL; 133 | } 134 | 135 | struct msgbuf_error msg_error; 136 | while (1) 137 | { 138 | if (msgrcv(msgq_error_id, &msg_error, sizeof(msg_error.mtext), MSGQ_TYPE_ERROR, 0) == -1) 139 | { 140 | perror("msgrcv key_error"); 141 | exit(1); 142 | } 143 | 144 | printf("Received error: %s\n", msg_error.mtext); 145 | } 146 | 147 | return NULL; 148 | } 149 | 150 | int main(int argc, char** argv) 151 | { 152 | int msgq_time_id = msgget(key_time, IPC_CREAT | 0666); 153 | int msgq_error_id = msgget(key_error, IPC_CREAT | 0666); 154 | 155 | pid_t pid = fork(); 156 | if (pid == -1) 157 | { 158 | perror("fork"); 159 | exit(1); 160 | } 161 | 162 | if (pid == 0) 163 | { 164 | // Child (sender) 165 | struct sigaction act; 166 | memset(&act, 0, sizeof(act)); 167 | act.sa_sigaction = signal_handler; 168 | act.sa_flags = SA_SIGINFO; 169 | if (sigaction(SIGINT, &act, NULL) == -1) 170 | { 171 | perror("sigaction"); 172 | exit(1); 173 | } 174 | 175 | int count = 0; 176 | while (1) 177 | { 178 | // send time to message queue 179 | struct msgbuf_time msg_time; 180 | msg_time.mtype = MSGQ_TYPE_TIME; 181 | msg_time.mtime = time(NULL); 182 | if (msgsnd(msgq_time_id, &msg_time, sizeof(msg_time.mtime), 0) == -1) 183 | { 184 | perror("msgsnd key_time"); 185 | } 186 | 187 | // send error to message queue 188 | if (count % 5 == 0) 189 | { 190 | struct msgbuf_error msg_error; 191 | msg_error.mtype = MSGQ_TYPE_ERROR; 192 | memset(msg_error.mtext, 0, MAX_MSG_SIZE); 193 | snprintf(msg_error.mtext, MAX_MSG_SIZE, "Error: %d", rand()); 194 | if (msgsnd(msgq_error_id, &msg_error, sizeof(msg_error.mtext), 0) == -1) 195 | { 196 | perror("msgsnd key_error"); 197 | } 198 | } 199 | 200 | count++; 201 | sleep(1); 202 | } 203 | } 204 | else 205 | { 206 | // Parent (receiver) 207 | pthread_t thread_time; 208 | pthread_t thread_error; 209 | 210 | if (pthread_create(&thread_time, NULL, thread_time_func, NULL) != 0) 211 | { 212 | perror("pthread_create thread_time"); 213 | } 214 | 215 | if (pthread_create(&thread_error, NULL, thread_error_func, NULL) != 0) 216 | { 217 | perror("pthread_create thread_error"); 218 | } 219 | 220 | pthread_detach(thread_time); 221 | pthread_detach(thread_error); 222 | 223 | wait(NULL); 224 | } 225 | return 0; 226 | } -------------------------------------------------------------------------------- /MessageQueue/system_v_msgq_random_numbers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define PROJECT_ID 0x1234 12 | 13 | #define PATH_MSGQ_RANDOM "/tmp/msgq_random" 14 | 15 | struct random_msgbuf 16 | { 17 | long mtype; 18 | long mvalue; 19 | }; 20 | 21 | key_t key_random; 22 | 23 | void init_ipc_keys() __attribute__((constructor)); 24 | 25 | void init_ipc_keys() 26 | { 27 | int fd_random = open(PATH_MSGQ_RANDOM, O_CREAT | O_RDWR, 0666); 28 | if (fd_random == -1) 29 | { 30 | perror("open PATH_MSGQ_RANDOM"); 31 | exit(1); 32 | } 33 | close(fd_random); 34 | 35 | key_random = ftok(PATH_MSGQ_RANDOM, PROJECT_ID); 36 | if (key_random == -1) 37 | { 38 | perror("ftok PATH_MSGQ_RANDOM"); 39 | exit(1); 40 | } 41 | } 42 | 43 | void clean_ipc_keys() 44 | { 45 | if (msgctl(msgget(key_random, IPC_CREAT | IPC_EXCL), IPC_RMID, NULL) == 0) 46 | { 47 | printf("Cleanup msgget(key_random, IPC_CREAT | IPC_EXCL)\n"); 48 | } 49 | 50 | if (unlink(PATH_MSGQ_RANDOM) == 0) 51 | { 52 | printf("Cleanup %s\n", PATH_MSGQ_RANDOM); 53 | } 54 | } 55 | 56 | void signal_handler(int signum, siginfo_t *info, void *ptr) 57 | { 58 | if (signum == SIGINT) 59 | { 60 | clean_ipc_keys(); 61 | exit(0); 62 | } 63 | } 64 | 65 | int main(int argc, char** argv) 66 | { 67 | int msgq_id = msgget(key_random, IPC_CREAT | 0666); 68 | if (msgq_id == -1) 69 | { 70 | perror("msgget"); 71 | exit(1); 72 | } 73 | 74 | pid_t pid = fork(); 75 | if (pid == -1) 76 | { 77 | perror("fork"); 78 | exit(1); 79 | } 80 | 81 | if (pid == 0) 82 | { 83 | // Child (sender) 84 | printf("CHILD: msgq_id = %d\n", msgq_id); 85 | 86 | while (1) 87 | { 88 | struct random_msgbuf msgbuf; 89 | msgbuf.mtype = 1; 90 | msgbuf.mvalue = random(); 91 | if (msgsnd(msgq_id, &msgbuf, sizeof(struct random_msgbuf) - sizeof(long), 0) == -1) 92 | { 93 | perror("msgsnd"); 94 | exit(1); 95 | } 96 | printf("CHILD: Sent %ld\n", msgbuf.mvalue); 97 | 98 | struct msqid_ds buf; 99 | if (msgctl(msgq_id, IPC_STAT, &buf) == -1) 100 | { 101 | perror("msgctl IPC_STAT"); 102 | exit(1); 103 | } 104 | printf("CHILD: msg_qnum = %ld\n", buf.msg_qnum); 105 | 106 | sleep(1); 107 | } 108 | } 109 | else 110 | { 111 | // Parent (receiver) 112 | printf("PARENT: msgq_id = %d\n", msgq_id); 113 | 114 | struct sigaction act; 115 | memset(&act, 0, sizeof(act)); 116 | act.sa_sigaction = signal_handler; 117 | act.sa_flags = SA_SIGINFO; 118 | if (sigaction(SIGINT, &act, NULL) == -1) 119 | { 120 | perror("sigaction"); 121 | exit(1); 122 | } 123 | 124 | while (1) 125 | { 126 | struct random_msgbuf msgbuf; 127 | if (msgrcv(msgq_id, &msgbuf, sizeof(struct random_msgbuf) - sizeof(long), 0, 0) == -1) 128 | { 129 | perror("msgrcv"); 130 | exit(1); 131 | } 132 | printf("PARENT: Received %ld\n", msgbuf.mvalue); 133 | 134 | sleep(1); 135 | } 136 | 137 | wait(NULL); 138 | } 139 | return 0; 140 | } -------------------------------------------------------------------------------- /Pipe/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10...3.28) 2 | project(IPCPipe) 3 | 4 | set(CMAKE_BUILD_TYPE Debug) 5 | 6 | function(compile_executables target_name file_path) 7 | add_executable(${target_name} ${file_path}) 8 | 9 | target_link_libraries(${target_name} 10 | PRIVATE 11 | pthread 12 | ) 13 | endfunction() 14 | 15 | file(GLOB_RECURSE C_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.c") 16 | file(GLOB_RECURSE CPP_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") 17 | 18 | foreach(file_path ${C_FILES}) 19 | get_filename_component(target_name ${file_path} NAME_WE) 20 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 21 | endforeach() 22 | 23 | foreach(file_path ${CPP_FILES}) 24 | get_filename_component(target_name ${file_path} NAME_WE) 25 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 26 | endforeach() 27 | -------------------------------------------------------------------------------- /Pipe/pipe_ls_wc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() 9 | { 10 | int pipefd[2]; 11 | if (pipe(pipefd) == -1) 12 | { 13 | perror("pipe"); 14 | exit(1); 15 | } 16 | 17 | pid_t pid = fork(); 18 | if (pid == -1) 19 | { 20 | perror("fork"); 21 | exit(1); 22 | } 23 | 24 | if (pid == 0) 25 | { 26 | // Child process 27 | close(pipefd[0]); 28 | dup2(pipefd[1], STDOUT_FILENO); // Redirect stdout to pipefd[1] 29 | close(pipefd[1]); 30 | execlp("ls", "ls", NULL); 31 | } 32 | else 33 | { 34 | // Parent process 35 | close(pipefd[1]); 36 | dup2(pipefd[0], STDIN_FILENO); // Redirect stdin to pipefd[0] 37 | close(pipefd[0]); 38 | execlp("wc", "wc", "-l", NULL); 39 | } 40 | 41 | return 0; 42 | } -------------------------------------------------------------------------------- /Pipe/pipe_parent_and_child.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char** argv) 9 | { 10 | int pipefd[2]; 11 | if (pipe(pipefd) == -1) 12 | { 13 | perror("pipe"); 14 | exit(1); 15 | } 16 | 17 | pid_t pid = fork(); 18 | if (pid == -1) 19 | { 20 | perror("fork"); 21 | exit(1); 22 | } 23 | 24 | if (pid == 0) 25 | { 26 | // Child process 27 | close(pipefd[0]); 28 | sleep(3); 29 | printf("CHILD Write file descriptor: %d\n", pipefd[1]); 30 | write(pipefd[1], "test", 5); 31 | close(pipefd[1]); 32 | exit(0); 33 | } 34 | else 35 | { 36 | // Parent process 37 | close(pipefd[1]); 38 | 39 | if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) == -1) 40 | { 41 | perror("fcntl"); 42 | exit(1); 43 | } 44 | 45 | char buf[5]; 46 | while (1) 47 | { 48 | int ret = read(pipefd[0], buf, 5); 49 | if (ret == -1) 50 | { 51 | if (errno == EAGAIN || errno == EWOULDBLOCK) 52 | { 53 | perror("PARENT Read"); 54 | sleep(1); 55 | } 56 | else 57 | { 58 | perror("read"); 59 | exit(1); 60 | } 61 | } 62 | else 63 | { 64 | printf("PARENT Read: %s\n", buf); 65 | break; 66 | } 67 | } 68 | 69 | close(pipefd[0]); 70 | } 71 | 72 | return 0; 73 | } -------------------------------------------------------------------------------- /Pipe/pipe_same_process.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char** argv) 7 | { 8 | int pfds[2]; 9 | if (pipe(pfds) == -1) 10 | { 11 | perror("pipe"); 12 | exit(1); 13 | } 14 | 15 | printf("Write file descriptor: %d\n", pfds[1]); 16 | write(pfds[1], "test", 5); 17 | 18 | printf("Read file descriptor: %d\n", pfds[0]); 19 | char buf[5]; 20 | read(pfds[0], buf, 5); 21 | printf("Read: %s\n", buf); 22 | 23 | return 0; 24 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | - [Introduction](#introduction) 2 | - [File Locking](#file-locking) 3 | - [Pipe (Anonymous Pipe)](#pipe-anonymous-pipe) 4 | - [FIFO (Named Pipe)](#fifo-named-pipe) 5 | - [Signal](#signal) 6 | - [Semaphore](#semaphore) 7 | - [Message Queue](#message-queue) 8 | - [Shared Memory](#shared-memory) 9 | - [Socket](#socket) 10 | - [References](#references) 11 | 12 | # Introduction 13 | 14 | The Linux IPC feature provides the methods for multiple processes to exchange data and signals. 15 | 16 | This guideline will introduce to you various IPC techniques, including File Locking, Pipe, Signal, Semaphore, Message Queue, Shared Memory, and Socket. 17 | 18 | Each technique has its unique use cases and advantages. 19 | 20 | ## File Locking 21 | 22 | File Locking is a mechanism to control access to a file by multiple processes, ensure that only one process can modify the file at a time, prevent data corruption. 23 | 24 | This code below demonstrates a simple producer-consumer model using file locking for IPC in Linux: 25 | 26 | - The producer (child process) writes numbers to a shared file, while the consumer (parent process) reads and clears the file. 27 | - File locking ensures that only one process accesses the file at a time, preventing race conditions. 28 | 29 | **Function to lock file** 30 | 31 | ``` 32 | void lock_file_wait(int fd) 33 | { 34 | struct flock lock; 35 | memset(&lock, 0, sizeof(lock)); 36 | lock.l_type = F_WRLCK; // Write lock 37 | lock.l_whence = SEEK_SET; // Relative to the start of the file 38 | lock.l_start = 0; // Start from the beginning of the file 39 | lock.l_len = 0; // Lock the whole file 40 | lock.l_pid = getpid(); 41 | 42 | if (fcntl(fd, F_SETLKW, &lock) == -1) 43 | { 44 | perror("fcntl"); 45 | } 46 | } 47 | ``` 48 | 49 | ```struct flock lock```: Defines the lock. 50 | 51 | ```fcntl(fd, F_SETLKW, &lock)```: Sets the lock, waiting if necessary. 52 | 53 | **Function to unlock file** 54 | 55 | ``` 56 | void unlock_file(int fd) 57 | { 58 | struct flock lock; 59 | memset(&lock, 0, sizeof(lock)); 60 | lock.l_type = F_UNLCK; 61 | lock.l_whence = SEEK_SET; 62 | lock.l_start = 0; 63 | lock.l_len = 0; 64 | lock.l_pid = getpid(); 65 | 66 | if (fcntl(fd, F_SETLK, &lock) == -1) 67 | { 68 | perror("fcntl"); 69 | } 70 | } 71 | ``` 72 | 73 | ```lock.l_type = F_UNLCK```: Specifies an unlock operation. 74 | 75 | ```fcntl(fd, F_SETLK, &lock)```: Sets the unlock operation. 76 | 77 | **Full example source code** [HERE](https://github.com/nguyenchiemminhvu/LinuxIPC/tree/main/File). 78 | 79 | ## Pipe (Anonymous Pipe) 80 | 81 | A pipe is an unidirectional communication channel that allows data to flow from one process to another. 82 | 83 | It is commonly used for simple communication between parent and child processes. 84 | 85 | Pipes are easy to use but limited to communication between related processes. 86 | 87 | ``` 88 | #include 89 | #include 90 | #include 91 | #include 92 | 93 | int main(int argc, char** argv) 94 | { 95 | int pfds[2]; 96 | if (pipe(pfds) == -1) 97 | { 98 | perror("pipe"); 99 | exit(1); 100 | } 101 | 102 | printf("Write file descriptor: %d\n", pfds[1]); 103 | write(pfds[1], "test", 5); 104 | 105 | printf("Read file descriptor: %d\n", pfds[0]); 106 | char buf[5]; 107 | read(pfds[0], buf, 5); 108 | printf("Read: %s\n", buf); 109 | 110 | return 0; 111 | } 112 | ``` 113 | 114 | **Find more demonstration** [HERE](https://github.com/nguyenchiemminhvu/LinuxIPC/tree/main/Pipe). 115 | 116 | ## FIFO (Named Pipe) 117 | 118 | Unlike regular pipes, which are anonymous and only exist as long as the processes are running, FIFOs are given a name in the file system and can be accessed by unrelated processes. 119 | 120 | **Full example source code** [HERE](https://github.com/nguyenchiemminhvu/LinuxIPC/tree/main/FIFO). 121 | 122 | ## Signal 123 | 124 | Signals are a form of IPC used to notify a process that a specific event has occurred. They are used for handling asynchronous events like interrupts. Common signals include SIGINT (interrupt), SIGKILL (terminate), and SIGALRM (alarm). 125 | 126 | I have prepared a sample code that demonstrates Signal technique. 127 | 128 | **Full example source code** [HERE](https://github.com/nguyenchiemminhvu/LinuxIPC/tree/main/Signal). 129 | 130 | The program manages a set of processes, monitor their heartbeats, and restart them if they become unresponsive. 131 | 132 | ## Semaphore 133 | 134 | Semaphores are synchronization tools used to control access to shared resources. They can be used to signal between processes and ensure that only a certain number of processes can access a resource at the same time. 135 | 136 | Set of System V semaphore APIs on Unix-like operating systems: 137 | 138 | [semget()](https://man7.org/linux/man-pages/man3/semget.3p.html): Creates a new semaphore set or accesses an existing one. 139 | 140 | [semop()](https://man7.org/linux/man-pages/man3/semop.3p.html): Performs operations on semaphores, such as incrementing or decrementing their values. 141 | 142 | [semctl()](https://man7.org/linux/man-pages/man3/semctl.3p.html): Performs various control operations on semaphores, such as setting values or removing the semaphore set. 143 | 144 | **Find demonstration source code** [HERE](https://github.com/nguyenchiemminhvu/LinuxIPC/tree/main/Semaphore). 145 | 146 | ## Message Queue 147 | 148 | Message queues allow processes to exchange messages in a structured way. Each message is placed in a queue and can be read by another process. This method is useful for complex communication patterns and ensures that messages are delivered in order. 149 | 150 | Set of System V message queue APIs on Unix-like operating systems: 151 | 152 | [msgget()](https://man7.org/linux/man-pages/man3/msgget.3p.html): Returns an identifier for the queue. This identifier is used for subsequent operations. 153 | 154 | [msgsnd()](https://man7.org/linux/man-pages/man3/msgsnd.3p.html): Send a message to the queue. 155 | 156 | [msgrcv()](https://man7.org/linux/man-pages/man3/msgrcv.3p.html): Receive a message from the queue. 157 | 158 | [msgctl()](https://man7.org/linux/man-pages/man3/msgctl.3p.html): Perform various control operations on the message queue, such as querying its status or removing it. 159 | 160 | **Find demonstration source code** [HERE](https://github.com/nguyenchiemminhvu/LinuxIPC/tree/main/MessageQueue). 161 | 162 | ## Shared Memory 163 | 164 | Shared memory is a method where multiple processes can access the same memory space. It is the fastest form of IPC because it avoids the overhead of copying data between processes. However, it requires careful synchronization to prevent data corruption. 165 | 166 | ```Creation and Access```: Shared memory segments are created using the [shmget()](https://man7.org/linux/man-pages/man3/shmget.3p.html) system call, which returns an identifier for the segment. This identifier is used for subsequent operations. 167 | 168 | ```Attaching to Memory```: Processes attach to the shared memory segment using the [shmat()](https://man7.org/linux/man-pages/man3/shmat.3p.html) system call, which returns a pointer to the shared memory. This pointer can be used to read from and write to the shared memory. 169 | 170 | ```Detaching from Memory```: When a process no longer needs access to the shared memory, it can detach using the [shmdt()](https://man7.org/linux/man-pages/man3/shmdt.3p.html) system call. 171 | 172 | ```Control Operations```: The [shmctl()](https://man7.org/linux/man-pages/man3/shmctl.3p.html) system call is used to perform various control operations on the shared memory segment, such as querying its status, changing its permissions, or removing it. 173 | 174 | **Find demonstration source code** [HERE](https://github.com/nguyenchiemminhvu/LinuxIPC/tree/main/SharedMemory). 175 | 176 | ## Socket 177 | 178 | Sockets provide a way for processes to communicate over a network. They can be used for communication between processes on the same machine or different machines. 179 | 180 | Using in IPC context, Unix Sockets is powerful mechanism for communication between processes on the same machine. Unix Sockets don't need complex IP and port setup, they use file system paths to establish connections. 181 | 182 | **Full Unix-socket client-server example source code** [HERE](https://github.com/nguyenchiemminhvu/LinuxIPC/tree/main/Socket). 183 | 184 | # References 185 | 186 | [https://github.com/nguyenchiemminhvu/LinuxIPC/tree/main](https://github.com/nguyenchiemminhvu/LinuxIPC/tree/main) 187 | 188 | [https://beej.us/guide/bgipc/html/](https://beej.us/guide/bgipc/html/) 189 | 190 | [https://opensource.com/article/19/4/interprocess-communication-linux-networking](https://opensource.com/article/19/4/interprocess-communication-linux-networking) 191 | 192 | [https://opensource.com/article/19/4/interprocess-communication-linux-storage](https://opensource.com/article/19/4/interprocess-communication-linux-storage) 193 | 194 | [https://opensource.com/article/19/4/interprocess-communication-linux-channels](https://opensource.com/article/19/4/interprocess-communication-linux-channels) 195 | 196 | [https://www.linkedin.com/pulse/brief-linux-ipc-amit-nadiger/](https://www.linkedin.com/pulse/brief-linux-ipc-amit-nadiger/) 197 | -------------------------------------------------------------------------------- /Semaphore/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10...3.28) 2 | project(IPCSemaphore) 3 | 4 | set(CMAKE_BUILD_TYPE Debug) 5 | 6 | function(compile_executables target_name file_path) 7 | add_executable(${target_name} ${file_path}) 8 | 9 | target_link_libraries(${target_name} 10 | PRIVATE 11 | pthread 12 | rt 13 | ) 14 | endfunction() 15 | 16 | file(GLOB_RECURSE C_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.c") 17 | file(GLOB_RECURSE CPP_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") 18 | 19 | foreach(file_path ${C_FILES}) 20 | get_filename_component(target_name ${file_path} NAME_WE) 21 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 22 | endforeach() 23 | 24 | foreach(file_path ${CPP_FILES}) 25 | get_filename_component(target_name ${file_path} NAME_WE) 26 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 27 | endforeach() 28 | -------------------------------------------------------------------------------- /Semaphore/posix_semaphore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define SEM_PATH "/posix_semaphore" 13 | #define SEM_MODE 0666 14 | 15 | void signal_handler(int signum, siginfo_t *info, void *ptr) 16 | { 17 | if (signum == SIGINT) 18 | { 19 | sem_close(sem_open(SEM_PATH, O_CREAT, SEM_MODE, 0)); 20 | sem_unlink(SEM_PATH); 21 | remove(SEM_PATH); 22 | printf("Semaphore closed and unlinked\n"); 23 | exit(0); 24 | } 25 | } 26 | 27 | void* producing_thread(void* arg) 28 | { 29 | sem_t* p_sem = (sem_t*)arg; 30 | int count = 0; 31 | while (1) 32 | { 33 | printf("Made a product unit\n"); 34 | count++; 35 | 36 | if (count == 5) 37 | { 38 | if (sem_post(p_sem) == -1) 39 | { 40 | perror("sem_post"); 41 | } 42 | count = 0; 43 | } 44 | sleep(1); 45 | } 46 | } 47 | 48 | int main(int argc, char** argv) 49 | { 50 | sem_t* p_sem = sem_open(SEM_PATH, O_CREAT | O_EXCL, SEM_MODE, 0); 51 | if (p_sem == SEM_FAILED) 52 | { 53 | if (errno == EEXIST) 54 | { 55 | p_sem = sem_open(SEM_PATH, 0, SEM_MODE, 0); 56 | } 57 | else 58 | { 59 | perror("sem_open"); 60 | exit(1); 61 | } 62 | } 63 | 64 | pid_t pid = fork(); 65 | if (pid < 0) 66 | { 67 | perror("fork"); 68 | exit(1); 69 | } 70 | 71 | if (pid == 0) 72 | { 73 | // Child process 74 | pthread_t tid[3]; 75 | for (int i = 0; i < 3; i++) 76 | { 77 | pthread_create(&tid[i], NULL, producing_thread, p_sem); 78 | pthread_detach(tid[i]); 79 | } 80 | 81 | while (1) 82 | { 83 | pause(); 84 | } 85 | } 86 | else 87 | { 88 | // Parent process 89 | struct sigaction act; 90 | act.sa_sigaction = signal_handler; 91 | act.sa_flags = SA_SIGINFO; 92 | sigaction(SIGINT, &act, NULL); 93 | 94 | while (1) 95 | { 96 | if (sem_wait(p_sem) == -1) 97 | { 98 | perror("sem_wait"); 99 | } 100 | 101 | printf("PARENT consume a product unit\n"); 102 | } 103 | 104 | wait(NULL); 105 | } 106 | return 0; 107 | } -------------------------------------------------------------------------------- /Semaphore/system_v_multiple_semaphores.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define PROJECT_ID 0x87654321 14 | #define SEM_SET_SIZE 2 15 | #define SEM_FLAGS 0666 16 | #define SEM_MODE (IPC_CREAT | IPC_EXCL | SEM_FLAGS) 17 | 18 | #define SEM_PATH "/tmp/semaphores" 19 | 20 | key_t sem_key; 21 | 22 | void init_semaphore_keys() __attribute__((constructor)); 23 | 24 | void init_semaphore_keys() 25 | { 26 | int fd = open(SEM_PATH, O_CREAT | O_RDWR, 0666); 27 | if (fd == -1) 28 | { 29 | perror("open SEM_PATH"); 30 | exit(1); 31 | } 32 | close(fd); 33 | 34 | sem_key = ftok(SEM_PATH, PROJECT_ID); 35 | if (sem_key == -1) 36 | { 37 | perror("ftok SEM_PATH"); 38 | exit(1); 39 | } 40 | } 41 | 42 | void signal_handler(int signum, siginfo_t *info, void *ptr) 43 | { 44 | if (signum == SIGINT) 45 | { 46 | if (semctl(semget(sem_key, 1, SEM_FLAGS), 0, IPC_RMID) == 0) 47 | { 48 | printf("Cleanup semget(sem_key, 1, SEM_FLAGS)\n"); 49 | } 50 | 51 | if (unlink(SEM_PATH) == 0) 52 | { 53 | printf("Cleanup %s\n", SEM_PATH); 54 | } 55 | 56 | exit(0); 57 | } 58 | } 59 | 60 | void sem_wait_for_resourses(int sem_id, int set_idx, int n) 61 | { 62 | struct sembuf sembuf = { 63 | .sem_num = set_idx, 64 | .sem_op = -n, 65 | .sem_flg = 0, 66 | }; 67 | if (semop(sem_id, &sembuf, 1) == -1) 68 | { 69 | perror("semop request"); 70 | exit(1); 71 | } 72 | } 73 | 74 | void sem_release_resourses(int sem_id, int set_idx, int n) 75 | { 76 | struct sembuf sembuf = { 77 | .sem_num = set_idx, 78 | .sem_op = n, 79 | .sem_flg = 0, 80 | }; 81 | if (semop(sem_id, &sembuf, 1) == -1) 82 | { 83 | perror("semop release"); 84 | exit(1); 85 | } 86 | } 87 | 88 | int main(int argc, char** argv) 89 | { 90 | int sem_id = semget(sem_key, SEM_SET_SIZE, SEM_MODE); 91 | if (sem_id == -1) 92 | { 93 | perror("semget"); 94 | exit(1); 95 | } 96 | 97 | if (semctl(sem_id, 0, SETALL, (unsigned short[]){0, 0}) == -1) 98 | { 99 | perror("semctl SETALL"); 100 | exit(1); 101 | } 102 | 103 | pid_t pid = fork(); 104 | if (pid < 0) 105 | { 106 | perror("fork"); 107 | exit(1); 108 | } 109 | 110 | if (pid == 0) 111 | { 112 | // Child process (producer) 113 | while (1) 114 | { 115 | printf("CHILD produce 1 product ID 0\n"); 116 | sem_release_resourses(sem_id, 0, 1); 117 | 118 | printf("CHILD produce 1 product ID 1\n"); 119 | sem_release_resourses(sem_id, 1, 1); 120 | 121 | sleep(1); 122 | } 123 | } 124 | else 125 | { 126 | // Parent process (consumer) 127 | struct sigaction act; 128 | memset(&act, 0, sizeof(act)); 129 | act.sa_sigaction = signal_handler; 130 | act.sa_flags = SA_SIGINFO; 131 | if (sigaction(SIGINT, &act, NULL) == -1) 132 | { 133 | perror("sigaction"); 134 | exit(1); 135 | } 136 | 137 | int count_packages = 0; 138 | while (1) 139 | { 140 | sem_wait_for_resourses(sem_id, 0, 2); 141 | sem_wait_for_resourses(sem_id, 1, 3); 142 | printf("PARENT make a package with 2 products ID 0 and 3 products ID 1\n"); 143 | count_packages++; 144 | printf("PARENT count_packages = %d\n", count_packages); 145 | 146 | unsigned short sem_values[SEM_SET_SIZE]; 147 | if (semctl(sem_id, 0, GETALL, sem_values) == 0) 148 | { 149 | for (int i = 0; i < SEM_SET_SIZE; i++) 150 | { 151 | printf("Number of product ID [%d] = %d\n", i, sem_values[i]); 152 | } 153 | } 154 | } 155 | 156 | wait(NULL); 157 | } 158 | return 0; 159 | } -------------------------------------------------------------------------------- /Semaphore/system_v_semaphore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define PROJECT_ID 0x12345678 14 | #define SEM_FLAGS 0666 15 | #define SEM_MODE (IPC_CREAT | IPC_EXCL | SEM_FLAGS) 16 | 17 | #define SEM_PATH "/tmp/semaphore" 18 | 19 | key_t sem_key; 20 | 21 | void init_semaphore_keys() __attribute__((constructor)); 22 | 23 | void init_semaphore_keys() 24 | { 25 | int fd = open(SEM_PATH, O_CREAT | O_RDWR, 0666); 26 | if (fd == -1) 27 | { 28 | perror("open SEM_PATH"); 29 | exit(1); 30 | } 31 | close(fd); 32 | 33 | sem_key = ftok(SEM_PATH, PROJECT_ID); 34 | if (sem_key == -1) 35 | { 36 | perror("ftok SEM_PATH"); 37 | exit(1); 38 | } 39 | } 40 | 41 | void signal_handler(int signum, siginfo_t *info, void *ptr) 42 | { 43 | if (signum == SIGINT) 44 | { 45 | if (semctl(semget(sem_key, 1, SEM_FLAGS), 0, IPC_RMID) == 0) 46 | { 47 | printf("Cleanup semget(sem_key, 1, SEM_FLAGS)\n"); 48 | } 49 | 50 | if (unlink(SEM_PATH) == 0) 51 | { 52 | printf("Cleanup %s\n", SEM_PATH); 53 | } 54 | 55 | exit(0); 56 | } 57 | } 58 | 59 | void sem_wait_for_resourses(int sem_id, int n) 60 | { 61 | struct sembuf sembuf = { 62 | .sem_num = 0, 63 | .sem_op = -n, 64 | .sem_flg = 0, 65 | }; 66 | if (semop(sem_id, &sembuf, 1) == -1) 67 | { 68 | perror("semop request"); 69 | exit(1); 70 | } 71 | } 72 | 73 | void sem_release_resourses(int sem_id, int n) 74 | { 75 | struct sembuf sembuf = { 76 | .sem_num = 0, 77 | .sem_op = n, 78 | .sem_flg = 0, 79 | }; 80 | if (semop(sem_id, &sembuf, 1) == -1) 81 | { 82 | perror("semop release"); 83 | exit(1); 84 | } 85 | } 86 | 87 | int main(int argc, char** argv) 88 | { 89 | int sem_id = semget(sem_key, 1, SEM_MODE); 90 | if (sem_id == -1) 91 | { 92 | perror("semget"); 93 | exit(1); 94 | } 95 | 96 | // Set the number of semaphore resources to 0 97 | if (semctl(sem_id, 0, SETVAL, 0) == -1) 98 | { 99 | perror("semctl SETVAL"); 100 | exit(1); 101 | } 102 | 103 | pid_t pid = fork(); 104 | if (pid < 0) 105 | { 106 | perror("fork"); 107 | exit(1); 108 | } 109 | 110 | if (pid == 0) 111 | { 112 | // Child process (producer) 113 | while (1) 114 | { 115 | printf("CHILD produce 1 product\n"); 116 | sem_release_resourses(sem_id, 1); 117 | sleep(1); 118 | } 119 | } 120 | else 121 | { 122 | // Parent process (consumer) 123 | struct sigaction act; 124 | memset(&act, 0, sizeof(act)); 125 | act.sa_sigaction = signal_handler; 126 | act.sa_flags = SA_SIGINFO; 127 | if (sigaction(SIGINT, &act, NULL) == -1) 128 | { 129 | perror("sigaction"); 130 | exit(1); 131 | } 132 | 133 | while (1) 134 | { 135 | sem_wait_for_resourses(sem_id, 5); 136 | printf("PARENT make a package with 5 products\n"); 137 | } 138 | 139 | wait(NULL); 140 | } 141 | return 0; 142 | } -------------------------------------------------------------------------------- /SharedMemory/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10...3.28) 2 | project(IPCSharedMemory) 3 | 4 | set(CMAKE_BUILD_TYPE Debug) 5 | 6 | function(compile_executables target_name file_path) 7 | add_executable(${target_name} ${file_path}) 8 | 9 | target_link_libraries(${target_name} 10 | PRIVATE 11 | pthread 12 | ) 13 | endfunction() 14 | 15 | file(GLOB_RECURSE C_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.c") 16 | 17 | foreach(file_path ${C_FILES}) 18 | get_filename_component(target_name ${file_path} NAME_WE) 19 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 20 | endforeach() 21 | -------------------------------------------------------------------------------- /SharedMemory/posix_memory_mapped_file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define SHM_PATH "/tmp/shm_file" 13 | #define SHM_SIZE 64 14 | #define SHM_MODE 0666 15 | 16 | int common_idx = 0; 17 | 18 | void signal_handler(int signum, siginfo_t* info, void* ptr) 19 | { 20 | if (signum == SIGINT) 21 | { 22 | shm_unlink(SHM_PATH); 23 | printf("Cleanup %s\n", SHM_PATH); 24 | exit(0); 25 | } 26 | } 27 | 28 | int main() 29 | { 30 | int shm_fd = open(SHM_PATH, O_CREAT | O_RDWR, SHM_MODE); 31 | if (shm_fd == -1) 32 | { 33 | perror("open fd"); 34 | exit(1); 35 | } 36 | 37 | if (ftruncate(shm_fd, SHM_SIZE) == -1) 38 | { 39 | perror("ftruncate"); 40 | close(shm_fd); 41 | exit(1); 42 | } 43 | 44 | pid_t pid = fork(); 45 | if (pid == -1) 46 | { 47 | perror("fork"); 48 | exit(1); 49 | } 50 | 51 | if (pid == 0) 52 | { 53 | // Child process 54 | char* shm_ptr = (char*)mmap(NULL, SHM_SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0); 55 | if (shm_ptr == MAP_FAILED) 56 | { 57 | perror("mmap"); 58 | exit(1); 59 | } 60 | 61 | while (common_idx < SHM_SIZE / 2) 62 | { 63 | char ch = 'a' + (common_idx % 26); 64 | shm_ptr[common_idx] = ch; 65 | printf("CHILD edited: %s\n", shm_ptr); 66 | common_idx++; 67 | usleep(100000); 68 | } 69 | 70 | munmap(shm_ptr, SHM_SIZE); 71 | } 72 | else 73 | { 74 | // Parent process 75 | struct sigaction act; 76 | act.sa_sigaction = signal_handler; 77 | act.sa_flags = SA_SIGINFO; 78 | sigaction(SIGINT, &act, NULL); 79 | 80 | char* shm_ptr = (char*)mmap(NULL, SHM_SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0); 81 | if (shm_ptr == MAP_FAILED) 82 | { 83 | perror("mmap"); 84 | exit(1); 85 | } 86 | 87 | memset(shm_ptr, 0, SHM_SIZE); 88 | 89 | common_idx = SHM_SIZE / 2; 90 | while (common_idx < SHM_SIZE - 1) 91 | { 92 | char ch = 'A' + (common_idx % 26); 93 | shm_ptr[common_idx] = ch; 94 | printf("PARENT edited: %s\n", shm_ptr + SHM_SIZE / 2); 95 | common_idx++; 96 | usleep(100000); 97 | } 98 | 99 | munmap(shm_ptr, SHM_SIZE); 100 | 101 | wait(NULL); 102 | 103 | close(shm_fd); 104 | unlink(SHM_PATH); 105 | } 106 | 107 | return 0; 108 | } -------------------------------------------------------------------------------- /SharedMemory/posix_shared_mem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define SHM_PATH "/dev/shm_posix" 13 | #define SHM_SIZE 32 14 | #define SHM_MODE 0666 15 | #define SHM_FLAGS (O_CREAT | O_RDWR) 16 | 17 | int common_idx = 0; 18 | 19 | void signal_handler(int signum, siginfo_t* info, void* ptr) 20 | { 21 | if (signum == SIGINT) 22 | { 23 | shm_unlink(SHM_PATH); 24 | remove(SHM_PATH); 25 | printf("Cleanup %s\n", SHM_PATH); 26 | exit(0); 27 | } 28 | } 29 | 30 | int main(int argc, char** argv) 31 | { 32 | int shm_id = shm_open(SHM_PATH, SHM_FLAGS, SHM_MODE); 33 | if (shm_id == -1) 34 | { 35 | perror("shm_open"); 36 | exit(1); 37 | } 38 | 39 | if (ftruncate(shm_id, SHM_SIZE) == -1) 40 | { 41 | perror("ftruncate"); 42 | exit(1); 43 | } 44 | 45 | pid_t pid = fork(); 46 | if (pid == -1) 47 | { 48 | perror("fork"); 49 | exit(1); 50 | } 51 | 52 | if (pid == 0) 53 | { 54 | // Child process 55 | char* shm_ptr = (char*)mmap(NULL, SHM_SIZE, PROT_WRITE, MAP_SHARED, shm_id, 0); 56 | if (shm_ptr == MAP_FAILED) 57 | { 58 | perror("mmap"); 59 | exit(1); 60 | } 61 | 62 | while (common_idx < SHM_SIZE) 63 | { 64 | char ch = 'a' + (common_idx % 26); 65 | shm_ptr[common_idx] = ch; 66 | printf("CHILD edited: %s\n", shm_ptr); 67 | common_idx++; 68 | usleep(100000); 69 | } 70 | 71 | munmap(shm_ptr, SHM_SIZE); 72 | } 73 | else 74 | { 75 | // Parent process 76 | struct sigaction act; 77 | act.sa_sigaction = signal_handler; 78 | act.sa_flags = SA_SIGINFO; 79 | sigaction(SIGINT, &act, NULL); 80 | 81 | char* shm_ptr = (char*)mmap(NULL, SHM_SIZE, PROT_WRITE, MAP_SHARED, shm_id, 0); 82 | if (shm_ptr == MAP_FAILED) 83 | { 84 | perror("mmap"); 85 | exit(1); 86 | } 87 | 88 | memset(shm_ptr, 0, SHM_SIZE); 89 | 90 | while (common_idx < SHM_SIZE) 91 | { 92 | char ch = 'A' + (common_idx % 26); 93 | shm_ptr[common_idx] = ch; 94 | printf("PARENT edited: %s\n", shm_ptr); 95 | common_idx++; 96 | usleep(100000); 97 | } 98 | 99 | munmap(shm_ptr, SHM_SIZE); 100 | 101 | wait(NULL); 102 | } 103 | 104 | return 0; 105 | } -------------------------------------------------------------------------------- /SharedMemory/system_v_shared_mem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #define PROJECT_ID 0x5555 16 | 17 | #define SHM_MODE 0666 18 | #define SHM_FLAGS (IPC_CREAT | SHM_MODE) 19 | #define SHM_SIZE 32 20 | #define SHM_PATH "/tmp/shm" 21 | 22 | key_t shm_key; 23 | int common_idx = 0; 24 | 25 | void init_shm_keys() __attribute__((constructor)); 26 | 27 | void init_shm_keys() 28 | { 29 | int fd_shm = open(SHM_PATH, O_CREAT | O_RDWR, 0666); 30 | if (fd_shm == -1) 31 | { 32 | perror("open"); 33 | exit(1); 34 | } 35 | close(fd_shm); 36 | 37 | shm_key = ftok(SHM_PATH, PROJECT_ID); 38 | if (shm_key == -1) 39 | { 40 | perror("ftok"); 41 | exit(1); 42 | } 43 | } 44 | 45 | void signal_handler(int signum, siginfo_t *info, void *ptr) 46 | { 47 | if (signum == SIGINT) 48 | { 49 | shmctl(shmget(shm_key, SHM_SIZE, SHM_FLAGS), IPC_RMID, NULL); 50 | unlink(SHM_PATH); 51 | remove(SHM_PATH); 52 | printf("Cleanup Shared Memory\n"); 53 | exit(0); 54 | } 55 | } 56 | 57 | int main(int argc, char** argv) 58 | { 59 | int shm_id = shmget(shm_key, SHM_SIZE, SHM_FLAGS); 60 | if (shm_id == -1) 61 | { 62 | perror("shmget"); 63 | exit(1); 64 | } 65 | 66 | pid_t pid = fork(); 67 | if (pid == -1) 68 | { 69 | perror("fork"); 70 | exit(1); 71 | } 72 | 73 | if (pid == 0) 74 | { 75 | char* shm_ptr = (char*)shmat(shm_id, NULL, 0); 76 | if (shm_ptr == MAP_FAILED) 77 | { 78 | perror("shmat"); 79 | exit(1); 80 | } 81 | 82 | memset(shm_ptr, 0, SHM_SIZE); 83 | 84 | while (common_idx < SHM_SIZE) 85 | { 86 | // reverse 87 | char ch = 'a' + (common_idx % 26); 88 | shm_ptr[common_idx] = ch; 89 | 90 | printf("CHILD edited: %s\n", (char*)shm_ptr); 91 | common_idx++; 92 | usleep(100000); 93 | } 94 | 95 | shmdt(shm_ptr); 96 | } 97 | else 98 | { 99 | struct sigaction act; 100 | act.sa_sigaction = signal_handler; 101 | act.sa_flags = SA_SIGINFO; 102 | sigaction(SIGINT, &act, NULL); 103 | 104 | char* shm_ptr = (char*)shmat(shm_id, NULL, 0); 105 | if (shm_ptr == MAP_FAILED) 106 | { 107 | perror("shmat"); 108 | exit(1); 109 | } 110 | 111 | memset(shm_ptr, 0, SHM_SIZE); 112 | 113 | while (common_idx < SHM_SIZE) 114 | { 115 | char ch = 'A' + (common_idx % 26); 116 | shm_ptr[common_idx] = ch; 117 | printf("PARENT edited: %s\n", (char*)shm_ptr); 118 | common_idx++; 119 | usleep(100000); 120 | } 121 | 122 | shmdt(shm_ptr); 123 | 124 | wait(NULL); 125 | } 126 | 127 | return 0; 128 | } -------------------------------------------------------------------------------- /Signal/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10...3.28) 2 | project(IPCSignal) 3 | 4 | set(CMAKE_BUILD_TYPE Debug) 5 | set (CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED True) 7 | 8 | function(compile_executables target_name file_path) 9 | add_executable(${target_name} ${file_path}) 10 | 11 | target_link_libraries(${target_name} 12 | PRIVATE 13 | stdc++fs 14 | ) 15 | endfunction() 16 | 17 | file(GLOB_RECURSE CPP_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") 18 | 19 | foreach(file_path ${CPP_FILES}) 20 | get_filename_component(target_name ${file_path} NAME_WE) 21 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 22 | endforeach() 23 | -------------------------------------------------------------------------------- /Signal/process_a.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | std::cout << "Process A started with PID: " << getpid() << std::endl; 17 | int count = 0; 18 | while (true) 19 | { 20 | sleep(1); 21 | count++; 22 | pid_t parent_id = getppid(); 23 | kill(parent_id, SIGUSR1); 24 | 25 | if (count > 3) 26 | { 27 | break; 28 | } 29 | } 30 | return 0; 31 | } -------------------------------------------------------------------------------- /Signal/process_b.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | std::cout << "Process B started with PID: " << getpid() << std::endl; 17 | int count = 0; 18 | while (true) 19 | { 20 | sleep(1); 21 | count++; 22 | pid_t parent_id = getppid(); 23 | kill(parent_id, SIGUSR1); 24 | 25 | if (count > 3) 26 | { 27 | break; 28 | } 29 | } 30 | return 0; 31 | } -------------------------------------------------------------------------------- /Signal/process_c.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) 15 | { 16 | std::cout << "Process C started with PID: " << getpid() << std::endl; 17 | int count = 0; 18 | while (true) 19 | { 20 | sleep(1); 21 | count++; 22 | pid_t parent_id = getppid(); 23 | kill(parent_id, SIGUSR1); 24 | 25 | if (count > 3) 26 | { 27 | break; 28 | } 29 | } 30 | return 0; 31 | } -------------------------------------------------------------------------------- /Signal/system_service.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #define HEARTBEAT_THRESHOLD (3) 16 | 17 | struct ProcessInfo 18 | { 19 | std::string process_name; 20 | std::chrono::time_point last_heartbeat; 21 | }; 22 | 23 | std::map process_table; 24 | std::queue process_queue; 25 | std::mutex process_table_mut; 26 | 27 | void signal_handler(int signum, siginfo_t* siginfo, void* context) 28 | { 29 | std::cout << "Received signal: " << signum << " from PID: " << siginfo->si_pid << std::endl; 30 | if (signum == SIGUSR1) 31 | { 32 | std::lock_guard lock(process_table_mut); 33 | for (auto& process : process_table) 34 | { 35 | if (process.first == siginfo->si_pid) 36 | { 37 | process.second.last_heartbeat = std::chrono::steady_clock::now(); 38 | break; 39 | } 40 | } 41 | } 42 | else if (signum == SIGINT) 43 | { 44 | std::cout << "Shutting down system service..." << std::endl; 45 | std::lock_guard lock(process_table_mut); 46 | for (const auto& process : process_table) 47 | { 48 | kill(process.first, SIGTERM); 49 | } 50 | exit(EXIT_SUCCESS); 51 | } 52 | else if (signum == SIGCHLD) 53 | { 54 | int status; 55 | if (waitpid(siginfo->si_pid, &status, WNOHANG) > 0) 56 | { 57 | std::cerr << "Process with PID: " << siginfo->si_pid << " has exited with status: " << status << std::endl; 58 | if (WIFEXITED(status) || WIFSIGNALED(status)) 59 | { 60 | std::cerr << "Process exited normally with status: " << WEXITSTATUS(status) << std::endl; 61 | std::lock_guard lock(process_table_mut); 62 | ProcessInfo process_info = process_table[siginfo->si_pid]; 63 | process_queue.push(process_info); 64 | process_table.erase(siginfo->si_pid); 65 | } 66 | } 67 | } 68 | else 69 | { 70 | std::cerr << "Received unknown signal: " << signum << std::endl; 71 | } 72 | } 73 | 74 | void start_process(const std::string& process_name) 75 | { 76 | std::cout << "Starting process: " << process_name << std::endl; 77 | pid_t pid = fork(); 78 | if (pid == 0) 79 | { 80 | execl(process_name.c_str(), process_name.c_str(), nullptr); 81 | std::cerr << "Failed to exec process: " << process_name << std::endl; 82 | exit(EXIT_FAILURE); 83 | } 84 | else if (pid > 0) 85 | { 86 | ProcessInfo process_info; 87 | process_info.process_name = process_name; 88 | process_info.last_heartbeat = std::chrono::steady_clock::now(); 89 | 90 | process_table[pid] = process_info; 91 | 92 | std::cout << "Started process: " << process_name << " with PID: " << pid << std::endl; 93 | } 94 | else 95 | { 96 | std::cerr << "Failed to start process: " << process_name << std::endl; 97 | } 98 | } 99 | 100 | void init_processes() 101 | { 102 | std::cout << "Initializing processes..." << std::endl; 103 | for (const auto& entry : std::experimental::filesystem::directory_iterator(".")) 104 | { 105 | if (std::experimental::filesystem::is_regular_file(entry.path()) 106 | && (std::experimental::filesystem::status(entry.path()).permissions() & std::experimental::filesystem::perms::owner_exec) == std::experimental::filesystem::perms::owner_exec) 107 | { 108 | std::string process_name = entry.path().filename().string(); 109 | if (process_name.find("process_") != std::string::npos) 110 | { 111 | process_queue.push({process_name, std::chrono::steady_clock::now()}); 112 | } 113 | } 114 | } 115 | } 116 | 117 | void monitor_processes() 118 | { 119 | while (true) 120 | { 121 | std::this_thread::sleep_for(std::chrono::seconds(1)); 122 | auto current_time = std::chrono::steady_clock::now(); 123 | std::cout << "tick..." << std::endl; 124 | 125 | std::lock_guard lock(process_table_mut); 126 | for (auto it = process_table.begin(); it != process_table.end();) 127 | { 128 | ProcessInfo process_info = it->second; 129 | auto duration = std::chrono::duration_cast(current_time - process_info.last_heartbeat).count(); 130 | if (duration > HEARTBEAT_THRESHOLD) 131 | { 132 | process_queue.push(process_info); 133 | 134 | std::cout << "Process: " << process_info.process_name << " with PID: " << it->first << " is not responding. Restarting..." << std::endl; 135 | kill(it->first, SIGKILL); 136 | 137 | int status; 138 | waitpid(it->first, &status, 0); 139 | 140 | it = process_table.erase(it); 141 | } 142 | else 143 | { 144 | ++it; 145 | } 146 | } 147 | 148 | // Restarting processes 149 | while (!process_queue.empty()) 150 | { 151 | ProcessInfo process_info = process_queue.front(); 152 | process_queue.pop(); 153 | start_process(process_info.process_name); 154 | } 155 | } 156 | } 157 | 158 | int main(int argc, char** argv) 159 | { 160 | struct sigaction sig_act; 161 | sig_act.sa_flags = SA_SIGINFO | SA_NOCLDWAIT; 162 | sig_act.sa_sigaction = signal_handler; 163 | sigemptyset(&sig_act.sa_mask); 164 | 165 | sigaction(SIGUSR1, &sig_act, nullptr); 166 | sigaction(SIGCHLD, &sig_act, nullptr); 167 | sigaction(SIGINT, &sig_act, nullptr); 168 | 169 | init_processes(); 170 | 171 | std::thread monitor_thread(monitor_processes); 172 | std::cout << "System service started..." << std::endl; 173 | monitor_thread.detach(); 174 | 175 | while (true) 176 | { 177 | pause(); 178 | } 179 | 180 | return 0; 181 | } -------------------------------------------------------------------------------- /Socket/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10...3.28) 2 | project(IPCSocket) 3 | 4 | set(CMAKE_BUILD_TYPE Debug) 5 | 6 | function(compile_executables target_name file_path) 7 | add_executable(${target_name} ${file_path}) 8 | 9 | target_link_libraries(${target_name} 10 | PRIVATE 11 | pthread 12 | ) 13 | endfunction() 14 | 15 | file(GLOB_RECURSE C_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.c") 16 | file(GLOB_RECURSE CPP_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") 17 | 18 | foreach(file_path ${C_FILES}) 19 | get_filename_component(target_name ${file_path} NAME_WE) 20 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 21 | endforeach() 22 | 23 | foreach(file_path ${CPP_FILES}) 24 | get_filename_component(target_name ${file_path} NAME_WE) 25 | compile_executables(${target_name} ${CMAKE_CURRENT_SOURCE_DIR}/${file_path}) 26 | endforeach() 27 | -------------------------------------------------------------------------------- /Socket/unix_client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define SOCKET_PATH "/tmp/unix_socket" 13 | #define MAX_CONNECTION 64 14 | #define BUFFER_SIZE 1024 15 | 16 | int global_sock_server = -1; 17 | 18 | void signal_handler(int signum, siginfo_t *info, void *ptr) 19 | { 20 | if (signum == SIGINT) 21 | { 22 | if (global_sock_server != -1) 23 | { 24 | close(global_sock_server); 25 | printf("Disconnect from server\n"); 26 | } 27 | exit(0); 28 | } 29 | } 30 | 31 | int main(int argc, char** argv) 32 | { 33 | struct sigaction act; 34 | memset(&act, 0, sizeof(act)); 35 | act.sa_sigaction = signal_handler; 36 | act.sa_flags = SA_SIGINFO; 37 | if (sigaction(SIGINT, &act, NULL) == -1) 38 | { 39 | perror("sigaction"); 40 | exit(1); 41 | } 42 | 43 | int sock_server = socket(AF_UNIX, SOCK_STREAM, 0); 44 | if (sock_server < 0) 45 | { 46 | perror("socket"); 47 | exit(1); 48 | } 49 | 50 | global_sock_server = sock_server; 51 | 52 | struct sockaddr_un addr_server; 53 | memset(&addr_server, 0, sizeof(struct sockaddr_un)); 54 | addr_server.sun_family = AF_UNIX; 55 | strncpy(&addr_server.sun_path, SOCKET_PATH, sizeof(addr_server.sun_path) - 1); 56 | 57 | if (connect(sock_server, (struct sockaddr*)&addr_server, sizeof(addr_server)) == -1) 58 | { 59 | perror("connect"); 60 | close(sock_server); 61 | exit(1); 62 | } 63 | 64 | // Client Loop 65 | while (1) 66 | { 67 | char request_buf[BUFFER_SIZE]; 68 | memset(request_buf, 0, BUFFER_SIZE); 69 | printf("Enter request: "); 70 | fgets(request_buf, BUFFER_SIZE - 1, stdin); 71 | request_buf[strcspn(request_buf, "\r\n")] = 0; 72 | 73 | int sent_bytes = send(sock_server, request_buf, strlen(request_buf), 0); 74 | if (sent_bytes <= 0) 75 | { 76 | perror("send"); 77 | continue; 78 | } 79 | else 80 | { 81 | char response_buf[BUFFER_SIZE]; 82 | memset(response_buf, 0, BUFFER_SIZE); 83 | 84 | int recv_bytes = recv(sock_server, response_buf, BUFFER_SIZE, 0); 85 | if (recv_bytes <= 0) 86 | { 87 | perror("recv"); 88 | break; 89 | } 90 | 91 | printf("Server response: %s\n", response_buf); 92 | 93 | if (strcmp(request_buf, "quit") == 0) 94 | { 95 | break; 96 | } 97 | } 98 | } 99 | 100 | close(sock_server); 101 | return 0; 102 | } -------------------------------------------------------------------------------- /Socket/unix_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define SOCKET_PATH "/tmp/unix_socket" 14 | #define MAX_CONNECTION 64 15 | #define BUFFER_SIZE 1024 16 | 17 | void signal_handler(int signum) 18 | { 19 | if (signum == SIGINT) 20 | { 21 | unlink(SOCKET_PATH); 22 | printf("\nServer shut down.\n"); 23 | exit(0); 24 | } 25 | } 26 | 27 | void set_non_blocking(int fd) 28 | { 29 | int flags = fcntl(fd, F_GETFL); 30 | if (flags == -1) 31 | { 32 | perror("fcntl F_GETFL"); 33 | return; 34 | } 35 | 36 | if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) 37 | { 38 | perror("fcntl F_SETFL O_NONBLOCK"); 39 | } 40 | } 41 | 42 | int main() 43 | { 44 | signal(SIGINT, signal_handler); 45 | 46 | int sock_server = socket(AF_UNIX, SOCK_STREAM, 0); 47 | if (sock_server < 0) 48 | { 49 | perror("socket"); 50 | exit(EXIT_FAILURE); 51 | } 52 | 53 | set_non_blocking(sock_server); 54 | 55 | struct sockaddr_un addr_server; 56 | memset(&addr_server, 0, sizeof(struct sockaddr_un)); 57 | addr_server.sun_family = AF_UNIX; 58 | strncpy(addr_server.sun_path, SOCKET_PATH, sizeof(addr_server.sun_path) - 1); 59 | 60 | unlink(SOCKET_PATH); 61 | 62 | if (bind(sock_server, (struct sockaddr *)&addr_server, sizeof(addr_server)) == -1) 63 | { 64 | perror("bind"); 65 | close(sock_server); 66 | exit(EXIT_FAILURE); 67 | } 68 | 69 | if (listen(sock_server, MAX_CONNECTION) == -1) 70 | { 71 | perror("listen"); 72 | close(sock_server); 73 | exit(EXIT_FAILURE); 74 | } 75 | 76 | printf("Server listening on %s\n", SOCKET_PATH); 77 | 78 | struct pollfd fds[MAX_CONNECTION]; 79 | memset(fds, 0, sizeof(struct pollfd) * MAX_CONNECTION); 80 | fds[0].fd = sock_server; 81 | fds[0].events = POLLIN; 82 | 83 | int nfds = 1; 84 | 85 | while (1) 86 | { 87 | int act = poll(fds, nfds, -1); 88 | if (act < 0) 89 | { 90 | perror("poll"); 91 | break; 92 | } 93 | 94 | for (int i = 0; i < nfds; i++) 95 | { 96 | if (fds[i].revents & POLLIN) 97 | { 98 | if (fds[i].fd == sock_server) 99 | { 100 | int sock_client = accept(sock_server, NULL, NULL); 101 | if (sock_client > 0) 102 | { 103 | printf("Client %d is connected\n", sock_client); 104 | set_non_blocking(sock_client); 105 | 106 | if (nfds < MAX_CONNECTION) 107 | { 108 | fds[nfds].fd = sock_client; 109 | fds[nfds].events = POLLIN; 110 | nfds++; 111 | } 112 | else 113 | { 114 | printf("Max clients reached. Closing client %d.\n", sock_client); 115 | close(sock_client); 116 | } 117 | } 118 | else 119 | { 120 | if (errno != EAGAIN && errno != EWOULDBLOCK) 121 | { 122 | perror("accept"); 123 | } 124 | } 125 | } 126 | else 127 | { 128 | char buffer[BUFFER_SIZE] = {0}; 129 | int recv_bytes = recv(fds[i].fd, buffer, BUFFER_SIZE, 0); 130 | 131 | if (recv_bytes > 0) 132 | { 133 | printf("Client %d sent: %s\n", fds[i].fd, buffer); 134 | 135 | char response[BUFFER_SIZE] = {0}; 136 | snprintf(response, BUFFER_SIZE, "Server time: %ld", time(NULL)); 137 | if (send(fds[i].fd, response, strlen(response), 0) <= 0) 138 | { 139 | perror("send"); 140 | } 141 | } 142 | else if (recv_bytes == 0 || (recv_bytes == -1 && errno != EAGAIN && errno != EWOULDBLOCK)) 143 | { 144 | printf("Client %d is disconnected\n", fds[i].fd); 145 | close(fds[i].fd); 146 | 147 | fds[i] = fds[nfds - 1]; 148 | nfds--; 149 | i--; 150 | } 151 | else 152 | { 153 | if (errno != EAGAIN && errno != EWOULDBLOCK) 154 | { 155 | perror("recv"); 156 | } 157 | } 158 | } 159 | } 160 | } 161 | } 162 | 163 | close(sock_server); 164 | unlink(SOCKET_PATH); 165 | return 0; 166 | } 167 | -------------------------------------------------------------------------------- /Socket/unix_socket_pair.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define SOCKET_PATH "/tmp/unix_socket" 14 | #define BUFFER_SIZE 32 15 | 16 | void signal_handler(int signum) 17 | { 18 | if (signum == SIGINT || signum == SIGCHLD) 19 | { 20 | unlink(SOCKET_PATH); 21 | exit(0); 22 | } 23 | } 24 | 25 | int main() 26 | { 27 | int fd_pair[2]; 28 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd_pair) == -1) 29 | { 30 | perror("socketpair"); 31 | exit(1); 32 | } 33 | 34 | pid_t pid = fork(); 35 | if (pid == -1) 36 | { 37 | perror("fork"); 38 | exit(1); 39 | } 40 | 41 | if (pid == 0) 42 | { 43 | signal(SIGCHLD, signal_handler); 44 | 45 | char buf[BUFFER_SIZE]; 46 | while (1) 47 | { 48 | memset(buf, 0, BUFFER_SIZE); 49 | int read_bytes = recv(fd_pair[1], buf, BUFFER_SIZE, 0); 50 | if (read_bytes <= 0) 51 | { 52 | break; 53 | } 54 | 55 | int n = strlen(buf); 56 | for (int i = 0; i < n; i++) 57 | { 58 | if (buf[i] >= 'a' && buf[i] <= 'z') 59 | { 60 | buf[i] = (buf[i] & (~32)); 61 | } 62 | else 63 | { 64 | buf[i] = (buf[i] | 32); 65 | } 66 | } 67 | 68 | send(fd_pair[1], buf, n, 0); 69 | 70 | usleep(100000); 71 | } 72 | } 73 | else 74 | { 75 | signal(SIGINT, signal_handler); 76 | 77 | char buf[BUFFER_SIZE]; 78 | memset(buf, 0, BUFFER_SIZE); 79 | for (int i = 0; i < BUFFER_SIZE - 1; i++) 80 | { 81 | buf[i] = 'a' + (i % 26); 82 | printf("PARENT made string: %s\n", buf); 83 | send(fd_pair[0], buf, BUFFER_SIZE, 0); 84 | 85 | char response[BUFFER_SIZE]; 86 | memset(response, 0, BUFFER_SIZE); 87 | recv(fd_pair[0], response, BUFFER_SIZE, 0); 88 | printf("CHILD remade string: %s\n", response); 89 | 90 | strcpy(buf, response); 91 | } 92 | 93 | close(fd_pair[0]); 94 | close(fd_pair[1]); 95 | unlink(SOCKET_PATH); 96 | kill(pid, SIGCHLD); 97 | wait(NULL); 98 | } 99 | 100 | return 0; 101 | } --------------------------------------------------------------------------------