A client-server communication program using UNIX signals to transmit messages bit by bit.
- Overview
- How It Works
- Project Structure
- Technical Implementation
- Compilation & Usage
- Features
- Signal Communication Protocol
- Bonus Features
Minitalk is a 42 School project that demonstrates inter-process communication (IPC) using UNIX signals. The project consists of a server that receives messages and a client that sends them, with all communication happening through SIGUSR1 and SIGUSR2 signals.
The communication works by transmitting each character bit by bit:
- SIGUSR1 represents a
1bit - SIGUSR2 represents a
0bit - Each character is sent as 8 bits (1 byte)
- The null terminator
\0signals the end of the message
Client Server
│ │
├─ Send bit 1 (SIGUSR1) ───────→│
│◄─────────────────── ACK (SIGUSR1)
│ │
├─ Send bit 0 (SIGUSR2) ───────→│
│◄─────────────────── ACK (SIGUSR1)
│ │
└─ Continue for all 8 bits... │
│
Complete character received
minitalk/
├── client.c # Basic client implementation
├── client_bonus.c # Enhanced client with emojis
├── server.c # Basic server implementation
├── server_bonus.c # Enhanced server with better error handling
├── minitalk.h # Header file with function prototypes
├── utility.c # Helper functions (ft_atoi, ft_strlen, ft_putnbr)
└── Makefile # Compilation rules
The server uses sigaction() for robust signal handling:
void handle_signal(int signal, siginfo_t *info, void *context)
{
static unsigned char current_char = 0;
static int bits_received = 0;
// Shift current character left and add new bit
current_char <<= 1;
if (signal == SIGUSR1)
current_char |= 1;
bits_received++;
// When 8 bits received, we have a complete character
if (bits_received == 8) {
if (current_char == '\0') {
// End of message
write(1, "\n", 1);
kill(client_pid, SIGUSR2); // Notify completion
} else {
write(1, ¤t_char, 1); // Print character
}
// Reset for next character
bits_received = 0;
current_char = 0;
}
// Send acknowledgment back to client
kill(client_pid, SIGUSR1);
}The client sends each character bit by bit:
static void send_signal(pid_t server_pid, char character)
{
int bit_position = 8;
while (bit_position--) {
g_signal_ready = 0;
// Extract bit at current position
if ((character >> bit_position) & 1)
kill(server_pid, SIGUSR1); // Send 1
else
kill(server_pid, SIGUSR2); // Send 0
// Wait for server acknowledgment
while (!g_signal_ready)
usleep(10);
}
}character >> bit_position: Right shift to get specific bit& 1: Mask to extract only the least significant bitcurrent_char <<= 1: Left shift to make room for new bitcurrent_char |= 1: Set the least significant bit
- SA_SIGINFO flag: Provides additional signal information (sender PID)
- siginfo_t structure: Contains sender's process ID for response
- Static variables: Maintain state between signal calls
- Acknowledgment system: Server confirms each bit reception
- Global flag: Client waits for acknowledgment before sending next bit
- usleep(10): Small delay to prevent overwhelming the system
# Compile basic version
make
# Compile bonus version
make bonus
# Clean object files
make clean
# Full clean (including executables)
make fclean
# Recompile everything
make re# Terminal 1: Start server
./server
# Output: Server PID: 12345
# Waiting for messages...
# Terminal 2: Send message
./client 12345 "Hello World!"# Terminal 1: Start bonus server
./server_bonus
# Output: 🚀 Bonus Server PID: 12345
# 📟 Ready for messages...
# Terminal 2: Send message
./client_bonus 12345 "Hello from bonus client! 🎉"
# Output: ⏛️ Successfully!- ✅ Client-server communication via signals
- ✅ Bit-by-bit character transmission
- ✅ Message acknowledgment system
- ✅ Proper null termination handling
- ✅ Enhanced visual feedback with emojis
- ✅ Better error handling
- ✅ Empty message validation
- ✅ Improved signal management
- ✅ Character confirmation counter
- Server Startup: Display PID and wait for signals
- Client Connection: Parse server PID from command line
- Character Loop: For each character in message:
- Send 8 bits (MSB first)
- Wait for acknowledgment after each bit
- Server reconstructs character bit by bit
- Message End: Send null terminator
- Completion: Server sends completion signal
| Signal | Direction | Meaning |
|---|---|---|
| SIGUSR1 | Client→Server | Bit value: 1 |
| SIGUSR2 | Client→Server | Bit value: 0 |
| SIGUSR1 | Server→Client | Bit acknowledged |
| SIGUSR2 | Server→Client | Message complete (bonus) |
The bonus version includes several enhancements:
- Visual feedback: Emoji-based status messages
- Input validation: Checks for empty messages
- Success notification: Confirms message delivery
- Character tracking: Counts confirmed characters
- Enhanced display: Colorful startup messages with emojis
- Better error handling: Validates signal handler setup
- Improved signal masking: More robust signal management
- Separated concerns: Character processing in dedicated function
This project teaches several important concepts:
- UNIX signal handling and manipulation
- Inter-process communication (IPC)
- Process identification and signaling
- Bit manipulation and binary operations
- Signal-based synchronization
- Race condition prevention
- Acknowledgment protocols
- State management with static variables
- Signal handler validation
- Input parameter checking
- System call error management
- Graceful program termination
- Memory safety: No dynamic allocation used
- 42 Norm compliance: Follows strict coding standards
- Error handling: Comprehensive input validation
- Modularity: Separated utilities and core logic
- Documentation: Well-commented code structure
Note: This project demonstrates low-level system programming concepts and is designed for educational purposes in the 42 School curriculum.