Chariot虽然给我们提供了友好的界面,但是必须使用命令行或者使用它的API才能
实现自动测试。Chariot在安装的时候会让你选择命令行界面组件,在它的安装目录下面有一些工具,
暂时还不知道是干什么的,但是它的c语言API可以尝试一下。
打开Chariot的帮助文件,可以看到它具有API interface:
其中,TCL接口可以参照别人的博客,目前还没找到有人做过c语言的,这里就开始研究一下。
帮助里面提到,它支持这些编译器(Qt可能也支持,只是没有列出):
- Microsoft Visual C++ .NET 2003, Visual Studio 6.0 SP5 and above.
- IBM VisualAge for C++ Version 3.5 and above. (Note: this compiler is no longer available for new purchases).
- Watcom C/C++ Version 10.0 and above. (Note: this compiler is no longer available for new purchases).
我这里为了省力,先使用VC6.0来做。
新建一个工程,加入下述文件:
这些文件都可以在C:\Program Files\Ixia\IxChariot\SDK目录下找到。
编译后的结果是0 error, 0 warnings
然后点击VC的叹号后运行出错,说需要ChrApi.dll。我这里也走了一下弯路。
解压lib文件之后,发现有很多这样的DLL,我随便抽取都会出问题。
后来下了个dll查看器,发现无法识别这些dll。最后在chariot安装目录下
找到了这些dll。将生成的test.exe直接放入chariot安装目录下就可以运行了(虽然可能有小问题)。
这样已经成功了一半了。接下来就是修改、完善、定制代码。
这里贴出示例代码吧:
/**************************************************************** * * IxChariot API SDK File: ChrLBSimple.c * * This module contains code made available by Ixia on an AS IS * basis. Any one receiving the module is considered to be * licensed under Ixia copyrights to use the Ixia-provided * source code in any way he or she deems fit, including copying * it, compiling it, modifying it, and redistributing it, with * or without modifications. No license under any Ixia patents * or patent applications is to be implied from this copyright * license. * * A user of the module should understand that Ixia cannot * provide technical support for the module and will not be * responsible for any consequences of use of the program. * * Any notices, including this one, are not to be removed from * the module without the prior written consent of Ixia. * * For more information, contact: * * Ixia * 26601 W. Agoura Rd. * Calabasas, CA 91302 USA * Web: http://www.ixiacom.com * Phone: 818-871-1800 * Fax: 818-871-1805 * * General Information: * e-mail: info@ixiacom.com * * Technical Support: * e-mail: support@ixiacom.com * * EXAMPLE: Your First Program * * This program creates and runs a simple loopback test using * the File Send, Short Connection script, prints some results, * and saves it to disk. * * All attributes of this test are defined by this program. * ****************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> /* * The header file which defines everything in the Chariot API: * functions, constants, etc. */ #include "../../include/chrapi.h" /* * Local function to print information about errors. */ static void show_error( CHR_HANDLE handle, CHR_API_RC code, CHR_STRING where); /* * Data for the test: * Change these for your local network if desired. */ static CHR_STRING e1 = "localhost"; static CHR_STRING e2 = "localhost"; static CHR_STRING script = "c:/Program Files/Ixia/IxChariot/Scripts/Throughput.scr"; static CHR_STRING testfile = "lbtest.tst"; static CHR_COUNT timeout = 120; /* 2 minutes in seconds */ /************************************************************** * * Program main * * If the return code from any Chariot API function call * is not CHR_OK, the show_error() function is called to * display information about what happened then exit. * * The numbers is parentheses in the comments refer to the * Program Notes section of the Chariot API Programming Guide. * **************************************************************/ void main() { /* * The object handles we‘ll need */ CHR_TEST_HANDLE test = (CHR_TEST_HANDLE)NULL; CHR_PAIR_HANDLE pair = (CHR_PAIR_HANDLE)NULL; /* * Variables and buffers for the attributes and results */ CHR_COUNT pairCount; CHR_PROTOCOL protocol; char addr[CHR_MAX_ADDR]; char scriptName[CHR_MAX_FILENAME]; char applScriptName[CHR_MAX_APPL_SCRIPT_NAME]; CHR_LENGTH len; CHR_COUNT timingRecCount; CHR_FLOAT avg, min, max; /* * Buffer for extended error info for initialization */ char errorInfo[CHR_MAX_ERROR_INFO]; /* * Chariot API return code */ CHR_API_RC rc; /* (1) * You have to initialize the Chariot API * before you can use the functions in it. * This is the only Chariot API function * which includes extended error information * in its calling parameters, since it is * not associated with an object. */ rc = CHR_api_initialize(CHR_DETAIL_LEVEL_ALL, errorInfo, CHR_MAX_ERROR_INFO, &len); if (CHR_OK != rc) { /* * Because initialization failed, we can‘t * ask the API for the message for this * return code, so we can‘t call our * show_error() function. Instead, we‘ll * print what we do know before exiting. */ printf("Initialization failed: rc = %d\n", rc); printf("Extended error info:\n%s\n", errorInfo); } /* (2) * You must create a test object to define a new test * or to load an existing test from disk. */ if (CHR_OK == rc) { printf("Create the test...\n"); rc = CHR_test_new(&test); if (rc != CHR_OK) { show_error((CHR_HANDLE)NULL, rc, "test_new"); } } /* (3) * You must create a pair object in order to define it. */ if (CHR_OK == rc) { printf("Create the pair...\n"); rc = CHR_pair_new(&pair); if (rc != CHR_OK) { show_error((CHR_HANDLE)NULL, rc, "pair_new"); } } /* (4) * Once you have a pair, you can define its attributes. */ if (CHR_OK == rc) { printf("Set required pair attributes...\n"); rc = CHR_pair_set_e1_addr(pair, e1, strlen(e1)); if (rc != CHR_OK) { show_error(pair, rc, "pair_set_e1_addr"); } } if (CHR_OK == rc) { rc = CHR_pair_set_e2_addr(pair, e2, strlen(e2)); if (rc != CHR_OK) { show_error(pair, rc, "pair_set_e2_addr"); } } /* (5) * You must define a script for use in the test. */ if (CHR_OK == rc) { printf("Use a script...\n"); rc = CHR_pair_use_script_filename(pair, script, strlen(script)); if (rc != CHR_OK) { show_error(pair, rc, "pair_use_script_filename"); } } /* (6) * Now that the pair is defined, you can add it to the test. */ if (CHR_OK == rc) { printf("Add the pair to the test...\n"); rc = CHR_test_add_pair(test, pair); if (rc != CHR_OK) { show_error(test, rc, "test_add_pair"); } } /* (7) * We have a test defined, so now we can run it. */ if (CHR_OK == rc) { printf("Run the test...\n"); rc = CHR_test_start(test); if (rc != CHR_OK) { show_error(test, rc, "test_start"); } } /* (8) * We have to wait for the test to stop before we can look * at the results from it. We‘ll wait for 2 minutes here, * then call it an error if it has not yet stopped. */ if (CHR_OK == rc) { printf("Wait for the test to stop...\n"); rc = CHR_test_query_stop(test, timeout); if (rc != CHR_OK) { show_error(test, rc, "test_query_stop"); } } /* (9) * Let‘s print out how we defined the test before printing * results from running it. Since we have the pair handle * from when we created it, we don‘t need to get it from * the test. */ if (CHR_OK == rc) { printf("===========\n"); printf("Test setup:\n----------\n"); rc = CHR_test_get_pair_count(test, &pairCount); if (rc != CHR_OK) { show_error(test, rc, "get_pair_count"); } printf("Number of pairs = %d\n", pairCount); } if (CHR_OK == rc) { rc = CHR_pair_get_e1_addr(pair, addr, CHR_MAX_ADDR, &len); if (rc != CHR_OK) { show_error(pair, rc, "pair_get_e1_addr"); } printf("E1 address : %s\n", addr); } if (CHR_OK == rc) { rc = CHR_pair_get_e2_addr(pair, addr, CHR_MAX_ADDR, &len); if (rc != CHR_OK) { show_error(pair, rc, "pair_get_e2_addr"); } printf("E2 address : %s\n", addr); } /* * We didn‘t set protocol, but let‘s show it anyway . */ if (CHR_OK == rc) { rc = CHR_pair_get_protocol(pair, &protocol); if (rc != CHR_OK) { show_error(pair, rc, "pair_get_protocol"); } printf("Protocol : %d\n", protocol); } /* * We‘ll show both the script filename and * the application script name. */ if (CHR_OK == rc) { rc = CHR_pair_get_script_filename(pair, scriptName, CHR_MAX_FILENAME, &len); if (rc != CHR_OK) { show_error(pair, rc, "pair_get_script_filename"); } printf("Script filename : %s\n", scriptName); } if (CHR_OK == rc) { rc = CHR_pair_get_appl_script_name(pair, applScriptName, CHR_MAX_APPL_SCRIPT_NAME, &len); if (rc != CHR_OK) { show_error(pair, rc, "pair_get_appl_script_name"); } printf("Appl script name: %s\n", applScriptName); } /* (10) * Now let‘s get some results: * the number of timing records and * the throughput (avg, min, max), */ if (CHR_OK == rc) { printf("\nTest results:\n------------\n"); rc = CHR_pair_get_timing_record_count(pair, &timingRecCount); if (rc != CHR_OK) { show_error(pair, rc, "pair_get_timing_record_count"); } printf("Number of timing records = %d\n", timingRecCount); } /* (11) * We‘re not going to check for NO_SUCH_VALUE here * although we should. This return code signals that * the requested result is not available for this * particular test. These kinds of results are shown * as "n/a" in the Chariot console display. In this case, * though, we should be able to get throughput. we‘ll call * any other return code except CHR_OK an error. */ if (CHR_OK == rc) { rc = CHR_pair_results_get_average(pair, CHR_RESULTS_THROUGHPUT, &avg); if (rc != CHR_OK) { show_error(pair, rc, "pair_results_get_average"); } } if (CHR_OK == rc) { rc = CHR_pair_results_get_minimum(pair, CHR_RESULTS_THROUGHPUT, &min); if (rc != CHR_OK) { show_error(pair, rc, "pair_results_get_minimum"); } } if (CHR_OK == rc) { rc = CHR_pair_results_get_maximum(pair, CHR_RESULTS_THROUGHPUT, &max); if (rc != CHR_OK) { show_error(pair, rc, "pair_results_get_maximum"); } /* * We‘ll format these to look like the way the Chariot * console displays these kinds of numbers. */ printf("Throughput:\n avg %.3f min %.3f max %.3f\n", avg, min, max); } /* (12) * Finally, let‘s save the test so we can look at it again. * We have to set the filename before we can save it. */ if (CHR_OK == rc) { printf("==========\nSave the test...\n"); rc = CHR_test_set_filename(test, testfile, strlen(testfile)); if (rc != CHR_OK) { show_error(test, rc, "test_set_filename"); } else { rc = CHR_test_save(test); } if (rc != CHR_OK) { show_error(test, rc, "test_save"); } } /* (13) * Explicitly free allocated resources */ if ( pair != (CHR_PAIR_HANDLE)NULL ) { CHR_pair_delete(pair); } if ( test != (CHR_TEST_HANDLE)NULL ) { CHR_test_delete(test); } /* * Exit test with success or error code. */ exit(rc); } /************************************************************** * * Print information about an error and exit. * * Parameters: handle - what object had the error * code - the Chariot API return code * where - what function call failed * **************************************************************/ static void show_error( CHR_HANDLE handle, CHR_API_RC code, CHR_STRING where) { char msg[CHR_MAX_RETURN_MSG]; CHR_LENGTH msgLen; char errorInfo[CHR_MAX_ERROR_INFO]; CHR_LENGTH errorLen; CHR_API_RC rc; /* * Get the API message for this return code. */ rc = CHR_api_get_return_msg(code, msg, CHR_MAX_RETURN_MSG, &msgLen); if (rc != CHR_OK) { /* Could not get the message: show why */ printf("%s failed\n", where); printf( "Unable to get message for return code %d, rc = %d\n", code, rc); } else { /* Tell the user about the error */ printf("%s failed: rc = %d (%s)\n", where, code, msg); } /* * See if there is extended error information available. * It‘s meaningful only after some error returns. After * failed "new" function calls, we don‘t have a handle so * we cannot check for extended error information. */ if ((code == CHR_OPERATION_FAILED || code == CHR_OBJECT_INVALID || code == CHR_APP_GROUP_INVALID) && handle != (CHR_HANDLE)NULL) { rc = CHR_common_error_get_info(handle, CHR_DETAIL_LEVEL_ALL, errorInfo, CHR_MAX_ERROR_INFO, &errorLen); if (rc == CHR_OK) { /* * We can ignore all non-success return codes here * because most should not occur (the api‘s been * initialized, the handle is good, the buffer * pointer is valid, and the detail level is okay), * and the NO_SUCH_VALUE return code here means * there is no info available. */ printf("Extended error info:\n%s\n", errorInfo); } } }