/* * Sun Public License * * The contents of this file are subject to the Sun Public License Version * 1.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is available at http://www.sun.com/ * * The Original Code is the SLAMD Distributed Load Generation Engine. * The Initial Developer of the Original Code is Neil A. Wilson. * Portions created by Neil A. Wilson are Copyright (C) 2004-2010. * Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): Neil A. Wilson */ package com.slamd.tools.tcpreplay; import java.io.IOException; import java.text.DecimalFormat; /** * This program can be used to replay captured communication to a target server * to generate load. * * * @author Neil A. Wilson */ public class TCPReplay { /** * Parses the command-line arguments, creates the TCP capture daemon, and * starts capturing data. * * @param args The command-line arguments provided to this program. */ public static void main(String[] args) { // Specify default values for all the command-line arguments. boolean preserveTiming = false; float timingMultiplier = (float) 1.0; int delayBetweenIterations = 0; int delayBetweenPackets = 0; int maxDuration = -1; int maxIterations = 1; int numThreads = 1; int targetPort = -1; String captureFile = null; String targetHost = null; // Process the command-line arguments. for (int i=0; i < args.length; i++) { if (args[i].equals("-h")) { targetHost = args[++i]; } else if (args[i].equals("-p")) { targetPort = Integer.parseInt(args[++i]); if ((targetPort < 1) || (targetPort > 65535)) { System.err.println("ERROR: The target port must be between 1 and " + "65535"); System.exit(1); } } else if (args[i].equals("-i")) { captureFile = args[++i]; } else if (args[i].equals("-P")) { preserveTiming = true; } else if (args[i].equals("-m")) { timingMultiplier = Float.parseFloat(args[++i]); } else if (args[i].equals("-d")) { delayBetweenPackets = Integer.parseInt(args[++i]); } else if (args[i].equals("-I")) { maxIterations = Integer.parseInt(args[++i]); } else if (args[i].equals("-D")) { delayBetweenIterations = Integer.parseInt(args[++i]); } else if (args[i].equals("-T")) { maxDuration = Integer.parseInt(args[++i]); } else if (args[i].equals("-t")) { numThreads = Integer.parseInt(args[++i]); } else if (args[i].equals("-H")) { displayUsage(); System.exit(0); } else { System.err.println("ERROR: Unrecognized argument \"" + args[i] + '"'); displayUsage(); System.exit(1); } } // Verify that all the required parameters were provided. if (targetHost == null) { System.err.println("ERROR: No target server host provided (use -h)"); displayUsage(); System.exit(1); } if (targetPort < 0) { System.err.println("ERROR: No target server port provided (use -p)"); displayUsage(); System.exit(1); } if (captureFile == null) { System.err.println("ERROR: No capture file provided (use -i)"); displayUsage(); System.exit(1); } // Create the replay utility. ReplayCapture replayCapture = null; try { replayCapture = new ReplayCapture(targetHost, targetPort, captureFile, preserveTiming, timingMultiplier, delayBetweenPackets, maxIterations, delayBetweenIterations, maxDuration, numThreads); System.out.println("Read " + replayCapture.getNumPackets() + " packets from capture file \"" + captureFile + "\"."); } catch (IOException ioe) { System.err.println("ERROR: Unable to read capture file \"" + captureFile + "\": " + ioe); } catch (CaptureException ce) { System.err.println("ERROR: Unable to parse capture file \"" + captureFile + "\": " + ce); } // Start replaying the data, and wait for all threads to finish before // continuing. long startTime = System.currentTimeMillis(); replayCapture.replayData(); replayCapture.waitForReplayThreads(); long stopTime = System.currentTimeMillis(); // Print out some basic stats about the replay. long totalDisconnects = replayCapture.getTotalDisconnects(); long totalIterations = replayCapture.getTotalIterationsCompleted(); long totalReplayed = replayCapture.getTotalPacketsReplayed(); long totalDuration = stopTime - startTime; double packetsPerSecond = 1000.0 * totalReplayed / totalDuration; System.out.println("Processing complete."); System.out.println("Total Active Duration (ms): " + totalDuration); System.out.println("Total Iterations Completed: " + totalIterations); System.out.println("Total Packets Replayed: " + totalReplayed); System.out.println("Total Disconnects Encountered: " + totalDisconnects); System.out.println("Packets Replayed per Second: " + new DecimalFormat("0.000").format(packetsPerSecond)); } /** * Displays usage information for this program. */ public static void displayUsage() { String EOL = System.getProperty("line.separator"); System.out.println( "USAGE: java TCPReplay {options}" + EOL + " where {options} include" + EOL + "-h {address} -- Specifies the address of the server to which the data" + EOL + " should be replayed" + EOL + "-p {port} -- Specifies the port of the server to which the data" + EOL + " should be replayed" + EOL + "-i {file} -- Specifies the input file containing the captured data" + EOL + " to be replayed" + EOL + "-P -- Indicates that an attempt should be made to preserve" + EOL + " original timing between requests" + EOL + "-m {value} -- Specifies a multipler that may applied to the" + EOL + " original time between requests" + EOL + "-d {value} -- Specifies the delay in milliseconds to insert between" + EOL + " each packet replayed if the original timing is not to" + EOL + " be preserved" + EOL + "-I {value} -- Specifies the maximum number of iterations each" + EOL + " thread should make through the entire data set" + EOL + "-D {value} -- Specifies the delay in milliseconds to insert between" + EOL + " individual iterations through the entire data set" + EOL + "-T {value} -- Specifies the maximum length of time in seconds that" + EOL + " the replay should be allowed to process" + EOL + "-t {value} -- Specifies the number of threads that should replay" + EOL + " the data set concurrently" + EOL + "-H -- Displays this usage information" ); } }