Skip to content

rfs-hybrid-42-common-core/minitalk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

11 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

This project has been created as part of the 42 curriculum by maaugust.

Minitalk Cover

๐Ÿ’ฌ Minitalk: Data Exchange Using UNIX Signals


๐Ÿ’ก Description

Minitalk is a project in the 42 curriculum. The purpose of this project is to code a small data exchange program using UNIX signals.

We are tasked with creating a communication program in the form of a client and a server. The client must send a specified string to the server, which must then receive and display the string without delay. To make things interesting, communication between the client and server must exclusively use UNIX signals, specifically only SIGUSR1 and SIGUSR2.


๐Ÿ“‘ Features

๐Ÿ”น Mandatory Features

  • Sequential Processing: The server can receive strings from several clients in a row without needing to restart.
  • Speed: The program parses and prints bits rapidly, ensuring large strings (100+ characters) are displayed in under a second.
  • Robust Error Handling: The program handles errors thoroughly and will not quit unexpectedly (no segmentation faults, bus errors, or double frees).

๐Ÿš€ Bonus Features

  • Ping-Pong Acknowledgment: The server acknowledges every single received message by sending a signal back to the client.
  • Unicode Support: Natively supports and prints Unicode characters.

๐Ÿง  Algorithm & Data Structure

The Core Logic: Bitwise Operations

Since we are only allowed to use two signals (SIGUSR1 and SIGUSR2), we cannot send standard char data types directly. Instead, the client translates every character of the string into its 8-bit binary representation.

  • It sends SIGUSR1 to represent a 1.
  • It sends SIGUSR2 to represent a 0.

The server catches these signals one by one, shifts the bits back into an 8-bit unsigned char (to avoid sign-extension issues), and prints the reconstructed byte to the standard output. Because it prints raw bytes, UTF-8/Unicode characters are implicitly supported in both versions!

Signal Pacing vs. State Management

  • Mandatory Approach: The client paces its signal transmission using usleep() between each bit to prevent overwhelming the server's signal queue and dropping bits.
  • Bonus Approach (Ping-Pong): To achieve flawless transmission without relying on arbitrary sleep times, the bonus client utilizes a single global variable as a lock, pausing the client loop until an acknowledgment signal (SIGUSR1) is received from the server before dispatching the next bit.

The Global Variable: volatile sig_atomic_t

The project subject permits the use of one global variable per program, provided its use is strictly justified. In the bonus client, volatile sig_atomic_t g_ack; is used. Here is the technical justification:

  • sig_atomic_t: This integer type guarantees that reading and writing to the variable happens in a single, atomic instruction. This prevents a scenario where the main program is halfway through reading the variable when a signal interrupts it and changes the value, which would result in corrupted or "half-read" data.
  • volatile: This keyword tells the compiler that the variable's value can change at any time asynchronously (outside the normal flow of the code, such as inside a signal handler). Without volatile, an optimizing compiler might look at the while (g_ack == PAUSE) loop, assume g_ack is never modified inside that loop, and aggressively compile it into an infinite loop. volatile forces the program to fetch the actual, most up-to-date value from memory on every single iteration.

๐Ÿ› ๏ธ Instructions

๐Ÿ“ฆ Installation

To compile the project, run the following commands in the root of the repository.

  • To build the mandatory executables (client and server):
make
  • To build the bonus executables with acknowledgment features (client_bonus and server_bonus):
make bonus

๐Ÿงน Cleaning

  • make clean: Removes the compiled object files (.o).
  • make fclean: Removes object files and all executables.
  • make re: Performs a clean re-build.

๐Ÿ’ป Usage

1. Start the Server: The server must be started first. Upon launch, it will print its PID.

./server
# OR for the bonus version:
./server_bonus

Output:

The process ID is: 12345.

2. Run the Client: In a separate terminal window, run the client by passing the server's PID and the string you wish to send.

./client 12345 "Hello, 42!"
# OR for the bonus version:
./client_bonus 12345 "Hello, 42!"

The server terminal will immediately print Hello, 42!. If using the bonus version, the client terminal will also print a success message upon full acknowledgment.


โš ๏ธ The Mandatory usleep Dilemma (A Note for Students)

