Automating Multi-Party Communication for a C++ Program
This tutorial will guide you through automating the execution of a C++ program requiring three parties to communicate. We’ll cover multiple methods to achieve this, with a detailed description for using Python with libtmux
.
Prerequisites
- Basic knowledge of command line and scripting
- Required tools installed (varies by method)
Methods to Automate Multi-Party Communication
- Using Bash Script with tmux
- Using Makefile
- Using Python with libtmux (detailed)
- Using Docker
Method 1: Using Bash Script with tmux
This method leverages tmux
commands directly in a shell script.
Create a bash script file, e.g., run_experiments.sh
:
#!/bin/bash
# Define the session name
SESSION_NAME="MultiPartySession"
# Start a new tmux session and run the server
tmux new-session -d -s $SESSION_NAME -n server "./your_program server"
# Create a new window and run the third_party
tmux new-window -t $SESSION_NAME -n third_party "./your_program third_party"
# Allow some time for the server and third_party to start
sleep 5
# Create a new window and run the client_access
tmux new-window -t $SESSION_NAME -n client_access "./your_program client_access"
# Wait for the client to finish (adjust the sleep time based on expected duration)
sleep 60
# Terminate the server and third_party processes
pkill -f "./your_program server"
pkill -f "./your_program third_party"
# Kill the tmux session
tmux kill-session -t $SESSION_NAME
Make the script executable and run it:
chmod +x run_experiments.sh
./run_experiments.sh
Method 2: Using Makefile
Using a Makefile
is a structured approach often used for compiling and running programs with specific parameters.
Create a Makefile
:
TMUX_SESSION = MultiPartySession
CLIENT_ACCESS_TIME = 60
.PHONY: run
run:
tmux new-session -d -s $(TMUX_SESSION) -n server "./your_program server"
sleep 5
tmux new-window -t $(TMUX_SESSION) -n third_party "./your_program third_party"
sleep 5
tmux new-window -t $(TMUX_SESSION) -n client_access "./your_program client_access"
sleep $(CLIENT_ACCESS_TIME)
$(MAKE) terminate
.PHONY: terminate
terminate:
pkill -f "./your_program server"
pkill -f "./your_program third_party"
tmux kill-session -t $(TMUX_SESSION)
Run the Makefile:
make run
Method 3: Using Python with libtmux (Detailed)
This method uses the libtmux
library to manage tmux
sessions programmatically.
Install Required Tools
Install tmux:
For Ubuntu/Debian:
sudo apt-get update
sudo apt-get install tmux
For CentOS/RHEL:
sudo yum install tmux
For macOS:
brew install tmux
Install libtmux Python Library:
pip install libtmux
Create the Python Script
Create a new Python script file, e.g., run_experiments.py
, and copy the following code into it:
import os
import subprocess
import time
import libtmux
def find_and_kill_process_using_port(port):
try:
pids = subprocess.check_output(['lsof', '-t', '-i:{}'.format(port)], text=True).strip().split()
for pid in pids:
if pid:
print(f"Port {port} is being used by PID {pid}, attempting to kill.")
subprocess.check_call(['kill', '-9', pid]) # Forcefully terminating the process
print(f"Successfully killed process {pid}")
except subprocess.CalledProcessError as e:
print(f"No process is using port {port} or failed to kill process: {e}")
def main():
tmux_server = libtmux.Server()
session_name = "MultiPartySession"
# Example ports to be cleared before starting
ports = [8283, 8288]
for port in ports:
find_and_kill_process_using_port(port)
# Example Z and R values for demonstration purposes
rest_z = [14, 18, 22]
compileAndMove = {
'Z': [14, 18, 22, 26],
'R': [115, 127, 139, 151],
'p_stash': 8283,
'p_tp': 8288
}
for z, r in zip(compileAndMove['Z'], compileAndMove['R']):
if z not in rest_z:
continue
print(f"Running experiment with Z={z} and R={r}")
# Construct the common command path
commonCommandPath = f"./your_program_Z_{z}_R_{r}"
# Create a new tmux session and windows for server, third_party, and client
session = tmux_server.new_session(session_name=session_name, kill_session=True, detach=True)
# Start the server in the first window
server_window = session.new_window(window_name="server", attach=False)
server_pane = server_window.active_pane
server_pane.send_keys(f"{commonCommandPath} server", enter=True)
print(f"Started server for Z={z} and R={r}")
# Start the third_party in the second window
third_party_window = session.new_window(window_name="third_party", attach=False)
third_party_pane = third_party_window.active_pane
third_party_pane.send_keys(f"{commonCommandPath} third_party", enter=True)
print(f"Started third_party for Z={z} and R={r}")
# Allow some time for server and third_party to start
time.sleep(5)
# Start the client in the third window
client_window = session.new_window(window_name="client_access", attach=False)
client_pane = client_window.active_pane
client_pane.send_keys(f"{commonCommandPath} client_access", enter=True)
print(f"Started client_access for Z={z} and R={r}")
# Wait for the client to finish by continuously checking its output
while True:
time.sleep(1)
output = client_pane.capture_pane()
if not output or all(line.strip() == "" for line in output):
break
# Log output from each pane (optional, for debugging)
server_output = server_pane.capture_pane()
third_party_output = third_party_pane.capture_pane()
client_output = client_pane.capture_pane()
print(f"Server output for Z={z} and R={r}:\n{''.join(server_output)}")
print(f"Third party output for Z={z} and R={r}:\n{''.join(third_party_output)}")
print(f"Client output for Z={z} and R={r}:\n{''.join(client_output)}")
# Terminate the server and third_party processes
server_pane.cmd('send-keys', 'C-c')
third_party_pane.cmd('send-keys', 'C-c')
print(f"Terminated server and third_party for Z={z} and R={r}")
# Ensure all processes have stopped
time.sleep(1)
# Close the tmux session
session.kill_session()
print(f"Closed tmux session for Z={z} and R={r}")
# Delay before starting the next iteration, if necessary
time.sleep(1)
print("All tasks completed.")
if __name__ == "__main__":
main()
Run the Python Script
Make the script executable (optional but recommended):
chmod +x run_experiments.py
Run the script:
python run_experiments.py
Verify the Execution
- Monitor the Output: Check the output of the script to see detailed logging messages.
- Attach to the tmux Session: Use
tmux attach-session -t MultiPartySession
to attach to thetmux
session and see the output of each command in real-time. - Check Running Processes: Use
ps aux | grep your_program
to check if the processes are running.
Troubleshooting
- Ports Already in Use: Ensure the ports used by your processes are free. The script attempts to kill any processes using specific ports at the start.
- Processes Not Starting: Check the command paths and ensure the executable is in the correct directory. Verify the output of each pane for error messages.
- Script Errors: Read the error messages in the output and make necessary adjustments. The provided script logs detailed output for debugging purposes.
Conclusion
This tutorial demonstrated multiple methods to automate the execution of a multi-party C++ program. The detailed method using Python and libtmux
offers a flexible and programmatic approach to managing tmux
sessions and windows. Choose the method that best fits your requirements and environment.
For further customization and debugging, refer to the libtmux
documentation and adjust the script as needed.