If you are testing the mandatory version of this project on a slow Virtual Machine (VM) or Windows Subsystem for Linux (WSL), you might see random garbage characters printed to the terminal.

The 42 subject requires that displaying 100 characters must take less than 1 second. However, Linux does not queue pending signals of the same type. In the mandatory version, the client relies on a hardcoded usleep() delay to pace the signals.

  • If the sleep time is too low, the VM's OS scheduler fails to context-switch fast enough, the server drops the incoming signal, and the bits become permanently misaligned (resulting in garbage data).
  • If the sleep time is too high, the program avoids garbage data but fails the strict speed requirement.

The Solution: The usleep value in the mandatory client.c is optimized for bare-metal campus machines (like the 42 iMacs). If you test this on a slow personal machine and get garbage output, simply increase the usleep delay in client.c to account for your hypervisor's latency. Alternatively, test the Bonus versionโ€”its ping-pong acknowledgment system dynamically adapts to the CPU's exact speed, completely eliminating this hardware bottleneck!


โš ๏ธ The Buffer vs. Stream Debate (Server Output)

A common debate among 42 students is whether the server should print characters one-by-one as they arrive, or buffer the entire string and print it all at once at the very end. This implementation intentionally streams the output character-by-character. Here is why:

  • "Without Delay": The subject requires the server to display the string "without delay". Waiting a full minute to receive a massive string before printing anything looks like a frozen program or a crash. Streaming characters provides real-time, live feedback of the communication.
  • The malloc Trap: The server has no prior knowledge of the incoming message's length. To buffer the string, it would require continuous, dynamic malloc and free operations inside a signal handler as the buffer expands. This introduces severe performance overhead and massive memory leak risks. By streaming directly via write(), this implementation maintains a memory footprint of effectively zero bytes and avoids the dynamic memory trap entirely.

๐Ÿงช Testing & Edge Cases

Minitalk can be deceivingโ€”it might perfectly transmit a small string like "Hello" but completely break, crash, or print random garbage data when handling massive strings or complex characters due to signal dropping or race conditions. Rigorous testing is essential.

1. Unicode & Emoji Stress Test Because this implementation passes raw bytes, it natively supports multi-byte Unicode characters. Try sending complex emojis to ensure bits aren't being misaligned:

./client_bonus 12345 "๐Ÿ”ฅ ๐Ÿ‘พ 42 Porto is awesome! ๐Ÿ‘พ ๐Ÿ”ฅ"

2. Third-Party Testers To ensure your Minitalk output is correct every single time without dropping signals in the middle of a massive transmission, highly recommend running your code through these community testers:

๐Ÿšจ The Norm

Moulinette relies on a program called norminette to check if your files comply with the 42 Norm. Every single .c and .h file must pass this check. If there is a norm error, you will receive a 0.

The 42 Header: Before writing any code, every file must start with the standard 42 header. norminette will automatically fail any file missing this specific signature.

/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   client.c                                           :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: maaugust <maaugust@student.42.fr>          +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2025/07/01 15:19:21 by maaugust          #+#    #+#             */
/*   Updated: 2025/07/09 17:18:26 by maaugust         ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

Run the following command in the root of your repository to check all your files at once:

norminette -R CheckForbiddenSourceHeader srcs/ bonus/ includes/

๐Ÿ“š Resources & References

System Manuals:

  • man 2 kill, man 2 signal, man 2 sigaction, man 2 pause - Essential Linux programmer's manuals for understanding system calls related to process signaling.

Articles & Guides:

Video Tutorials:

42 Standards:

๐Ÿค– AI Usage & Transparency

In the spirit of transparency and the learning objectives of the 42 curriculum, here is how AI tools were utilized during this project:

  • Tooling & Formatting: Assisted in restructuring and fixing minor variable duplication in the Makefile, formatting this README.md layout, and generating comprehensive Doxygen comments for the source files.
  • Zero Code Generation: No core logic was generated by AI. The core bitwise parsing algorithm, signal management via sigaction, and the ping-pong acknowledgment loop were 100% manually researched and written. This guarantees a true understanding of UNIX process communication.

About

A small client-server data exchange program built in C, utilizing UNIX signals (SIGUSR1 and SIGUSR2) for bit-level communication. Bonus implementation supports full Unicode characters and server-to-client acknowledgment.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors