Explorar el Código

add tarscpp files

root hace 5 años
commit
711a5ed70c
Se han modificado 100 ficheros con 10131 adiciones y 0 borrados
  1. 3 0
      .gitmodules
  2. 32 0
      CMakeLists.txt
  3. 33 0
      README.md
  4. 24 0
      README.zh.md
  5. 177 0
      docs-en/tars_cpp_develop_specification.md
  6. 52 0
      docs-en/tars_cpp_faq.md
  7. 92 0
      docs-en/tars_cpp_future_promise.md
  8. 236 0
      docs-en/tars_cpp_http_demo.md
  9. 518 0
      docs-en/tars_cpp_quickstart.md
  10. 73 0
      docs-en/tars_cpp_server_thread.md
  11. 1359 0
      docs-en/tars_cpp_user_guide.md
  12. 47 0
      docs-en/tars_protobuf_cpp.md
  13. 685 0
      docs-en/tars_push.md
  14. BIN
      docs/images/tars_cpp_quickstart_bushu1.png
  15. BIN
      docs/images/tars_cpp_quickstart_bushu2.png
  16. BIN
      docs/images/tars_cpp_quickstart_patch.png
  17. BIN
      docs/images/tars_cpp_quickstart_patchresult.png
  18. BIN
      docs/images/tars_cpp_quickstart_upload.png
  19. BIN
      docs/images/tars_cpp_third_protocol.png
  20. BIN
      docs/images/tars_web_index.png
  21. 178 0
      docs/tars_cpp_develop_specification.md
  22. 52 0
      docs/tars_cpp_faq.md
  23. 88 0
      docs/tars_cpp_future_promise.md
  24. 237 0
      docs/tars_cpp_http_demo.md
  25. 486 0
      docs/tars_cpp_quickstart.md
  26. 74 0
      docs/tars_cpp_server_thread.md
  27. 1341 0
      docs/tars_cpp_user_guide.md
  28. 44 0
      docs/tars_protobuf_cpp.md
  29. 684 0
      docs/tars_push.md
  30. 14 0
      examples/CoroutineDemo/AServer/AServant.tars
  31. 56 0
      examples/CoroutineDemo/AServer/AServantImp.cpp
  32. 58 0
      examples/CoroutineDemo/AServer/AServantImp.h
  33. 58 0
      examples/CoroutineDemo/AServer/AServer.cpp
  34. 51 0
      examples/CoroutineDemo/AServer/AServer.h
  35. 12 0
      examples/CoroutineDemo/AServer/makefile
  36. 14 0
      examples/CoroutineDemo/BServer/AServant.tars
  37. 15 0
      examples/CoroutineDemo/BServer/BServant.tars
  38. 140 0
      examples/CoroutineDemo/BServer/BServantImp.cpp
  39. 62 0
      examples/CoroutineDemo/BServer/BServantImp.h
  40. 55 0
      examples/CoroutineDemo/BServer/BServer.cpp
  41. 51 0
      examples/CoroutineDemo/BServer/BServer.h
  42. 12 0
      examples/CoroutineDemo/BServer/makefile
  43. 7 0
      examples/CoroutineDemo/README.md
  44. 15 0
      examples/CoroutineDemo/client/BServant.tars
  45. 144 0
      examples/CoroutineDemo/client/main.cpp
  46. 12 0
      examples/CoroutineDemo/client/makefile
  47. 15 0
      examples/CoroutineDemo/testCoro/BServant.tars
  48. 107 0
      examples/CoroutineDemo/testCoro/main.cpp
  49. 12 0
      examples/CoroutineDemo/testCoro/makefile
  50. 15 0
      examples/CoroutineDemo/testParallelCoro/BServant.tars
  51. 276 0
      examples/CoroutineDemo/testParallelCoro/main.cpp
  52. 12 0
      examples/CoroutineDemo/testParallelCoro/makefile
  53. 175 0
      examples/HttpDemo/HttpClient/main.cpp
  54. 16 0
      examples/HttpDemo/HttpClient/makefile
  55. 49 0
      examples/HttpDemo/HttpServer/HttpImp.cpp
  56. 51 0
      examples/HttpDemo/HttpServer/HttpImp.h
  57. 98 0
      examples/HttpDemo/HttpServer/HttpServer.cpp
  58. 50 0
      examples/HttpDemo/HttpServer/HttpServer.h
  59. 14 0
      examples/HttpDemo/HttpServer/makefile
  60. 27 0
      examples/PromiseDemo/AServer/AServant.tars
  61. 252 0
      examples/PromiseDemo/AServer/AServantImp.cpp
  62. 63 0
      examples/PromiseDemo/AServer/AServantImp.h
  63. 57 0
      examples/PromiseDemo/AServer/AServer.cpp
  64. 52 0
      examples/PromiseDemo/AServer/AServer.h
  65. 25 0
      examples/PromiseDemo/AServer/BServant.tars
  66. 25 0
      examples/PromiseDemo/AServer/CServant.tars
  67. 12 0
      examples/PromiseDemo/AServer/makefile
  68. 25 0
      examples/PromiseDemo/BServer/BServant.tars
  69. 45 0
      examples/PromiseDemo/BServer/BServantImp.cpp
  70. 40 0
      examples/PromiseDemo/BServer/BServantImp.h
  71. 57 0
      examples/PromiseDemo/BServer/BServer.cpp
  72. 52 0
      examples/PromiseDemo/BServer/BServer.h
  73. 11 0
      examples/PromiseDemo/BServer/makefile
  74. 25 0
      examples/PromiseDemo/CServer/CServant.tars
  75. 45 0
      examples/PromiseDemo/CServer/CServantImp.cpp
  76. 40 0
      examples/PromiseDemo/CServer/CServantImp.h
  77. 57 0
      examples/PromiseDemo/CServer/CServer.cpp
  78. 53 0
      examples/PromiseDemo/CServer/CServer.h
  79. 11 0
      examples/PromiseDemo/CServer/makefile
  80. 138 0
      examples/PromiseDemo/Client/main.cpp
  81. 13 0
      examples/PromiseDemo/Client/makefile
  82. 6 0
      examples/PromiseDemo/README.md
  83. 13 0
      examples/PushDemo/PushClient/Makefile
  84. 162 0
      examples/PushDemo/PushClient/TestRecvThread.cpp
  85. 28 0
      examples/PushDemo/PushClient/TestRecvThread.h
  86. 30 0
      examples/PushDemo/PushClient/main.cpp
  87. 55 0
      examples/PushDemo/PushServer/TestPushServantImp.cpp
  88. 43 0
      examples/PushDemo/PushServer/TestPushServantImp.h
  89. 83 0
      examples/PushDemo/PushServer/TestPushServer.cpp
  90. 41 0
      examples/PushDemo/PushServer/TestPushServer.h
  91. 67 0
      examples/PushDemo/PushServer/TestPushThread.cpp
  92. 31 0
      examples/PushDemo/PushServer/TestPushThread.h
  93. 17 0
      examples/PushDemo/PushServer/makefile
  94. 7 0
      examples/PushDemo/README.md
  95. 80 0
      examples/QuickStartDemo/HelloServer/AsyncClient/main.cpp
  96. 16 0
      examples/QuickStartDemo/HelloServer/AsyncClient/makefile
  97. 62 0
      examples/QuickStartDemo/HelloServer/Client/main.cpp
  98. 16 0
      examples/QuickStartDemo/HelloServer/Client/makefile
  99. 26 0
      examples/QuickStartDemo/HelloServer/Hello.tars
  100. 42 0
      examples/QuickStartDemo/HelloServer/HelloImp.cpp

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "servant/protocol"]
+	path = servant/protocol
+	url = https://github.com/TarsCloud/TarsProtocol.git

+ 32 - 0
CMakeLists.txt

@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(tars_cpp)
+
+set(CMAKE_VERBOSE_MAKEFILE off)
+
+set(MYSQL_DIR_INC "/usr/local/mysql/include")
+set(MYSQL_DIR_LIB "/usr/local/mysql/lib")
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O2 -Wall -Wno-deprecated")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -Wall -Wno-deprecated")
+
+#set(CMAKE_BUILD_TYPE "Debug")
+
+set(TARS_VERSION "1.1.0")
+add_definitions(-DTARS_VERSION="${TARS_VERSION}")
+set(TARS_SSL 0)
+add_definitions(-DTARS_SSL=${TARS_SSL})
+set(TARS_HTTP2 0)
+add_definitions(-DTARS_HTTP2=${TARS_HTTP2})
+
+set(INSTALL_PREFIX "/usr/local/tars/cpp")
+
+set(CMAKE_INSTALL_PREFIX ${INSTALL_PREFIX})
+
+add_subdirectory(util)
+add_subdirectory(tools)
+
+set(TARS2CPP "${tools_BINARY_DIR}/tars2cpp/tars2cpp")
+
+add_subdirectory(servant)
+

+ 33 - 0
README.md

@@ -0,0 +1,33 @@
+[点我查看中文版](README.zh.md)
+
+This project is the source code of the Tars RPC framework C++ language.
+
+Directory |Features
+------------------|----------------
+servant      |Source code implementation of C++ language framework rpc
+tools        |Source code implementation of C++ language framework IDL tool
+util         |Source code implementation of C++ language framework basic tool library
+examples     |Sample code for the C++ language framework, including: quick start examples, introduction to promise programming, examples of pressure test programs
+test         |Test procedures for various parts of the C++ language framework
+docs         |Document description
+docs-en      |English document description
+
+Dependent environment
+
+Software |version requirements
+------|--------
+linux kernel:   |	2.6.18 and above
+gcc:          	|   4.1.2 and above glibc-devel
+bison tool:     |	2.5 and above
+flex tool:      |	2.5 and above
+cmake:       	|   2.8.8 and above
+mysql:          |	4.1.17 and above
+
+Compile and install
+```
+cmake .
+make
+make install
+```
+
+Detailed installation reference Install.md

+ 24 - 0
README.zh.md

@@ -0,0 +1,24 @@
+该工程是Tars RPC框架C++语言的源代码
+
+目录名称 |功能
+------------------|----------------
+servant      |C++语言框架rpc的源码实现
+tools        |C++语言框架IDL工具的源码实现
+util         |C++语言框架基础工具库的源码实现
+examples     |C++语言框架的示例代码,包括:快速入门示例、promise编程入门示例、压测程序示例
+test         |C++语言框架各个部分的测试程序
+docs         |文档说明
+docs-en      |英文文档说明
+
+依赖环境
+
+软件 |软件要求
+------|--------
+linux内核版本:      |	2.6.18及以上版本
+gcc版本:          	|   4.1.2及以上版本、glibc-devel
+bison工具版本:      |	2.5及以上版本
+flex工具版本:       |	2.5及以上版本
+cmake版本:       	|   2.8.8及以上版本
+mysql版本:         |	4.1.17及以上版本
+
+详细安装参见Install.md

+ 177 - 0
docs-en/tars_cpp_develop_specification.md

@@ -0,0 +1,177 @@
+# Table of Contents
+> * Naming convention
+> * Tars File Directory Specification
+> * Makefile specification
+
+# 1. Naming convention
+
+## 1.1. Service naming
+
+APP: The application name, which identifies a small collection of services. In the Tars system, the application name must be unique. For example: TestApp.
+
+Server: service name, the name of the process that provides the service. The server name is named according to the service service function. It is generally named: XXServer, such as LogServer, TimerServer, etc.
+
+Servant: A service provider that provides an interface or instance of a specific service. For example: HelloImp
+
+Description:
+
+A Server can contain multiple Servant, the system will use the service's App + Server + Servant, combined to define the routing name of the service in the system, called routing Obj, its name must be unique in the whole system, so that when you serve externally, you can uniquely identify yourself.
+
+Therefore, when defining an APP, you need to pay attention to the uniqueness of the APP.
+
+For example: Comm.TimerServer.TimerObj, Comm.LogServer.LogServerObj, etc.;
+
+## 1.2. Namespace naming
+
+Each business has a different name, the Application name, which is also used as the namespace for all code under the Application.
+
+Therefore, the namespace is generally the name of the business, for example:
+```
+namespace Comm
+```
+## 1.3. Class name (interface name)
+
+The name of the class must consist of one or more words or abbreviations that express the meaning of the class. The first letter of the word is capitalized.
+
+E.g:
+```
+class HelloWorldApp
+```
+
+## 1.4. Method naming
+
+The naming of functions is based on the principle of expressing the action of a function. It is usually started by a verb and then followed by a noun that represents the action object. Beginning with a lowercase letter, the first letter of each word is capitalized.
+
+In addition, there are some general function naming rules.
+
+Get number start with 'get', then keep up with the name of the object to be fetched;
+
+Setting start with 'set', and then keep up with the name of the object to be set;
+
+The function that responds to the message in the object, starting with 'on', and then the name of the corresponding message;
+
+The function that performs the active action can start with 'do', and then the corresponding action name;
+
+Use 'has' or 'can' instead of the 'is' prefix of the boolean get function, the meaning is more clear.
+
+E.g:
+```
+getNumber();
+
+setNumber();
+
+onProcess();
+
+doAddFile();
+
+hasFile();
+
+canPrint();
+
+sendMessage();
+```
+
+## 1.5. Variable naming rules
+
+For the definition of various variables, there is one thing in common, that is, you should use meaningful English words or English word abbreviations, do not use simple meaningless strings, try not to use Arabic numerals, and should not use the initial of Chinese Pinyin.
+
+Names like this are not recommended: Value1, Value2, Value3, Value4....
+
+The general rule is: lowercase letters begin, followed by each word whose first letter is uppercase, usually a noun. (if there is only one word, lowercase)
+
+userNo (mobile number), station (province), destNo (destination number), srcNo (source number), etc.
+
+Other: For some more important numbers, it is best to use constant substitution instead of writing numbers directly. The constants are all uppercase, and multiple words are separated by underscores.
+
+NUMBER_OF_GIRLFRIENDS
+
+# 2. Tars file directory specification
+
+The Tars file is the protocol communication interface of the TARS service, so it is very important to be managed in accordance with the following specifications:
+
+The tars file is in principle placed with the corresponding server;
+
+Each server creates a /home/tarsproto/[namespace]/[server] subdirectory on the development machine;
+
+All tars files need to be updated to the corresponding server directory under /home/tarsproto;
+
+When using other server tars files, you need to use them in /home/tarsproto, you can't copy them to this directory, see Makefile specification;
+
+The tars interface can only be added in principle and cannot be reduced or modified.
+
+Run 'make release' inside the makefile will automatically complete the relevant operations, see the Makefile specification;
+
+Description:
+
+'make release' will copy the tars file to /home/tarsproto/[namespace]/[server] directory, generate tars2cpp to generate .h, and generate a [server].mk file; When others call this service, include this mk file at the bottom of the makefile.
+
+# 3. Makefile specification
+
+It is highly recommended to use the Makefile specification when use service that realized with Tars.
+
+The TARS framework provides a basic Makefile for makefile.tars. The service written in Tars contains the Makefile to help you maintain the Makefile.
+
+The TARS framework also provides a script (installation directory /script/create_tars_server.sh) to automatically generate an empty service framework and Makefile;
+
+## 3.1. Makefile usage principle
+
+In principle, a directory can only be a Server or a program, that is, a Makefile can only have one Target;
+
+When you need to include other libraries, include them in the bottom of the Makefile according to the dependency order;
+
+E.g:
+```
+include /home/tarsproto/TestApp/HelloServer/HelloServer.mk
+include /usr/local/tars/cpp/makefile/makefile.tars
+```
+Makefile.tars must be included.
+
+## 3.2. Makefile template explanation
+
+APP: the name space of the program (ie Application)
+
+TARGET: Server name;
+
+CONFIG: The name of the configuration file. When you make tar, the file is included in the tarball.
+
+INCLUDE: Other paths that need to be included;
+
+LIB: Required Library
+
+The Makefile for Test.HelloServer is as follows:
+```
+#------------------------------------------------- ----------------------
+
+APP            := TestApp
+TARGET         := HelloServer
+CONFIG         := HelloServer.conf
+STRIP_FLAG     := N
+TARS2CPP_FLAG  :=
+
+INCLUDE        +=
+LIB            +=
+
+#------------------------------------------------- ----------------------
+
+Include /home/tarsproto/TestApp/HelloServer/HelloServer.mk
+Include /usr/local/tars/cpp/makefile/makefile.tars
+```
+The key variables are usually not used, but the business can add its own values after these variables:
+```
+RELEASE_TARS: You need to publish the tars file in the /home/tarsproto/ directory. If you need to publish your own .h to /home/tarsproto, you can do the following:
+RELEASE_TARS += xxx.h
+CONFIG: The name of the configuration file. In fact, you can add the files you need later, so that the file will be included in the tarball when you call make tar.
+```
+For other variables, please read makefile.tars.
+
+## 3.3. Makefile use
+
+make help: You can see all the functions of the makefile.
+
+make tar: generate a release file
+
+make release: copy the tars file to the /home/tarsproto directory and automatically generate the relevant mk file
+
+make clean: clear
+
+make cleanall: clear all

+ 52 - 0
docs-en/tars_cpp_faq.md

@@ -0,0 +1,52 @@
+
+1. How to build the Tars C++ development environment?
+> * Please reference tars_install.md
+
+2. How to quickly implement an example of a Tars C++?
+> * For documentation, please refer to tars_cpp_quickstart.md, the relevant sample code, and the cpp/examples directory.
+
+3. What is the tars/tup protocol?
+> * For specific information, please refer to tars_tup.md.
+
+4. Does Tars C++ support custom protocols (such as: HTTP)?
+> * In addition to supporting tars/tup protocol, Tars C++ also supports business custom protocols. Please refer to tars_cpp_thirdprotocol.md for more details.
+
+5. How does Tars C++ pull the business configuration file?
+> * Tars C++ supports obtaining the specified business configuration file by using the addConfig method. The specific usage of business configuration can be referred to tars_config.md.
+
+6. How is the service running in the Tars framework monitored?
+> * For specific information, please refer to tars_server_monitor.md
+
+7. How to create a Tars C++ communicator?
+> * If the service is based on the TAF framework, please get it directly from Applicatin and do not create it by yourself. For example:
+```
+Application::getCommunicator()->stringToProxy<NotifyPrx>(ServerConfig::Notify);
+```
+> * If the service is not based on the TAF framework, just the TAF client, you can initialize communicator with new Communicator (CONF). For example:
+``` 
+TC_Config conf(“config.conf”);
+CommunicatorPtr c = new Communicator(conf);
+```
+
+8. How to set the timeout time of the Tars C++ invoke?
+> * For more details, please refer to tars_cpp_user_guide.md
+
+9. After the service is released but not running, how can we find out the reason?
+> * Whether the service configuration file is not properly obtained. For example, the configuration file name configured on the web platform is inconsistent with the configuration file name that was downloaded from the program add.
+> * When looking for a problem, first look at whether the "service current report" on web is prompted to be normal, for example: a configuration file has a configuration file that has not been downloaded successfully, and the service is downloaded when it is started.
+> * Look for the log log that you print for the service. Logs are usually in the /usr/local/app/tars/app_log/ application name/service name/directory.
+> * If there is still a problem, check the node log.
+
+10. How does the core file be opened and where is it generated?
+> * The core file is opened when the tafnode startup script is added to the ulimite -c unlimited, and the current core file is generated under the /usr/local/app/tars/app_log directory.
+
+11. Does the failure of master Registry affect the normal access of business services?
+> * Without affecting the normal access to business services, the bottom of the framework will cache the IP list of the backend services.
+
+12. How does the communicator Communicator get ip:prot through ServerName?
+> * 1.When the agent is created, it does not ask the master to get the IP list. Instead, it triggers the request area to get the master IP list when calling the proxy's interface.
+> * 2.If there is IP list information behind obj, it is equivalent to direct connection. This will not ask for master registry.
+> * 3.If there is no IP list information behind obj, it is quite indirect and will ask for master registry.
+> * 4.The strategy for requesting master registry: if the local cache has a list of IP for the requested obj, use a local cache of IP lists, and also asynchronously request the master registry to get the latest IP list
+> * 5.The strategy of requesting master registry: if there is no IP list in the local cache that has no cache request obj, the request of the business will be put into the queue, and the master control is requested to get the IP list asynchronously, after getting the IP list, then the request of the service is taken out from the queue and the request is sent.
+> * 6.Instead of refreshing each time and refreshing at regular intervals (default 60s), the trigger for timing refresh is business request.

+ 92 - 0
docs-en/tars_cpp_future_promise.md

@@ -0,0 +1,92 @@
+# Usage of Future/Promise in Tars framework
+
+It will generate the file.h automatically for the file.tars when using tars2cpp tool to generate the C++ file.
+There are four RPC methods for generating your custom interface in the .h file:
+
+*   Synchronous(sync);
+*   Asynchronous(async);
+*   Future/Promise;
+*   Coroutine(coro);
+
+There is sync/async method in the document[samples for use](https://github.com/Tencent/Tars/blob/master/docs/tars_cpp_quickstart.md). 
+It may be helpful to see this article for students who don't meet sync/async and then want to use Future/Promise under Tars.
+The content and examples in the article are based on the Future/Promise provided under the Tars framework, which is not exactly
+the same as the Future/Promise provided by boost, C++11, and other languages.
+
+&nbsp;
+
+## **What is Future/Promise?**
+
+Future and Promise are actually two completely different things:
+
+> Future: Which is used to represent and object that has not yet produced a result, and its behavior that produces this result is asynchronous.
+> 
+> Promise: The object of Future can be created by using the object of Promise(getFuture). The value which saved by object of Promise can be read 
+by the object of Future, and this two objects sharing states are associated. It can be considered that Promise provides a means for the
+synchronization of Future results.
+
+In short: **They provide a set of non-blocking parallel operations. Ofcource, you can also block the operation to wait for the Future result to return**
+
+&nbsp;
+
+## **What scenairo do Future/Promise apply to?**
+
+With a virtual example for explaining: **You will contact the intermediary through wechat to check the market and ask for som information, and finally get all the information summarized and then evaluate if you want to buy a house**
+
+If we have intermediaries A, B, C without considering timeout.
+
+**synchronous approach**: First we ask A with wechat, wait for A's reply, then ask B and wait for B's reply, finally ask C and wait for C's reply;
+
+**asynchronous approach**: First we ask A with wechat, we can do other things(such as watching TV, processing work) while waiting for A to reply. Then we ask B, C after A to reply.
+
+**Future/Promise approach**: We ask A, B, C with wechat at the same time, doing other things while getting all the responses.
+
+**According to experience, Future/Promise is the most appropriate method in this scenario.**
+
+For this scenairo, the interrogation agents A, B, C are three tasks without any coupling(a simple understanding is that the order can be disrupted, and there is no dependency between them, A-&gt;B-&gt;C,C-&gt;B-&gt;A is the same result), so the idea of using Future/Promise is most suitable.
+
+&nbsp;
+
+## **The code example of Future/Promise**
+
+Suppose we have a Test application whose TestServant service inside TestServer provides the interface "EchoTest" of the Echo service.
+
+```cpp
+//omit the corresponding header file
+//callback function
+void handleAll(const promise::Future<promise::Tuple<promise::Future<TestServantPrxCallbackPromise::PromisetestPtr>, 
+                    promise::Future<TestServantPrxCallbackPromise::PromisetestPtr> > > &result)
+{
+    promise::Tuple<promise::Future<TestServantPrxCallbackPromise::PromisetestPtr>, promise::Future<TestServantPrxCallbackPromise::PromisetestPtr> > out = result.get();
+ 
+    promise::Future<TestServantPrxCallbackPromise::PromisetestPtr> out1 = out.get<0>();
+    const tars::TC_AutoPtr<TestServantPrxCallbackPromise::Promisetest> print1 = out1.get();
+ 
+    promise::Future<TestServantPrxCallbackPromise::PromisetestPtr> out2 = out.get<1>();
+    const tars::TC_AutoPtr<TestServantPrxCallbackPromise::Promisetest> print2 = out2.get();
+ 
+    DEBUGLOG("handleAll:" << print1->_ret << "|" << print1->outStr << "|out2:" << print2->_ret << "|" << print2->outStr);
+}
+ 
+int main()
+{
+    map<string, string> ctx;
+    TestServantPrx testPrx = Application::getCommunicator()->stringToProxy<TestServantPrx>("Test.TestServer.TestServant");
+ 
+    promise::Future<TestServantPrxCallbackPromise::PromisetestPtr > result1 = testPrx->promise_async_EchoTest("manmanlu1", ctx);
+    promise::Future<TestServantPrxCallbackPromise::PromisetestPtr > result2 = testPrx->promise_async_EchoTest("manmanlu2", ctx);
+ 
+    promise::Future<promise::Tuple<promise::Future<TestServantPrxCallbackPromise::PromisetestPtr>, promise::Future<TestServantPrxCallbackPromise::PromisetestPtr> > > r =
+        promise::whenAll(result1, result2);
+    r.then(tars::TC_Bind(&handleAll));
+ 
+    DEBUGLOG("Test Future-Promise done");
+}
+```
+The output is:
+```
+Test Future-Promise done
+handleAll:0|manmanlu1|out2:0|manmanlu2
+```
+
+You can see that the asynchronous callback is triggered normally.

+ 236 - 0
docs-en/tars_cpp_http_demo.md

@@ -0,0 +1,236 @@
+# Other protocol support
+ 
+## Overview
+The TARS service framework only supports TARS's own tars protocol by default. However, in actual application scenarios, other protocols, such as HTTP, need to be supported in the TARS service framework. In this case, the communicator cannot be used to send data. The business itself need to implement this part of the code. For custom protocols, the processing is similar.
+
+For specific program examples, see cpp/examples/httpDemo/.
+
+To develop a third-party protocol server end: you need to implement the protocol parser and load it into the service, and establish a non-TAF framework service object meanwhile, this class inherits from the Servant class and establishes the protocol processor by reloading the doRequest method in the Servant class. 
+To access the service, the client needs to call the rpc function of proxy, before calling, set the request packet encoding function and the response packet decoding function for the proxy.
+
+![tars](../docs/images/tars_cpp_third_protocol.png)
+
+The black line in the figure represents the data flow direction: data (client) -> encoder of the request packet (client) -> protocol parser (server) -> doRequest protocol processor (server) -> generate return data (server) -> decoder of the response packet (client) -> response data (client)
+
+The encoder of the request packet (client) is responsible for packaging the data sent by the client, and the protocol parser (server) is responsible for parsing the received data and sending to the protocol processor (server) for processing and generating the return data, and the decoder of the response packet (client) is responsible for decoding the returned data.
+
+## 	Server Http protocol instance
+
+
+/usr/local/tars/cpp/script/create_tars_server.sh TestApp HttpServer Http
+
+Six files will be generated in the directory, delete http.tars (because it is not a tars protocol), and then some methods are manually implemented.
+
+Take HelloServer as an example. You need to support the http protocol.
+
+Modify the doRequest method inherited from the Servant class in HttpImp, which is the processor of the third-party service, this processor is responsible for processing the data sent to it by the protocol parser and generating the response returned to the client.
+
+HttpImp.h
+```cpp
+#ifndef _HttpImp_H_
+#define _HttpImp_H_
+
+#include "servant/Application.h"
+
+/**
+ *
+ *
+ */
+class HttpImp : public Servant
+{
+public:
+    /**
+     *
+     */
+    virtual ~HttpImp() {}
+
+    /**
+     *
+     */
+    virtual void initialize();
+
+    /**
+     *
+     */
+    virtual void destroy();
+
+    /**
+     *
+     */
+    int doRequest(TarsCurrentPtr current, vector<char> &buffer);
+
+};
+/////////////////////////////////////////////////////
+#endif
+```
+HttpImp.cpp
+```cpp
+#include "HttpImp.h"
+#include "servant/Application.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////
+void HttpImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+
+//////////////////////////////////////////////////////
+void HttpImp::destroy()
+{
+    //destroy servant here:
+    //...
+}
+
+int HttpImp::doRequest(TarsCurrentPtr current, vector<char> &buffer)
+{
+    TC_HttpRequest request; 
+    vector<char> v = current->getRequestBuffer();
+    string sBuf;
+    sBuf.assign(&v[0],v.size());
+    request.decode(sBuf);
+    TC_HttpResponse rsp;
+    string s="hello";
+    rsp.setResponse(s.c_str(),s.size());
+    rsp.encode(buffer);
+   
+    return 0;
+}
+```
+
+
+The initialize() function of the HttpServer class is responsible for loading the service object HttpImp and setting the third-party protocol parser parse.
+```cpp
+#ifndef _HttpServer_H_
+#define _HttpServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+
+using namespace tars;
+
+/**
+ *
+ **/
+class HttpServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~HttpServer() {};
+
+    /**
+     *
+     **/
+    virtual void initialize();
+
+    /**
+     *
+     **/
+    virtual void destroyApp();
+};
+
+extern HttpServer g_app;
+
+////////////////////////////////////////////
+#endif
+```
+
+```cpp
+#include "HttpServer.h"
+#include "HttpImp.h"
+
+using namespace std;
+
+HttpServer g_app;
+
+/////////////////////////////////////////////////////////////////
+struct HttpProtocol
+{
+    /**
+     * parse the heep request
+     * @param in
+     * @param out
+     *
+     * @return int
+     */
+    static int parseHttp(string &in, string &out)
+    {
+        try
+        {
+            //determine whether the request is a http request
+            bool b = TC_HttpRequest ::checkRequest(in.c_str(), in.length());
+            //intact http request
+            if(b)
+            {
+                out = in;
+                in  = "";
+                //TLOGDEBUG("out size: " << out.size() << endl);
+                return TC_EpollServer::PACKET_FULL;
+            }
+            else
+            {
+                return TC_EpollServer::PACKET_LESS;
+            }
+        }
+        catch(exception &ex)
+        {
+            return TC_EpollServer::PACKET_ERR;
+        }
+
+        return TC_EpollServer::PACKET_LESS;             //the packet recieved is defective
+    }
+
+};
+
+void
+HttpServer::initialize()
+{
+    //initialize application here:
+    //...
+
+    addServant<HttpImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".HttpObj");
+    addServantProtocol(ServerConfig::Application + "." + ServerConfig::ServerName + ".HttpObj",&HttpProtocol::parseHttp);
+}
+/////////////////////////////////////////////////////////////////
+void
+HttpServer::destroyApp()
+{
+    //destroy application here:
+    //...
+}
+/////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+/////////////////////////////////////////////////////////////////
+```
+
+
+
+
+
+
+
+
+
+
+

+ 518 - 0
docs-en/tars_cpp_quickstart.md

@@ -0,0 +1,518 @@
+# Contents
+> * [1.Environment construction] (#main-chapter-1)
+> * [2.Service naming] (#main-chapter-2)
+> * [3.Tars management system] (#main-chapter-3)
+> * [4.Service deployment] (#main-chapter-4)
+> * [5.Service development] (#main-chapter-5)
+> * [6.Service release] (#main-chapter-6)
+
+# 1. Environment construction  <a id="main-chapter-1"></a>
+
+How to set up the Tars C++ environment, please refer to the article tars_install.md.
+
+# 2. Service naming  <a id="main-chapter-2"></a>
+
+The service name of the Tars framework consists of three parts:
+
+APP:    Application name. it identifies a small set of service. In the Tars system, the app name must be unique. For example: TestApp.
+
+Server: Service name. A process provides service. It's named according to the service function and generally named as XXServer. For example: HelloServer.
+
+Servant:The name of provider. An interface or instance that provides a specific service. For example: HelloImp.
+
+Instructions:
+
+A Server can contain multiple Servant, and the system will use App + Server + Servant combination to define the routing name of the service in the system, called routing object. This name must be unique in the whole system, so that would uniquely identify itself when it externally served.
+
+Therefore, when defining an App, you need pay attention to the uniqueness of the App.
+
+For Example:TestApp.HelloServer.HelloObj.
+
+# 3. Tars management system  <a id="main-chapter-3"></a>
+
+When you login successfully, you will enter the Tars management system, as shown below:
+
+![tars](../docs/images/tars_web_index.png)
+
+Under the menu tree of the Tars management system, the following functions are available:
+
+- Business management: Includes deployed services, service management, release management, service configuration, service monitoring, feature monitoring, etc.
+
+- Operation and maintenance: Includes service deployment, capacity expansion, template management, etc.
+
+# 4. Service deployment   <a id="main-chapter-4"></a>
+
+Service deployment can actually be done after service development, but it is recommended to do it first.
+
+As shown below:
+
+![tars](../docs/images/tars_cpp_quickstart_bushu1.png)
+
+-	"Application" refers to which application your service program belongs to, for example: "TestApp".
+-   "Service name" refers to the identification name of your service program, for example: "HelloServer".
+-	"Service type" refers to the language in which your service program is written, for example: C++ choice "tars_cpp".
+-   "Template" refers to the name of the configuration file that is set when your service program starts. By default, "tars.default" can be used.
+-	"Node" refers to the machine IP on which the service is deployed.
+-   "Set group" refers to the group information of the set service. The Set information includes 3 parts: Set name, Set area, Set group name.
+-   "OBJ name" refers to the name of the Servant
+-   "OBJ binding IP" refers to the IP that is bound to the service, generally the same as the node.
+-   "port" refers to the port to which OBJ is bounded.
+-   "Port type" refers to Tcp or Udp.
+-   "Protocol" refers to the communication protocol used by the application layer. The Tars framework uses the tars protocol by default.
+-   "Number of Threads" refers to the number of business processing threads.
+-   "Maximum number of connections" refers to the maximum number of connections supported.
+-   "Maximum queue length" refers to the size of the request receiving queue.
+-   "Queue timeout" refers to the timeout period for requesting receive queue.
+
+Click "Submit", after success, the TestApp application under the menu will display the name of the HelloServer, and you will see the information of the new service program on the right side, as shown below.
+
+![tars](../docs/images/tars_cpp_quickstart_bushu2.png)
+
+The deployment on the management system is temporarily completed, so far, it just makes your service occupy a position on the management system, the real program has not been released yet.
+
+# 5. Service development  <a id="main-chapter-5"></a>
+
+## 5.1. Create service
+
+### 5.1.1. Run Tars script
+
+``` shell
+/usr/local/tars/cpp/script/create_tars_server.sh [App] [Server] [Servant]
+```
+
+Executed in this example:/usr/local/tars/cpp/script/create_tars_server.sh TestApp HelloServer Hello
+
+After the command is executed, the following file will be generated in the "TestApp/HelloServer/" of the current directory.
+
+``` shell
+HelloServer.h HelloServer.cpp Hello.tars HelloImp.h HelloImp.cpp makefile
+```
+
+These files already contain the most basic service framework and default test interface implementation.
+
+### 5.1.2. Tars interface file
+
+For the syntax and usage of the tars interface file, see tars_tup.md.
+
+As follows:
+
+Hello.tars:
+
+``` cpp
+module TestApp
+{
+
+interface Hello
+{
+    int test();
+};
+
+}; 
+```
+
+Automatically generate C++ files using the tars2cpp tool:
+
+``` shell
+/usr/local/tars/cpp/tools/tars2cpp hello.tars
+``` 
+
+Running this command will generate a hello.h file containing the client and server code.
+
+### 5.1.3. HelloImp is the interface implementation class of Servant
+
+Implement the interface test in file Hello.tars, as follows:
+
+HelloImp.h
+
+``` cpp
+
+#ifndef _HelloImp_H_
+#define _HelloImp_H_
+
+#include "servant/Application.h"
+#include "Hello.h"
+
+/**
+ * HelloImp inherits the Hello object defined in hello.h
+ *
+ */
+class HelloImp : public TestApp::Hello
+{
+public:
+    /**
+     *
+     */
+    virtual ~HelloImp() {}
+
+    /**
+     * Initialization, Hello's virtual function, called when HelloImp is initialized
+     */
+    virtual void initialize();
+
+    /**
+     * Destructor, Hello's virtual function, called when HelloImp exits
+     */
+    virtual void destroy();
+
+    /**
+     * Implement the test interface defined in the Tars file
+     */
+    virtual int test(tars::TarsCurrentPtr current) { return 0;};
+
+};
+/////////////////////////////////////////////////////
+#endif
+
+```
+
+HelloImp.cpp:
+
+``` cpp
+
+#include "HelloImp.h"
+#include "servant/Application.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////
+void HelloImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+
+//////////////////////////////////////////////////////
+void HelloImp::destroy()
+{
+    //destroy servant here:
+    //...
+}
+
+```
+
+### 5.1.4. HelloServer is the implementation class of the service
+
+As follows:
+
+HelloServer.h:
+
+``` cpp
+#ifndef _HelloServer_H_
+#define _HelloServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+
+using namespace tars;
+
+/**
+ * HelloServer inherits from the Application class in the Tars framework
+ **/
+class HelloServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~HelloServer() {};
+
+    /**
+     * Service initialization interface
+     **/
+    virtual void initialize();
+
+    /**
+     * Cleanup interface when the service exitsd
+     **/
+    virtual void destroyApp();
+};
+
+extern HelloServer g_app;
+
+////////////////////////////////////////////
+#endif
+
+```
+
+HelloServer.cpp:
+
+```cpp
+#include "HelloServer.h"
+#include "HelloImp.h"
+
+using namespace std;
+
+HelloServer g_app;
+
+/////////////////////////////////////////////////////////////////
+void
+HelloServer::initialize()
+{
+    //initialize application here:
+
+    //Add the binding relationship between the HelloImp and the route Obj.
+    addServant<HelloImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".HelloObj");
+}
+/////////////////////////////////////////////////////////////////
+void
+HelloServer::destroyApp()
+{
+    //destroy application here:
+    //...
+}
+/////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+/////////////////////////////////////////////////////////////////
+
+```
+
+## 5.2. Compile
+
+Enter the code directory, first do:
+
+``` shell
+make cleanall
+make	
+make tar
+``` 
+
+## 5.3. Extensions
+
+The Tars framework provides an interface definition language that can be used in tars files to add interfaces and methods to extend the functionality of the service.
+
+You can modify the tars file generated by create_tars_server.sh. In the following two interface methods, test is generated by default, and testHello is the newly added interface.
+
+``` cpp
+module TestApp
+{
+
+interface Hello
+{
+    int test();
+    int testHello(string sReq, out string sRsp);
+};
+
+}; 
+```
+
+using /usr/local/tars/cpp/tools/tars2cpp hello.tars regenerate hello.h.
+
+Modify HelloImp.h/HelloImp.cpp to implement the new interface code.
+
+The testHello method that inherits the Hello class from HelloImp.h:
+
+``` cpp
+virtual int testHello(const std::string &sReq, std::string &sRsp, tars::TarsCurrentPtr current);
+```
+
+HelloImp.cpp implements the testHello method:
+
+```cpp
+int HelloImp::testHello(const std::string &sReq, std::string &sRsp, tars::TarsCurrentPtr current)
+{
+    TLOGDEBUG("HelloImp::testHellosReq:"<<sReq<<endl);
+    sRsp = sReq;
+    return 0;
+}
+```
+Re-execute the following command to compile: 
+
+``` shell
+make cleanall
+make
+make tar
+```
+
+it will regenerate the HelloServer.tgz release package.
+
+## 5.4. Client synchronous/asynchronous call service
+
+On the development environment, create the /home/tarsproto/[APP]/[Server] directory.
+
+For the example above:/home/tarsproto/TestApp/HelloServer.
+
+Executing the command:
+``` shell
+make release 
+```
+it will generate .h, .tars and .mk files in the /home/tarsproto/TestApp/HelloServer directory.
+
+In this way, when a service needs to access the HelloServer, it directly references the above file, and does not need to copy the .tars file of the HelloServer (that is, the tars file of the HelloServer does not need to be stored in the code directory).
+
+Create a client code directory, like TestHelloClient/
+
+Write file main.cpp, create an instance and call the interface function just written to test.
+
+Synchronously:
+
+```cpp
+#include <iostream>
+#include "servant/Communicator.h"
+#include "Hello.h"
+
+using namespace std;
+using namespace TestApp;
+using namespace tars;
+
+int main(int argc,char ** argv)
+{
+    Communicator comm;
+
+    try
+    {
+        HelloPrx prx;
+        comm.stringToProxy("TestApp.HelloServer.HelloObj@tcp -h 10.120.129.226 -p 20001" , prx);
+
+        try
+        {
+            string sReq("hello world");
+            string sRsp("");
+
+            int iRet = prx->testHello(sReq, sRsp);
+            cout<<"iRet:"<<iRet<<" sReq:"<<sReq<<" sRsp:"<<sRsp<<endl;
+
+        }
+        catch(exception &ex)
+        {
+            cerr << "ex:" << ex.what() << endl;
+        }
+        catch(...)
+        {
+            cerr << "unknown exception." << endl;
+        }
+    }
+    catch(exception& e)
+    {
+        cerr << "exception:" << e.what() << endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << endl;
+    }
+
+    return 0;
+}
+```
+
+Asynchronous:
+
+```cpp
+#include <iostream>
+#include "servant/Communicator.h"
+#include "Hello.h"
+
+using namespace std;
+using namespace TestApp;
+using namespace tars;
+
+class HelloCallBack : public HelloPrxCallback
+{
+public:
+    HelloCallBack(){}
+
+    virtual ~HelloCallBack(){}
+
+    virtual void callback_testHello(tars::Int32 ret,  const std::string& sRsp)
+    {
+        cout<<"callback_testHello ret:"<< ret << "|sRsp:" << sRsp <<endl; 
+    }
+
+    virtual void callback_testHello_exception(tars::Int32 ret)
+    {
+        cout<<"callback_testHello_exception ret:"<< ret <<endl;
+    }
+};
+
+int main(int argc,char ** argv)
+{
+    Communicator comm;
+
+    try
+    {
+        HelloPrx prx;
+        comm.stringToProxy("TestApp.HelloServer.HelloObj@tcp -h 10.120.129.226 -p 20001" , prx);
+
+        try
+        {
+            string sReq("hello world");
+            HelloPrxCallbackPtr cb = new HelloCallBack();
+            prx->async_testHello(cb, sReq);
+            cout<<" sReq:"<<sReq<<endl;
+        }
+        catch(exception &ex)
+        {
+            cerr<<"ex:"<<ex.what() <<endl;
+        }
+        catch(...)
+        {
+            cerr<<"unknown exception."<<endl;
+        }
+    }
+    catch(exception& e)
+    {
+        cerr<<"exception:"<<e.what() <<endl;
+    }
+    catch (...)
+    {
+        cerr<<"unknown exception."<<endl;
+    }
+
+    getchar();
+
+    return 0;
+}
+```
+
+Edit the makefile, which contains the mk file in the /home/tarsproto/[APP]/[Server] directory that was just generated by make release, as follows:
+
+```makefile
+#-----------------------------------------------------------------------
+APP         :=TestApp
+TARGET      :=TestHelloClient
+CONFIG      :=
+STRIP_FLAG  := N
+
+INCLUDE     += 
+LIB         +=
+#-----------------------------------------------------------------------
+include /home/tarsproto/TestApp/HelloServer/HelloServer.mk
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------
+```
+
+Make the target file, upload it to the environment where you can access the server and run the test.
+
+
+# 6. Service release  <a id="main-chapter-6"></a>
+In the menu tree of the management system, find the service you deployed, click to enter the service page.
+
+first Select "Publish Management", then select the node to be published, then click "Publish Selected Node", and finally click "Upload Release Package", select the compiled package. As shown below:
+
+![tars](../docs/images/tars_cpp_quickstart_upload.png)
+
+ After the upload is successful, click the "Select Release Version" drop-down box and the service program you uploaded will appear. Select the top one (latest uploaded). As shown below:
+
+ ![tars](../docs/images/tars_cpp_quickstart_patch.png)
+
+ Click "Publish", the service starts to be released, after the release is successful, the following interface appears, as shown below:
+
+ ![tars](../docs/images/tars_cpp_quickstart_patchresult.png)
+ 
+If it fails, it may be a naming problem, an upload problem, and other environmental issues.

+ 73 - 0
docs-en/tars_cpp_server_thread.md

@@ -0,0 +1,73 @@
+# Contents
+> * Overview
+> * Service thread type of Tars(C++) service
+> * Analyzing the tasks of running threads
+> * Method of changing the number of threads
+
+# 1. Overview
+
+The Tars(C++) service is a single-process, multi-threaded RPC system. This article describes the number of threads that a standard Tars(C++) service starts, and the responsibilities of each thread.
+
+# 2. Service thread type of Tars(C++) service
+
+Starter |Thread function|Number of threads
+------|--------|-----
+SERVER |Server main thread, responsible for server initialization|1
+SERVER|Server network thread, responsible for sending and receiving data packets on the server (the number of threads is configurable)|Configurable
+SERVER|Server-side thread that listens on the port to run business logic, responsible for accepting and processing user-defined commands, service shutdown commands, etc.|1
+SERVER|Thread that assists the user in getting time, responsible for periodically calculating time and reducing system calls to gettimeofday|1
+SERVER|Thread used to scroll the log, responsible for local log file creation and log writing|1
+SERVER|Local log thread, responsible for file creation and log writing of local dyed logs (This thread will start if there is a daily print log or related initialization.)|1
+SERVER|Remote log thread, responsible for synchronizing the local dyed log to the remote (This thread will start if there is a daily print log or related initialization.)|1
+SERVER|Business processing thread, responsible for processing user business logic and completing the main functions of the RPC service. (Each ServantObj has its own business processing threads by default, but the business processing threads can also be shared.)|Configurable
+Communicator|Client network thread, responsible for managing socket connections, listening for read and write events, and completing network read and write|Configurable
+Communicator|Thread for statistical attribute reporting, responsible for collecting statistics and attribute information, and timing synchronization to stat and property.|1
+Communicator|Asynchronous callback thread, responsible for executing asynchronous callback function, each network thread of the client has its own asynchronous thread|Configurable
+
+# 3. Analyzing the tasks of running threads
+
+From a running Tars service application, we look at the characteristics of each thread and make a distinction between the various thread functions.
+
+Experimental scene:
+
+> * The server is configured with one ServantObj, which is configured with five business processing threads.
+
+> * The server is configured with one network thread.
+
+> * The communicator is configured with two network threads.
+
+> * The communicator is configured with two asynchronous callback thread.
+
+According to the thread startup configuration described above, this service should have:
+
+7(fixed) + 1(Number of server's network threads) + 5(Number of business processing threads) + 2(Number of communicator's network threads) + 2(Number of communicator's asynchronous callback threads) * 2(Number of communicator's network threads) = 19 threads.
+
+# 4. Method of changing the number of threads
+
+The above shows which thread is composed of a standard Tars(C++) service application. Any thread that indicates a number of 1 is implemented internally by the Tars(C++), and the user cannot change its number.
+
+The number of threads that can be changed are server's network threads, business processing threads, communicator's network threads, and communicator's asynchronous callback threads.
+
+## 4.1. Method of changing the number of business processing threads
+
+If you want to change the number of business processing threads of a certain servant object on the server, you can fill in the number N in the "Number of threads" column when the servant object is configured on the Tars management platform, then the Tars(C++) service application will start N business processing threads for the servant.
+
+
+Note:
+
+If the service has two Servant objects, each belonging to a different business processing thread group, when calculating the number of business threads, we only need to simply add the number of business processing threads of different Servant objects.
+
+If you set up a shared business processing thread group, the calculation method is different.
+
+For example:
+
+ServantA belongs to the business processing thread group HandleGroupA and starts 10 business processing threads
+
+ServantB and ServantC belong to the business processing thread group HandleGroupBC and start 10 business processing  threads.
+
+Then the total number of business processing threads should be: 10 + 10
+
+
+## 4.2. Method for changing server's network thread, communicator's network thread, and asynchronous callback processing thread
+
+If you want to change the number of server's network threads, communicator's network threads, and asynchronous callback threads, you can modify them on the template or add the corresponding service's private template.

+ 1359 - 0
docs-en/tars_cpp_user_guide.md

@@ -0,0 +1,1359 @@
+# Contents
+> * C++ Server 
+> * C++ Clinet
+> * Asynchronous nesting
+> * dyeing
+> * Tars protocol packet size
+> * The return code defined by the tars
+> * Business configuration
+> * Log
+> * Service management
+> * Statistical report
+> * Abnormally Report
+> * Attribute statistics
+
+# Guide to use of frame
+
+# 1. C++ Server
+
+Here is a complete example of how to use TARS to implement your own services.
+
+The following code describes an example of sending a hello world string to the server by a client and returning the Hello word string by the server.
+
+## 1.1. Defining interface
+
+Write the tars file as follows, Hello.tars:
+```
+
+module TestApp
+{
+
+interface Hello
+{
+    int test();
+    int testHello(string sReq, out string sRsp);
+};
+
+}; 
+
+```
+## 1.2. Compile interface file
+
+The C++ file is automatically generated by the tars2cpp tool: the /usr/local/tars/cpp/tools/tars2cpp hello.tars generates a hello.h file, which is included by the client and the server.
+
+## 1.3. Interface implementation
+
+The interface defined in the tars file is implemented in the code of the service:
+
+HelloImp.h
+
+```
+#ifndef _HelloImp_H_
+#define _HelloImp_H_
+
+#include "servant/Application.h"
+#include "Hello.h"
+
+/**
+ * HelloImp inherits the Hello objects defined in the hello.h
+ *
+ */
+class HelloImp : public TestApp::Hello
+{
+public:
+    /**
+     *
+     */
+    virtual ~HelloImp() {}
+
+    /**
+     * Initialization, the virtual function in Hello is called when HelloImp initializes.
+     */
+    virtual void initialize();
+
+    /**
+     * Deconstruction, The virtual function in Hello is called when the service destruct HelloImp exits.
+     */
+    virtual void destroy();
+
+    /**
+     * Implement the test interface defined in the tars file
+     */
+    virtual int test(tars::TarsCurrentPtr current) { return 0;};
+
+    /**
+     * Implement the test interface defined in the tars file
+     */
+    virtual int testHello(const std::string &sReq, std::string &sRsp, tars::TarsCurrentPtr current);
+
+};
+/////////////////////////////////////////////////////
+#endif
+
+```
+HelloImp.cpp
+```
+#include "HelloImp.h"
+#include "servant/Application.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////
+void HelloImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+
+//////////////////////////////////////////////////////
+void HelloImp::destroy()
+{
+    //destroy servant here:
+    //...
+}
+
+int HelloImp::testHello(const std::string &sReq, std::string &sRsp, tars::TarsCurrentPtr current)
+{
+    TLOGDEBUG("HelloImp::testHellosReq:"<<sReq<<endl);
+    sRsp = sReq;
+    return 0;
+}
+```
+
+The framework code of the server
+
+HelloServer.h:
+```
+#ifndef _HelloServer_H_
+#define _HelloServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+
+using namespace tars;
+
+/**
+ * The Application class in the framework is inherited by HelloServer
+ **/
+class HelloServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~HelloServer() {};
+
+    /**
+     * The initialization interface of the server
+     **/
+    virtual void initialize();
+
+    /**
+     * The interface used to clean up when the server exits
+     **/
+    virtual void destroyApp();
+};
+
+extern HelloServer g_app;
+
+////////////////////////////////////////////
+#endif
+
+```
+The contents of the HelloServer.cpp are as follows:
+```
+#include "HelloServer.h"
+#include "HelloImp.h"
+
+using namespace std;
+
+HelloServer g_app;
+
+/////////////////////////////////////////////////////////////////
+void
+HelloServer::initialize()
+{
+    //initialize application here:
+
+    //Adding Servant interface to implement binding between class HelloImp and routing Obj
+    addServant<HelloImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".HelloObj");
+}
+/////////////////////////////////////////////////////////////////
+void
+HelloServer::destroyApp()
+{
+    //destroy application here:
+    //...
+}
+/////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+////////////////////////////////////////////////////////////////
+```
+
+Illustration:
+> * Object HelloImp has a specific instance for each thread of the service, and the HelloImp interface is thread safe if it is only operated on the member variables of the HelloImp, and if the HelloImp interface needs to access the global object, it needs to be locked.
+> * ServerConfig::Application+“.”+ ServerConfig::ServerName + ".HelloObj"represents the name of the Hello object of the service, and the subsequent client can access the service through this name.
+> * A parameter shared by all functions is TarsCurrentPtr, and all original contents of the request packet can be obtained through this structure.
+> * HelloServer is a service class implemented by itself, inherited from the tars:: Application class in the server framework.
+
+## 1.4. ServerConfig
+
+There is a global structure ServerConfig in the service framework, which records the basic information of the server.
+
+The member variables of ServerConfig are static, and these parameters are automatically initialized from the service configuration file when the service framework is initialized.
+
+The definition of ServerConfig is as follows:
+```
+struct ServerConfig
+{
+    static std::string Application;         //Application name
+    static std::string ServerName;          //Server name. A server name contains one or more server identities.
+    static std::string BasePath;            //The application path is used to save the local directory of remote system configuration.
+    static std::string DataPath;            //The application data path is used to save common data files.
+    static std::string LocalIp;             //Local IP
+    static std::string LogPath;             //Log path
+    static int         LogSize;             //Log size (bytes)
+    static int         LogNum;              //Log number
+    static std::string LogLevel;            //Log level
+    static std::string Local;               //Local sockets
+    static std::string Node;                //Local node address
+    static std::string Log;                 //Log center address
+    static std::string Config;              //Configuration center address
+    static std::string Notify;              //Information notification Center
+    static std::string ConfigFile;          //Frame configuration file path
+    static int         ReportFlow;          //Whether to open the server to report all the interface flow, 0 is not reported, and 1 is reported (for non tars protocol service traffic statistics).
+    static int         IsCheckSet;          //Whether to check the legality of the call according to the set rules, 0 does not check, and 1 checks.
+    static bool        OpenCoroutine;	    //Whether to open the coroutine
+    static size_t      CoroutineMemSize;    //The maximum value of the coroutine occupied memory space
+    static uint32_t    CoroutineStackSize;  //Stack size for each coroutine(default 128K)
+
+```
+Parameter Description:
+> * Application:Application name, if the configuration file is not set, the default is UNKNOWN;
+> * ServerName:The name of the server. The default is the name of the executable file.
+> * BasePath:Basic path, which usually represents the path of executable files, defaults to "/".
+> * DataPath:The data file path, which usually indicates the existence of its own data, such as the MMAP file, and so on.
+> * LocalIp:Local IP, which acquiescence is the first network card IP of this machine, not 127.0.0.1.
+> * LogPath:Log file path, please refer to follow up for log writing.
+> * LogSize:The size of the rolling log file;
+> * LogNum:The number of rolling log files;
+> * LogLevel:Rolling log level;
+> * Local:The server can have a management port, which can be sent to the server through a management port, which represents the address of the bound management port, such as TCP -h 127.0.0.1 -p 8899, without a management port if it is not set.
+> * Node:Local NODE address,If it is set, the heartbeat is sent to NODE regularly, otherwise the heartbeat is not transmitted, usually only when the service is posted to the frame.
+> * Log:Log center address, for example: tars.tarslog.LogObj@tcp - H... - P... If there is no configuration, the remote log is not recorded.
+> * Config:The address of the configuration center, for example: tars.tarsconfig.ConfigObj@tcp - H... -p... If there is no configuration, the addConfig function is invalid and the configuration can not be pulled from the remote configuration center.
+> * Notify:Information to the center address, for example: tars.tarsnotify.NotifyObj@tcp - H... -p... If there is no configuration, the information submitted will be discarded directly.
+> * ConfigFile:Frame configuration file path
+> * IsCheckSet:Whether to check the legality of the call according to the set rules, 0 does not check, and 1 checks.
+> * OpenCoroutine:Whether to open a coroutine mode, the default value is 0, which means that it is not enabled.
+> * CoroutineMemSize:The maximum value of the coroutine occupied memory space
+> * CoroutineStackSize:Stack size for each coroutine(default 128K)
+
+The configuration of server is as below:
+```
+<tars>
+  <application>
+    <server>
+       #Ip:port of local node
+       node=tars.tarsnode.ServerObj@tcp -h 10.120.129.226 -p 19386 -t 60000
+       #Application name
+       app=TestApp
+       #Server name
+       server=HelloServer
+       #Local ip
+       localip=10.120.129.226
+       #Management port
+       local=tcp -h 127.0.0.1 -p 20001 -t 3000
+       #The server's executable files, configuration files, and so on
+       basepath=/usr/local/app/tars/tarsnode/data/TestApp.HelloServer/bin/
+       #Data directory of the server
+       datapath=/usr/local/app/tars/tarsnode/data/TestApp.HelloServer/data/
+       #Log path
+       logpath=/usr/local/app/tars/app_log/
+       #Rolling log size
+       logsize=10M
+       #The address of the configuration center
+       config=tars.tarsconfig.ConfigObj
+       #The address of the report [optional]
+       notify=tars.tarsnotify.NotifyObj
+       #The address of the remote log [optional]
+       log=tars.tarslog.LogObj
+       #Timeout time of server stop
+       deactivating-timeout=2000
+       #Log level
+       logLevel=DEBUG
+    </server>
+  </application>
+</tars>
+```
+
+## 1.5. Adapter
+
+Adapter corresponds to the TC_EpollServer:: BindAdapter in the code, which indicates the binding port.
+
+If a new binding port is added to the server, a new BindAdapter is set up, and the relevant parameters and processed objects can be very convenient to complete the processing on this port, usually with this function to complete the support of other protocols.
+
+For TARS servers, adding adapter items to the server's configuration files means that TARS can be added to a Servant processing object.
+
+The Adapter configuration is as follows:
+```
+<tars>
+  <application>
+    <server>
+       #Configuration of bound ports
+       <TestApp.HelloServer.HelloObjAdapter>
+            #Allowed IP address
+            allow
+            #The IP address of the listener
+            endpoint=tcp -h 10.120.129.226 -p 20001 -t 60000
+            #Processing group
+            handlegroup=TestApp.HelloServer.HelloObjAdapter
+            #Maximum connection
+            maxconns=200000
+            #Protocol
+            protocol=tars
+            #Queue size
+            queuecap=10000
+            #The timeout time of the queue (milliseconds)
+            queuetimeout=60000
+            #Processing object
+            servant=TestApp.HelloServer.HelloObj
+            #Current thread number
+            threads=5
+       </TestApp.HelloServer.HelloObjAdapter>
+    </server>
+  </application>
+</tars>
+```
+Focus on the servant item. In HelloServer:: Initialize (), the matching between the configuration and the object in the code is completed.```
+void HelloServer::initialize ()
+{
+    //Add servant
+    addServant<HelloImp>(ServerConfig::Application+“.”+ ServerConfig::ServerName + ".HelloObj");
+}
+```
+
+## 1.6. Server startup
+
+The server's boot command is as follows:
+```
+HelloServer --config=config.conf
+```
+Note: config.conf is the configuration file, the configuration files of the server and the client configuration files must be merged into this file.
+As for servers, they can be run separately and do not need to be published on the TARS system framework.
+
+The complete configuration is as follows:
+```
+<tars>
+  <application>
+    enableset=n
+    setdivision=NULL
+    <server>
+       #Ip:port of local node
+       node=tars.tarsnode.ServerObj@tcp -h 10.120.129.226 -p 19386 -t 60000
+       #Application name
+       app=TestApp
+       #Server name
+       server=HelloServer
+       #Local ip
+       localip=10.120.129.226
+       #Management port
+       local=tcp -h 127.0.0.1 -p 20001 -t 3000
+       #The server's executable files, configuration files, and so on
+       basepath=/usr/local/app/tars/tarsnode/data/TestApp.HelloServer/bin/
+       #Data directory of the server
+       datapath=/usr/local/app/tars/tarsnode/data/TestApp.HelloServer/data/
+       #Log path
+       logpath=/usr/local/app/tars/app_log/
+       #Rolling log size
+       logsize=10M
+       #The address of the configuration center
+       config=tars.tarsconfig.ConfigObj
+       #The address of the report [optional]
+       notify=tars.tarsnotify.NotifyObj
+       #The address of the remote log [optional]
+       log=tars.tarslog.LogObj
+       #Timeout time of server stop
+       deactivating-timeout=2000
+       #Log level
+       logLevel=DEBUG
+        #Configuration of bound ports
+       <TestApp.HelloServer.HelloObjAdapter>
+             #Allowed IP address
+            allow
+            #The IP address of the listener
+            endpoint=tcp -h 10.120.129.226 -p 20001 -t 60000
+            #Processing group
+            handlegroup=TestApp.HelloServer.HelloObjAdapter
+            #Maximum connection
+            maxconns=200000
+            #Protocol
+            protocol=tars
+            #Queue size
+            queuecap=10000
+            #The timeout time of the queue (milliseconds)
+            queuetimeout=60000
+            #Processing object
+            servant=TestApp.HelloServer.HelloObj
+            #Current thread number
+            threads=5
+       </TestApp.HelloServer.HelloObjAdapter>
+    </server>
+    <client>
+       #Master's address
+       locator=tars.tarsregistry.QueryObj@tcp -h 10.120.129.226 -p 17890
+       #Synchronous timeout time
+       sync-invoke-timeout=3000
+       #Asynchronous timeout time
+       async-invoke-timeout=5000
+       #Refresh the time interval of the IP list
+       refresh-endpoint-interval=60000
+       #The time interval of the reported data
+       report-interval=60000
+       #sampling rate
+       sample-rate=100000
+       #Maximum sampling number
+       max-sample-count=50
+       #Asynchronous thread number
+       asyncthread=3
+       #Template name
+       modulename=TestApp.HelloServer
+    </client>
+  </application>
+</tars>
+```
+
+# 2. C++ Client
+
+The client can complete the remote call without writing any code related to the protocol communication.The client code also needs to include the hello.h file.
+## 2.1. Communicator
+
+After the server is implemented, the client needs to send and receive data packets to the server. The client's operation of sending and receiving data packets to the server is implemented by Communicator.
+
+** Note: A Tars service can only have one Communicator variable, which can be obtained with Application::getCommunicator() (if it is not the Tars service, create a communicator yourself).
+
+The communicator is a carrier of client resources and contains a set of resources for sending and receiving packets, status statistics and other functions.
+
+The communicator is initialized as follows:
+```cpp
+TC_Config conf("config.conf");
+CommunicatorPtr c = new Communicator();
+//Initialize the communicator with a configuration file
+c-> setProperty(conf);
+//Or initialize directly with attributes
+c->setProperty("property", "tars.tarsproperty.PropertyObj");
+c->setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h ... -p ...");
+```
+Description:
+> * The communicator's configuration file format will be described later.
+> * Communicators can be configured without a configuration file, and all parameters have default values.
+> * The communicator can also be initialized directly through the "Property Settings Interface".
+> * If you need to get the RPC call proxy through the name server, you must set the locator parameter.
+
+Communicator attribute description:
+> * locator:The address of the registry service must be in the format "ip port". If you do not need the registry to locate the service, you do not need to configure this item.
+> * sync-invoke-timeout:The maximum timeout (in milliseconds) for synchronous calls. The default value for this configuration is 3000.
+> * async-invoke-timeout:The maximum timeout (in milliseconds) for asynchronous calls. The default value for this configuration is 5000.
+> * refresh-endpoint-interval:The interval (in milliseconds) for periodically accessing the registry to obtain information. The default value for this configuration is one minute.
+> * stat:The address of the service is called between modules. If this item is not configured, it means that the reported data will be directly discarded.
+> * property:The address that the service reports its attribute. If it is not configured, this means that the reported data is directly discarded.
+> * report-interval:The interval at which the information is reported to stat/property. The default is 60000 milliseconds.
+> * asyncthread:The number of threads that process asynchronous responses when taking an asynchronous call. The default is 1.
+> * modulename:The module name, the default value is the name of the executable program.
+
+The format of the communicator's configuration file is as follows:
+```
+<tars>
+  <application>
+    #The configuration required by the proxy
+    <client>
+        #address
+        locator                     = tars.tarsregistry.QueryObj@tcp -h 127.0.0.1 -p 17890
+        #The maximum timeout (in milliseconds) for synchronous calls.
+        sync-invoke-timeout         = 3000
+        #The maximum timeout (in milliseconds) for asynchronous calls.
+        async-invoke-timeout        = 5000
+        #The maximum timeout (in milliseconds) for synchronous calls.
+        refresh-endpoint-interval   = 60000
+        #Used for inter-module calls
+        stat                        = tars.tarsstat.StatObj
+        #Address used for attribute reporting
+        property                    = tars.tarsproperty.PropertyObj
+        #report time interval
+        report-interval             = 60000
+        #The number of threads that process asynchronous responses
+        asyncthread                 = 3
+        #The module name
+        modulename                  = Test.HelloServer
+    </client>
+  </application>
+</tars>
+```
+Instructions for use:
+> * When using the Tars framework for server use, users do not need to create their own communicators, directly using the communicator in the service framework. E.g: Application::getCommunicator()->stringToProxy(...). For a pure client scenario, the user needs to define a communicator and generate a service proxy.
+> * Application::getCommunicator() is a static function of the Application class, which can be obtained at any time;
+> * For the service proxy created by the communicator, it is also not necessary to call stringToProxy() before each use. The service proxy will be established during initialization, and it can be used directly afterwards.
+> * For the creation and use of agents, please see the following sections;
+> * For the same Obj name, the service proxy obtained by calling stringToProxy() multiple times is actually the same variable, which is safe for multi-threaded calls and does not affect performance.
+> * The ip list corresponding to obj can be obtained by Application::getCommunicator()->getEndpoint("obj").Another way to get an IP list is to get it directly from the proxy generated by the communicator, such as Application::getCommunicator()->stringToProxy(...) ->getEndpoint().
+
+## 2.2. Timeout control
+
+The timeout control is for the client proxy. There are records in the configuration file of the communicator described in the previous section:
+```cpp
+#The maximum timeout (in milliseconds) for synchronous calls.
+sync-invoke-timeout          = 3000
+#The maximum timeout (in milliseconds) for asynchronous calls.
+async-invoke-timeout         = 5000
+```
+The above timeout is valid for all the proxies generated by the communicator.
+
+If you need to set the timeout separately, as shown below:
+
+Set the timeout period for the proxy:
+```cpp
+ProxyPrx  pproxy;
+//Set the timeout for the agent's synchronous call (in milliseconds)
+pproxy->tars_timeout(3000);
+//Sets the timeout for the agent's asynchronous call (in milliseconds)
+pproxy->tars_async_timeout(4000);
+```
+
+Set the timeout for the calling interface:
+```cpp
+//Set the timeout (in milliseconds) for this interface call of this agent. This setting will only take effect once.
+pproxy->tars_set_timeout(2000)->a(); 
+```
+
+## 2.3. Call interface
+
+This section details how the Tars client remotely invokes the server.
+
+First, briefly describe the addressing mode of the Tars client. Secondly, it will introduce the calling method of the client, including but not limited to one-way calling, synchronous calling, asynchronous calling, hash calling, and so on.
+
+### 2.3.1. Introduction to addressing mode
+
+The addressing mode of the Tars service can usually be divided into two ways: the service name is registered in the master and the service name is not registered in the master. A master is a name server (routing server) dedicated to registering service node information.
+
+The service name added in the name server is implemented through the operation management platform.
+
+For services that are not registered with the master, it can be classified as direct addressing, that is, the ip address of the service provider needs to be specified before calling the service. The client needs to specify the specific address of the HelloObj object when calling the service:
+
+that is: Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985
+
+Test.HelloServer.HelloObj: Object name
+
+tcp:Tcp protocol
+
+-h:Specify the host address, here is 127.0.0.1
+
+-p:Port, here is 9985
+
+If HelloServer is running on two servers, HelloPrx is initialized as follows:
+```cpp
+HelloPrx pPrx = c->stringToProxy<HelloPrx>("Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985:tcp -h 192.168.1.1 -p 9983");
+```
+The address of HelloObj is set to the address of the two servers. At this point, the request will be distributed to two servers (distribution method can be specified, not introduced here). If one server is down, the request will be automatically assigned to another one, and the server will be restarted periodically.
+
+For services registered in the master, the service is addressed based on the service name. When the client requests the service, it does not need to specify the specific address of the HelloServer, but it needs to specify the address of the `registry` when generating the communicator or initializing the communicator.
+
+The following shows the address of the registry by setting the parameters of the communicator:
+```
+CommunicatorPtr c = new Communicator();
+c->setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h .. -p ..")
+```
+Since the client needs to rely on the registry's address, the registry must also be fault-tolerant. The registry's fault-tolerant method is the same as above, specifying the address of the two registry.
+
+### 2.3.2. One-way call
+
+A one-way call means that the client only sends data to the server without receiving the response from the server, and whether the server receives the request data.
+```cpp
+TC_Config conf("config.conf");
+CommunicatorPtr c = new Communicator();
+//Initialize the communicator with a configuration file
+c-> setProperty(conf);
+//Generate a client's service proxy
+HelloPrx pPrx = c->stringToProxy<HelloPrx>("Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985");
+//Initiate a remote call
+string s = "hello word";
+string r;
+pPrx->async_testHello(NULL, s);
+```
+### 2.3.3. Synchronous call
+
+Take a look at the code example below:
+```cpp
+TC_Config conf("config.conf");
+CommunicatorPtr c = new Communicator();
+//Initialize the communicator with a configuration file
+c-> setProperty(conf);
+//Generate a client's service proxy
+HelloPrx pPrx = c->stringToProxy<HelloPrx>("Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985");
+//Initiate a remote synchronization call
+string s = "hello word";
+string r;
+int ret = pPrx->testHello(s, r);
+assert(ret == 0);
+assert(s == r);
+```
+The above example shows that the client initiates a remote synchronization call to the HelloObj object of the HelloServer.
+
+### 2.3.4. Asynchronous call
+
+Define an asynchronous callback object:
+```cpp
+struct HelloCallback : public HelloPrxCallback
+{
+//Callback
+virtual void callback_testHello(int ret, const string &r)
+{
+    assert(r == "hello word");
+}
+
+virtual void callback_testHello_exception(tars::Int32 ret)
+{
+    assert(ret == 0);
+    cout << "callback exception:" << ret << endl;
+}
+};
+
+TC_Config conf("config.conf");
+CommunicatorPtr c = new Communicator();
+//Initialize the communicator with a configuration file
+c-> setProperty(conf);
+//Generate a client's service proxy
+HelloPrx pPrx = c->stringToProxy<HelloPrx>("Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985");
+//Define an object for a remote callback class
+HelloPrxCallbackPtr cb = new HelloCallback;
+
+//Initiate a remote synchronization call
+string s = "hello word";
+string r;
+pPrx->async_testHello(cb, s);
+```
+note:
+> * When a response from the server is received, HelloPrxCallback::callback_testHello() will be called.
+> * If the asynchronous call returns an exception or timeout, then HelloPrxCallback::callback_testHello_exception() will be called with the return value defined as follows:
+
+
+```cpp
+//The return code given by the TARS server
+const int TARSSERVERSUCCESS       = 0;       //The server is successfully processed
+const int TARSSERVERDECODEERR     = -1;      //Server decoding exception
+const int TARSSERVERENCODEERR     = -2;      //Server encoding exception
+const int TARSSERVERNOFUNCERR     = -3;      //The server does not have this function
+const int TARSSERVERNOSERVANTERR  = -4;      //The server does not have the Servant object.
+const int TARSSERVERRESETGRID     = -5;      //Inconsistent gray state on the server side
+const int TARSSERVERQUEUETIMEOUT  = -6;      //Server queue exceeded limit
+const int TARSASYNCCALLTIMEOUT    = -7;      //Asynchronous call timeout
+const int TARSINVOKETIMEOUT       = -7;      //Call timeout
+const int TARSPROXYCONNECTERR     = -8;      //Proxy link exception
+const int TARSSERVEROVERLOAD      = -9;      //The server is overloaded and exceeds the queue length.
+const int TARSADAPTERNULL         = -10;     //The client routing is empty, the service does not exist or all services are offline.
+const int TARSINVOKEBYINVALIDESET = -11;     //The client is called by an invalid set rule
+const int TARSCLIENTDECODEERR     = -12;     //Client decoding exception
+const int TARSSERVERUNKNOWNERR    = -99;     //Server location is abnormal
+```
+
+### 2.3.5. Set mode call
+
+Currently, the framework already supports the deployment of services in set mode. After deployment by set, calls between services are transparent to business development. However, because some services have special requirements, after the deployment by set, the client can specify the set name to invoke the server. So the framework adds the ability for the client to specify the set name to call those services deployed by set.
+
+The detailed usage rules are as follows:
+
+Assume that the service server HelloServer is deployed on two sets, Test.s.1 and Test.n.1. Then the client specifies the set mode to be called as follows:
+```cpp
+TC_Config conf("config.conf");
+CommunicatorPtr c = new Communicator();
+//Initialize the communicator with a configuration file
+c-> setProperty(conf);
+//Generate a client's service proxy
+HelloPrx pPrx_Tests1 = c->stringToProxy<HelloPrx>("Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985","Test.s.1");
+
+HelloPrx pPrx_Testn1 = c->stringToProxy<HelloPrx>("Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985","Test.n.1");
+
+//Initiate a remote synchronization call
+string s = "hello word";
+string r;
+
+int ret = pPrx_Tests1->testHello(s, r);
+
+int ret = pPrx_Testn1->testHello(s, r);
+```
+note:
+> * The priority of the specified set call is higher than the priority of the client and the server itself to enable the set. For example, both the client and the server have "Test.s.1" enabled, and if the client specifies "Test.n.1" when creating the server proxy instance, the actual request is sent to "Test.n.1"("Test.n.1" has a deployment service).
+> * Just create a proxy instance once
+
+### 2.3.6. Hash call
+
+Since multiple servers can be deployed, client requests are randomly distributed to the server, but in some cases, it is desirable that certain requests are always sent to a particular server. In this case, Tars provides a simple way to achieve:
+
+If there is a request for querying data according to the QQ number, as follows:
+```cpp
+QQInfo qi = pPrx->query(uin);
+```
+Normally, for the same call to uin, the server address of each response is not necessarily the same. However, With the following call, it can be guaranteed that each request for uin is the same server response.
+```cpp
+QQInfo qi = pPrx->tars_hash(uin)->query(uin);
+```
+
+
+note:
+> * This method is not strict. If a server goes down, these requests will be migrated to other servers. When it is normal, the request will be migrated back.
+> * The argument to tars_hash() must be int. For string, the Tars base library (under the util directory) also provides the method: tars::hash<string>()("abc"). See util/tc_hash_fun.h for details.
+
+# 3. Asynchronous nesting
+
+Asynchronous nesting represents the following:
+
+> * A calls B asynchronously, B calls C asynchronously after receiving the request, and B returns the result to A when C returns.
+
+Normally, B needs to return a response to A after B receives the request and finishes processing in the interface.
+Therefore, it is not can be implemented if B initiates an asynchronous request to C in the interface.
+
+Therefore, it is necessary to implemente the asynchronous calls across services by using the following methods.
+You can see the cpp/examples/QuickStartDemo/ProxyServer example for details.
+
+The following still uses the helloworld program to explain. Firstly, the client initiates a request to the proxy, and the proxy initiates
+testHello to the HelloServer asynchronously after receiving the request. Then the proxy returns the result by the HelloServer to the client
+after the request returns.
+
+The key logic in this process is on the ProxyServer. The following code is the logical processing in B:
+```cpp
+//Asynchronous callback object in ProxyServer
+class HelloCallback : public HelloPrxCallback
+{
+
+public:
+    HelloCallback(TarsCurrentPtr &current)
+    : _current(current)
+    {}
+
+    virtual void callback_testHello(tars::Int32 ret,  const std::string& sOut)
+    {
+        Proxy::async_response_testProxy(_current, ret, sOut);
+    }
+    virtual void callback_testHello_exception(tars::Int32 ret)
+    { 
+        TLOGERROR("HelloCallback callback_testHello_exception ret:" << ret << endl); 
+
+        Proxy::async_response_testProxy(_current, ret, "");
+    }
+
+    TarsCurrentPtr _current;
+};
+
+//The interface defined in ProxyServer
+tars::Int32 ProxyImp::testProxy(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current)
+{
+    try
+    {
+        current->setResponse(false);
+
+        TestApp::HelloPrxCallbackPtr cb = new HelloCallback(current);
+
+        _prx->tars_set_timeout(3000)->async_testHello(cb,sIn);
+    }
+    catch(std::exception &ex)
+    {
+        current->setResponse(true);
+
+        TLOGERROR("ProxyImp::testProxy ex:" << ex.what() << endl);
+    }
+
+    return 0;
+}
+```
+Description:
+> * The callback object HelloCallback saves the context current;
+> * The callback object return the request to the client through Proxy::async_response_testProxy after receiving the request returned by HelloServer;
+> * It needs to set the automatic reply current->setResponse(false) in the ProxyServer interface testProxy implementation;
+> * It is actually meaningless to return a value or parameters of testProxy. No matter what is returned;
+> * If other parameters are needed in the callback object, they can be passed in when constructing again;
+> * The callback object must be new and placed in the smart pointer, for example: HelloPrxCallbackPtr cb = new HelloCallback(current); For its life cycle, the business does not need to managed, because the framework layer is automatically managed;
+
+# 4. Dyeing
+
+## 4.1. Funcational Overview
+
+The main function of the dyeing function is to dye the message of a specific user number in an interface of a certain service, and conveniently view the log of all subsequent related call message flows caused by the user in real time.
+
+After the dye log is opened, the dyed log can be viewd on the server where tarslog is located. For the specific path, please refer to:
+
+The scrolling log which is written by the LOG macro in the program is all printed to the tarslog, its log file like: tars_dyeing.dyeing_roll_yyyymmdd.log. There is one file every day, such as:
+
+/usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/tars_dyeing.dyeing_roll_20161227.log
+
+The daily log which is written by the DLOG, FDLOG and FFDLOG in the program is all printed to the tarslog, its log file like: tars_dyeing.dyeing_day_yyyymmdd.log. There is one file every day, such as:
+
+/usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/tars_dyeing.dyeing_day_20161227.log
+
+## 4.2.	Rule description
+
+The dye log has two methods: active open and passive open.
+
+The active open means that the dyed log switch in the framework is opened on the requesting client.
+
+The specific steps are as follows:
+> * An anchor point is buried in the appropriate place of the client program, and the anchor point is used to decide whether to open the dye log switch according to a certain condition.--tars.TarsDyeingSwitch. The range of staining starts from the opening of log util the switch is destructed.
+> * The interface names enableDyeing is the method of openning dyed log. Subsequently, all logs should be requested(including this service, as well as logs for all services called later) will be printed an additional copy to the tarslog.
+> * The called service opens the dyed log according to the request flag and prints the log to tarslog. The flag is passed to the next service automatically if the called also calls other service. The dyed log is closed automatically when the request is completed.
+
+The passive open means that, under the pre-set dyeing condition of the requested server, the server opens the dyeing log switch of the service according to the transmitted key value.
+
+The specific steps are as follows:
+> * The dyed ingress interface needs to be specified as the routekey for the user keyword when the Tars interface is defined.
+> * The method of dyeing: You can set the user number, remote object and interface to be dyed to the target service through the management command interface(optional interface parameters).
+> * After the service receives the matching request(matching the user number, remote object and interface), the request packet is dyed.
+> * For the already dyed request, the related system log and the daily log will be printed normally, and also print to the local and remote dye log directory centralizedly. The directory location is in the /tars_dyeing directory.
+> * if other services are continuously called during the service processing, the request will passes the dyeing information through the status field. The called service will print the dyed log in the above manner and continue the dyeing status.
+
+## 4.3. The use case of active open
+The usage of active open:
+```cpp
+#include <iostream>
+#include "servant/Communicator.h"
+#include "Hello.h"
+#include "servant/TarsLogger.h"
+#include "util/tc_option.h"
+#include "util/tc_file.h"
+
+#include <string>
+using namespace std;
+using namespace TestApp;
+using namespace tars;
+
+int main(int argc,char ** argv)
+{
+try
+{
+    CommunicatorPtr comm =new Communicator();
+    comm->setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h 10.120.129.226 -p 17890 -t 10000");
+    TarsRollLogger::getInstance()->setLogInfo("TestApp", "HelloServer", "./log", 100000, 10, comm, "tars.tarslog.LogObj");
+    TarsRollLogger::getInstance()->sync(false);
+    TarsTimeLogger::getInstance()->setLogInfo(comm, "tars.tarslog.LogObj", "TestApp", "HelloServer", "./log");
+    {
+            //This log will only be printed to the local log before the dye log is opened.
+            TLOGDEBUG    (__FILE__ << "|" << __LINE__ <<"Test Before Dyeing"  <<endl);
+            DLOG        <<__FILE__ << "|" << __LINE__ <<"D/Test Before Dyeing"<<endl;
+            FDLOG("T_D")<<__FILE__ << "|" << __LINE__ <<"F/Test Before Dyeing"<<endl;
+    }
+         try
+         {
+        	{
+
+        	   //Declare a class TarsDyeingSwitch, and call enableDyeing to open the dye log.
+        	   TarsDyeingSwitch dye;
+        	   dye.enableDyeing();
+
+        	   //You can see the log in the local and dye logs after the dye log is opened.
+        	   {
+        	      TLOGDEBUG    (__FILE__ << "|" << __LINE__ <<"Test Before Dyeing before call other function"  <<endl);
+        	      DLOG        <<__FILE__ << "|" << __LINE__ <<"D/Test Before Dyeing before call other function"<<endl;
+        	      FDLOG("T_D")<<__FILE__ << "|" << __LINE__ <<"F/Test Before Dyeing before call other function"<<endl;
+        	   }
+        	   
+
+        	   string sReq("hello");
+        	   std::string sServant="TestApp.HelloServer.HelloObj";
+        	   TestApp::HelloPrx prx = comm->stringToProxy<TestApp::HelloPrx>(sServant);
+        	   tars::Int32 iRet = prx->test();
+        	   string sRsp;
+        	   prx->testHello(sReq,sRsp);
+
+			
+        	   TLOGDEBUG    (__FILE__ << "|" << __LINE__ <<"Test Before Dyeing after call other function"  <<endl);
+        	   DLOG        <<__FILE__ << "|" << __LINE__ <<"D/Test Before Dyeing after call other function"<<endl;
+        	   FDLOG("T_D")<<__FILE__ << "|" << __LINE__ <<"F/Test Before Dyeing after call other function"<<endl;
+        	}
+		
+        	{
+        	   //The dye log object has beed destructed, the dye function is invalid, and you can't see the dye log in the future.
+        	   TLOGDEBUG    (__FILE__ << "|" << __LINE__ <<"~Dyeing"<<endl);
+        	   DLOG        <<__FILE__ << "|" << __LINE__ <<"D/~Dyeing"<<endl;
+        	   FDLOG("T_D")<<__FILE__ << "|" << __LINE__ <<"F/~Dyeing"<<endl;
+        	}
+        }
+        catch(exception &ex)
+        {
+             cerr << "ex:" << ex.what() << endl;
+        }
+        catch(...)
+        {
+             cerr << "unknown exception." << endl;
+        }
+    }
+    catch(exception& e)
+    {
+        cerr << "exception:" << e.what() << endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << endl;
+    }
+    sleep(10); //Waiting for thread written log asynchronously to synchronize log data to logserver
+    return 0;
+}
+
+
+```
+
+in tars_dyeing.dyeing_roll_20161227.log
+```
+//This log is rolling log printed by the server using TLOGDEBUG.
+10.120.129.226|TestApp.HelloServer|2016-12-27 11:30:47|7670|DEBUG|main.cpp|37Test Before Dyeing before call other function
+//This log is rolling log printed by the server using TLOGDEBUG.
+10.120.129.226|TestApp.HelloServer|2016-12-27 11:30:47|7670|DEBUG|main.cpp|59Test Before Dyeing after call other function
+```
+in tars_dyeing.dyeing_day_20161227.log
+```
+//Rolling log using DLOG
+10.120.129.226|TestApp.HelloServer|2016-12-27 11:30:47|main.cpp|38D/Test Before Dyeing before call other function
+10.120.129.226|TestApp.HelloServer|2016-12-27 11:30:47|main.cpp|60D/Test Before Dyeing after call other function
+//Rolling log using FLOG
+10.120.129.226|TestApp.HelloServer|2016-12-27 11:30:47|main.cpp|39F/Test Before Dyeing before call other function
+10.120.129.226|TestApp.HelloServer|2016-12-27 11:30:47|main.cpp|61F/Test Before Dyeing after call other function
+```
+## 4.4. The Usage of passive open
+Interface definition to be dyed
+```
+interface HelloRouteObj
+{
+    int testHello(routekey string sInput, out string sOutput);
+};
+```
+Can be dyed by the frame command, the command format of the dye is:
+```
+tars.setdyeing dyeingKey dyeingServant [dyeingInterface]
+```
+This three parameters are the user number(the value corresponding to routekey), the remote object name, and the interface name(optional)
+Assume that the remote object of the above interface is TestApp.HelloServer.HelloObj testHello
+You can issue commands through the management platform: tars.setdyeing 123456 TestApp.HelloServer.HelloObj testHello
+
+When a request with sInput is 123456 is sent to the service, it is not only having the normal log output, but also having the local system log printed:
+
+/usr/local/app/tars/app_log/tars_dyeing/dyeing_20161227.log 
+TestApp.HelloServer|2016-12-27 15:38:49|11454|DEBUG|HelloImp::testHello sReq:123456
+
+local log one by one:
+
+/usr/local/app/tars/app_log/tars_dyeing/dyeing_20161227.log 
+TestApp.HelloServer|2016-12-27 15:38:49|11454|DEBUG|HelloImp::testHello sReq:123456
+
+The remote log will be printed to the machine where tarslog is located:
+remote system log:
+/usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/tars_dyeing.dyeing_roll_20161227.log
+
+remote log by day:
+/usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/tars_dyeing.dyeing_day_20161227.log
+
+The first field in the log is the service name of the dye request processing process, and the related logs of other subsequent services are also printed to the same file,
+and the logs of different services are distinguished by the first field.
+
+# 5. tars protocol packet size
+
+Currently, the tars protocol limits the size of data packets.
+
+The communicator (client) has no limit on the size of the delivered packet, and there is a limit on the received packet. The default is 10000000 bytes (close to 10M).
+
+The server has no restrictions on the delivered packets , and has a size limit on the received packets. The default is 100000000 bytes (close to 100M).
+
+## 5.1. Modify the client receiving packet size
+Modify the size of the packet by modifying the tars_set_protocol of ServantProxy.
+```cpp
+ProxyProtocol prot;
+prot.responseFunc = ProxyProtocol::tarsResponseLen<100000000>;
+prot.requestFunc  = ProxyProtocol::tarsRequest;
+ccserverPrx -> tars_set_protocol(prot);
+```
+100000000 represents the size of the limit, in bytes.
+
+ccserverPrx is globally unique, just set it once.
+
+In order to write codes conveniently, it is recommended to set it once in the initialization of the business thread .
+
+First call stringToProxy and then set it.
+```cpp
+prot.requestFunc = ProxyProtocol::tarsRequest //Must exist, the default is not this function.
+```
+If it is called in tup mode. Set len
+```cpp
+prot.responseFunc = ProxyProtocol:: tupResponseLen<100000000>;
+```
+## 5.2. Modify the server to receive the packet size
+
+Modify the packet size by setting the form of ServantProtocol.
+```cpp
+addServantProtocol(ServerConfig::Application + "." + ServerConfig::ServerName + ".BObj",AppProtocol::parseLenLen<100000000>);
+```
+It is recommended to set it in the initialize of the server and set it after addServant.
+
+# 6. Tars defined return code
+```
+//Define the return code given by the TARS service
+const int TARSSERVERSUCCESS       = 0;    //Server-side processing succeeded
+const int TARSSERVERDECODEERR     = -1;   //Server-side decoding exception
+const int TARSSERVERENCODEERR     = -2;   //Server-side encoding exception
+const int TARSSERVERNOFUNCERR     = -3;   //There is no such function on the server side
+const int TARSSERVERNOSERVANTERR  = -4;   //The server does not have the Servant object
+const int TARSSERVERRESETGRID     = -5;   // server grayscale state is inconsistent
+const int TARSSERVERQUEUETIMEOUT  = -6;   //server queue exceeds limit
+const int TARSASYNCCALLTIMEOUT    = -7;   // Asynchronous call timeout
+const int TARSINVOKETIMEOUT       = -7;   //call timeout
+const int TARSPROXYCONNECTERR     = -8;   //proxy link exception
+const int TARSSERVEROVERLOAD      = -9;   //Server overload, exceeding queue length
+const int TARSADAPTERNULL         = -10;  //The client routing is empty, the service does not exist or all services are down.
+const int TARSINVOKEBYINVALIDESET = -11;  //The client calls the set rule illegally
+const int TARSCLIENTDECODEERR     = -12;  //Client decoding exception
+const int TARSSERVERUNKNOWNERR    = -99;  //The server is in an abnormal position
+```
+
+# 7. Business Configuration
+The Tars service framework provides the ability to pull the configuration of a service from tarsconfig to a local directory.
+
+The method of use is very simple. In the initialize of the Server, call addConfig to pull the configuration file.
+
+Take HelloServer as an example:
+```
+HelloServer::initialize()
+{
+      //Increase the object
+      addServant<HelloImp>(ServerConfig::Application+"."+ ServerConfig::ServerName + ".HelloObj");
+
+      //pull the configuration file
+      addConfig("HelloServer.conf");
+}
+```
+Description:
+> * HelloServer.conf configuration file can be configured on the web management platform;
+> * After HelloServer.conf is pulled to the local, the absolute path of the configuration file can be indicated by ServerConfig::BasePath + "HelloServer.conf";
+> * The configuration file management is on the web management platform, and the web management platform can actively push the configuration file to the server;
+> * The configuration center supports ip level configuration, that is, a service is deployed on multiple services, only partially different (related to IP). In this case, the configuration center can support the merging of configuration files and support viewing on the web management platform as well as modification;
+
+Note:
+> * For services that are not released to the management platform, you need to specify the address of Config in the service configuration file, otherwise you cannot use remote configuration.
+
+
+# 8. Log
+
+Tars provides a number of macro for logging the system's rolling logs and daily logs. They are thread-safe and can be used at will.
+
+## 8.1. TLOGXXX tutorial
+
+TLOGXXX is used to record rolling logs, mainly used for debugging services. XXX includes four levels of INFO/DEBUG/WARN/ERROR, the meanings are as follows.
+
+> * INFO: Information level, the internal log of the framework is printed at this level, unless it's an error.
+> * DEBUG: Debug level, lowest level.
+> * WARN: Warning level.
+> * ERROR: Error level.
+
+Instructtions for use:
+
+```cpp
+TLOGINFO("test" << endl);
+TLOGDEBUG("test" << endl);
+TLOGWARN("test" << endl);
+TLOGERROR("test" << endl);
+```
+
+Directions:
+> * The current level of the server log can be set in the web management system.
+> * The logs of the Tars framework are printed by INFO. After setting it to INFO, you can see the frame log of Tars.
+> * TLOGXXX scrolls by size, you can modify the scroll size and number in the template configuration file of the service, usually do not need to modify.
+> * TLOGXXX indicates a circular log that is not sent to the remote tarslog service.
+> * The file name of TLOGXXX is related to the service name, usually like app.server.log.
+> * TLOGXXX has only one instance, so you can use it anywhere, but if it is used before the framework finishes LOG initialization, it will be output to cout.
+> * In the place where TLOGXXX is used, you need to add a line of code: #include "servant/TarsLogger.h"
+
+TLOGXXX is a macro, which is defined as follows:
+
+```cpp
+#define LOG             (TarsRollLogger::getInstance()->logger())
+
+#define LOGMSG(level,msg...) do{if(LOG->IsNeedLog(level)) LOG->log(level)<<msg;}while(0)
+
+#define TLOGINFO(msg...)  LOGMSG(TarsRollLogger::INFO_LOG,msg)
+#define TLOGDEBUG(msg...) LOGMSG(TarsRollLogger::DEBUG_LOG,msg)
+#define TLOGWARN(msg...)  LOGMSG(TarsRollLogger::WARN_LOG,msg)
+#define TLOGERROR(msg...) LOGMSG(TarsRollLogger::ERROR_LOG,msg)
+```
+
+The return type of TarsRollLogger::getInstance()->logger() is TC_RollLogger*,so you can set the LOG through it. For example:
+
+Set LOG to info level:
+```cpp
+TarsRollLogger::getInstance()->logger()->setLogLevel(TC_RollLogger::INFO_LOG);
+```
+
+The LOG log is asynchronous by default, but can also be set to sync:
+```cpp
+TarsRollLogger::getInstance()->sync(true);
+```
+
+You can also use LOG in any place where you use ostream. For example:
+```cpp
+ostream &print(ostream &os);
+```
+
+It can also be used like this:
+```cpp
+print(LOG->debug());
+```
+
+## 8.2.	DLOG/FDLOG
+
+Daily log, mainly used to record important business information:
+> * The default daily log of Tars is DLOG, and FDLOG can specify the file name of daily log.
+> * DLOG/FDLOG logs are automatically uploaded to tarslog and can be set to not be uploaded to tarslog.
+> * DLOG/FDLOG can modify the scrolling time, such as by minute, hour, etc.
+> * DLOG/FDLOG is asynchronous by default. It can be set to sync if necessary, but it must be asynchronous for remote upload to tarslog and cannot be set to sync.
+> * DLOG/FDLOG can be set to upload only to the remote and not recorded locally;
+> * In the place where TLOGXXX is used, you need to add a line of code: #include "servant/TarsLogger.h"
+
+## 8.3.	Code example
+```cpp
+CommunicatorPtr c = new Communicator();
+
+string logObj = "tars.tarslog.LogObj@tcp -h 127.0.0.1 -p 20500";
+
+//Initialize local scrolling logs
+TarsRollLogger::getInstance()->setLogInfo("Test", "TestServer", "./");
+
+//Initialize time log
+TarsTimeLogger::getInstance()->setLogInfo(c, logObj , "Test", "TestServer", "./");
+
+//If it is a Tars service, the above part of the code is not needed, the framework has been completed automatically.
+
+//The default daily log does't need to be uploaded to the server
+TarsTimeLogger::getInstance()->enableRemote("", false);
+
+//The default daily log is scrolled by minute
+TarsTimeLogger::getInstance()->initFormat("", "%Y%m%d%H%M");
+
+//Set abc2 not to be uploaded to the server
+TarsTimeLogger::getInstance()->enableRemote("abc2", false);
+
+//set abc2 scrolls by hour
+TarsTimeLogger::getInstance()->initFormat("abc2", "%Y%m%d%H");
+
+//Set abc3 to not be recorded locally
+TarsTimeLogger::getInstance()->enableLocal("abc3", false);
+
+int i = 100000;
+while(i--)
+{
+    //as same as last one
+    TLOGDEBUG(i << endl);
+    
+    //error level
+    TLOGERROR(i << endl);
+
+    DLOG << i << endl;
+    
+    FDLOG("abc1") << i << endl;
+    FDLOG("abc2") << i << endl;
+    FDLOG("abc3") << i << endl;
+
+    if(i % 1000 == 0)
+    {
+        cout << i << endl;
+    }
+    usleep(10);
+}
+```
+
+# 9. Service management
+The Tars server framework supports dynamic receiving commands to handle related business logic, such as dynamic update configuration.
+
+Two macros are defined in the framework:
+> * TARS_ADD_ADMIN_CMD_PREFIX: Add pre-command processing method, executed before all normal methods. The execution order between multiple pre-command methods is undefined.
+> * TARS_ADD_ADMIN_CMD_NORMAL: Add the Normal command processing method, which is executed at the end of all pre-command methods. The execution order between multiple normal methods is undefined.
+
+By using these two macros, you can register the command processing interface. When a command is sent to the service through the web management platform, the registered interface is called.
+
+There are two types of processing interfaces that are usually registered: global processing interface and object-based processing interface.
+
+The following uses HelloServer as an example to describe how to use commands.
+
+## 9.1. Global processing interface
+
+The so-called global processing interface means that the processing interface is service-dependent, not related to any objects such as HelloImp.
+
+Assume that HelloServer needs to add a function to set a FDLOG configuration file to not be uploaded to the remote tarslog. This processing is independent of the HelloImp object, so it is a global change. The processing steps are as follows:
+
+Add a handler to the HelloServer to do this. Note that the function must be declared  in this way:
+
+```cpp
+bool HelloServer::procDLOG(const string& command, const string& params, string& result)
+{
+    TarsTimeLogger::getInstance()->enableLocal(params, false);
+    return false;
+}
+```
+
+Register this function in HelloServer::initialize():
+```cpp
+void HelloServer::initialize()
+{
+    addServant(...);
+    addConfig(…);
+
+	//Registration handler:
+    TARS_ADD_ADMIN_CMD_NORMAL("DISABLEDLOG", HelloServer::procDLOG);
+}
+```
+Instruction:
+> * Can send commands directly to the service on the web management platform. Such as "DISABLEDLOG", indicating that the default daily log is set to not be recorded locally. "DISABLEDLOG test", indicating that the daily log of the test is not be recorded locally.
+> * Command handler must be declared in the same way.
+> * Return type: indicates whether the command is passed down. That is, if multiple interface functions are registered on one command, if false is returned, the subsequent interface is not called after the current interface is executed.
+> * First parameter: Indicates the name of registered command, in this example is "DISABLEDOG".
+> * Second parameter: Indicates the parameters of the command, which are decomposed by spaces, in this example is "test".
+> * Using TARS_ADD_ADMIN_CMD_NORMAL or TARS_ADD_ADMIN_CMD_PREFIX when registering depends on where you want the command to be executed.
+> * The first parameter of the registration macro represents the command name (cannot contain spaces), and the second parameter represents the function executed on the command.
+
+# 9.2. Object-based processing interface
+
+The so-called object-based processing interface means that the command interface is for an object in the service.
+
+For example, for the HelloImp object, if a command is sent to the service, the command interface of HelloImp in each thread will be executed once, and the process of executing these interfaces and the interface of executing HelloImp are mutually exclusive (ie, thread-safe)
+
+Assuming that HelloImp has the member variable string _hello, you need to send a command to notify each HelloImp object to change _hello to a custom value. The steps are as follows:
+
+Add handlers to HelloImp:
+```cpp
+bool HelloImp::procHello(const string& command, const string& params, string& result)
+{
+    _hello = params;
+    return false;
+}
+```
+
+Register the function in the initialization of HelloImp:
+```cpp
+void HelloImp::initialize()
+{
+    //Registration handler:
+    TARS_ADD_ADMIN_CMD_NORMAL("SETHELLO", HelloImp::procHello);
+}
+```
+
+After completing the above operation, send the "SETHELLO test" command on the web page, and _hello is assigned the value "test".
+
+# 9.3. Send management command
+How to send management commands: Publish a TARS service to the platform through the web management platform, and then send commands through the management platform.
+	
+TARS currently has eight commands built in:
+
+> * tars.help    		//View all administrative commands
+> * tars.loadconfig     //From the configuration center, pull the configuration file down. For example: tars.loadconfig filename
+> * tars.setloglevel    //Set the level of the rolling log. For example: tars.setloglevel [NONE, ERROR, WARN, DEBUG]
+> * tars.viewstatus     //View service status
+> * tars.connection     //View current link status
+> * tars.loadproperty	//Reload the properties in the configuration file
+> * tars.setdyeing    //Set staining information. For example: tars.setdyeing key servant [interface]
+
+# 10. Statistical reporting
+Reporting statistics information is the logic of reporting the time-consuming information and other information to tarsstat inside the Tars framework. No user development is required. After the relevant information is correctly set during program initialization, it can be automatically reported inside the framework (including the client and the server).
+
+After the client call the reporting interface, it is temporarily stored in memory. When it reaches a certain time point, it is reported to the tarsstat service (the default is once reporting 1 minute). We call the time gap between the two reporting time points as a statistical interval, and perform the operations such as accumulating and comparing the same key in a statistical interval.
+The sample code is as follows:
+```cpp
+//Initialize the communicator
+CommunicatorPtr pcomm = new Communicator();
+//Initialize the tarsregistry service address
+pcomm->setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h xxx.xxx.xxx.xx -p xxxx"
+//Initialize the stat service
+pcomm->setProperty("stat", "tars.tarsstat.StatObj");
+//Set the reporting interval
+pcomm->setProperty("report-interval", "1000");
+//Set the report main call name
+pcomm->setProperty("modulename", "Test.TestServer_Client");
+
+```
+Description:
+> *  If the main service is deployed on the web management system, you do not need to define Communicator set the configurations of tarsregistry, tarsstat, etc., the service will be automatically reported.
+> * If the main service or program is not deployed on the web management system, you need to define the Communicator, set the tarsregistry, tarsstat, etc., so that you can view the service monitoring of the called service on the web management system.
+> * The reported data is reported regularly and can be set in the configuration of the communicator.
+
+# 11. Anormaly reporting
+For better monitoring, the TARS framework supports reporting abnormal situdation directly to tarsnotify in the program and can be viewed on the WEB management page.
+
+
+The framework provides three macros to report different kinds of exceptions:
+```cpp
+// Report ordinary information
+TARS_NOTIFY_NORMAL(info) 
+// Report warning message
+TARS_NOTIFY_WARN(info) 
+// Report error message
+TARS_NOTIFY_ERROR(info)
+```
+Info is a string, which can directly report the string to tarsnotify. The reported string can be seen on the page, subsequently, we can alarm according to the reported information.
+
+# 12. Attribute Statistics
+In order to facilitate business statistics, the TARS framework also supports the display of information on the web management platform.
+
+
+The types of statistics currently supported include the following:
+> * Sum(sum)
+> * Average(avg)
+> * Distribution(distr)
+> * Maximum(max)
+> * Minimum(min)
+> * Count(count)
+
+The sample code is as follows:
+```cpp
+// Initialize the communicator
+Communicator _comm;
+// Initialize the property service address
+_comm.setProperty("property", "tars.tarsproperty.PropertyObj@ tcp -h xxx.xxx.xxx.xxx -p xxxx");
+
+// Initialize the distribution data range
+vector<int> v;
+v.push_back(10);
+v.push_back(30);
+v.push_back(50);
+v.push_back(80);
+v.push_back(100);
+
+// Create test1 attribute, this attribute uses all the statistics above, and pay attention to the initialization of distrv
+PropertyReportPtr srp = _comm.getStatReport()->createPropertyReport("test1", 
+PropertyReport::sum(), 
+PropertyReport::avg(), 
+PropertyReport::count(),
+PropertyReport::max(), 
+PropertyReport::min(),
+PropertyReport::distr(v));
+
+// Report data, property only supports int type data reporting
+int iValue = 0;
+for ( int i = 0; i < 10000000; i++ )
+{
+        sleep(1);
+     srp->report(rand() % 100 );
+}
+```
+
+Description:
+> * Data is reported regularly, and can be set in the configuration of the communicator, currently once per minute;
+> * Create a PropertyReportPtr function: The parameter createPropertyReport can be any collection of statistical methods, the example uses six statistical methods, usually only need to use one or two;
+> * Note that when you call createPropertyReport, you must create and save the created object after the service is enabled, and then just take the object to report, do not create it each time you use.
+

+ 47 - 0
docs-en/tars_protobuf_cpp.md

@@ -0,0 +1,47 @@
+# tars supports syntax of protobuf service
+
+Maybe there are a lots of businesses use by the protocol of protobuf that you have worked when you know tars.
+If you want to use tars for your businesses code, you must translate proto files into tars which is very troublesome and error prone.
+Pleasant is that tars provides direct support for proto files by using plugin mechanism of protoc.
+This mechanism can generate code about tars rpc automatically which makes you migration smooth and worry free.
+
+
+## Instructions
+
+
+### 1. write your proto files
+The syntax of the proto file is not limited, so you can use proto2 or proto3.
+But you must add **option cc_generic_services=false;** to your proto files.
+Because using the pb rpc interface generated by protoc it not our goal.
+Our goal is that taking over with the tars plugin to generate a rpc interface which conforms to the tars framework.
+An example of a proto file:
+
+
+```cpp
+syntax = "proto2";
+
+option cc_generic_services=false;
+
+package TestApp;
+
+message PbRequest {
+    required int32 a = 1;
+    required int32 b = 2;
+}
+
+message PbResponse { 
+    required int32 c = 1;
+}  
+
+service Hello {
+    rpc add(PbRequest) returns (PbResponse) {
+    }
+}
+```
+
+
+### 2. make
+Because of the statement that calls the tars pb plugin is already built into the makefile.tars, you just need to execute make.
+Tars plugin follows the rule that the file with a .pb.h suffix generated by protoc, so its generated file has a .tars.h suffix.
+
+

+ 685 - 0
docs-en/tars_push.md

@@ -0,0 +1,685 @@
+# The push function of the Tars
+
+# Contents
+> * [1.Background] 
+> * [2.Flow chart of the push mode]
+> * [3.Implement server-to-client push mode in Tars] 
+> * [4.Server function implementation] 
+> * [5.Client function implementation] 
+> * [6.Test results] 
+
+
+## Background
+
+In the actual application scenario, server-to-client push modes need to be supported in the TARS service framework.
+
+For example, see cpp/examples/pushDemo/.
+
+## Flow chart of the push mode
+Here's a flow chart of the push mode
+
+![tars](../docs/images/tars_flow.PNG)
+
+- The black line represents the data flow : data(client) -〉 request packet encoder(client) -〉 protocol parser(server) -〉 doRequest protocol processor(server) -〉 return data generation(server) -〉 response packet decoder(client) -〉 response data (client)
+- The yellow line represents the client access server
+- The blue line represents the server pushing the message to the client.
+- The **request packet encoder**(client)  is responsible for packaging and encoding the data sent by the client. The **protocol parser**(server) is responsible for unpacking the received data and handing it over to **protocol processor**(server).
+- The **protocol processor**(server) processes and generates the return data, while the **response packet decoder**(client) is responsible for decoding the returned data.
+
+## Implement server-to-client push mode in Tars:
+
+- For the server, first, the server needs to implement the protocol parser according to the mode of developing the third-party protocol (that is, the non-TARS protocol) and load it into the service. Then server need to establish a non-TARS service object, which inherits from the Servant class of the Tars framework, and establishes the protocol processor between the client and the server by overloading the doRequest method in the Servant class. The information of the client, who connected to the server, is saved in the method, so that the server can push the message to the client according to that information. Finally, the doClose method in the Servant class needs to be reloaded. After the server knows that the client closes the connection, the client's information saved in the doRequest method is released, so that the server does not need to push the message to the disconnected client. In addition, the server needs to establish a thread dedicated to push messages to the client.
+
+- For the client, the codec function of the protocol packet is implemented according to the mode of developing the third-party protocol, and it is set to the protocol parser of the corresponding ServantProxy proxy, and implemented by the `tars_set_protocol()` method of the `ServantProxy` class. Then you need to customize a callback class that inherits the `ServantProxyCallback` class. (Because the client receives the message from the server in an asynchronous manner, the client processes the message in an asynchronous manner.) At the same time, you need to override the `onDispatch()` method. In this method, the protocol defined between the client and the server is parsed. Finally, you need to create an instance of the callback class described above, and then pass it as a parameter to the `tars_set_push_callback()` method of `ServantProxy` class. In addition, the client needs to periodically send a message to the server (equivalent to a heartbeat packet) to tell the server that the client is alive. This is done because the server does not receive a message from the client within a certain period of time and automatically closes the connection between them. Before the server interacts with the client in push mode, the client needs to access the service by calling the rpc related function of the ServantProxy class.
+
+## Server function implementation
+
+### Server Implementation Overview
+First we deploy a TestPushServant service in accordance with the code of the third-party protocol. 
+Deploy a server on the management platform as shown below
+
+![tars](../docs/images/tars_push_deploy.PNG)
+
+Refer to the code that Tars supports third-party protocols:
+
+- The `initialize()` of the `TestPushServer` class loads the service object `TestPushServantImp` and sets a third-party protocol `parser`. The `parser` does not do any processing, and passes the received data packet to the service object for processing. But usually, the data is parsed before being handed over to the service object for processing.
+- `TestPushServantImp` overrides the `doRequest()` method that inherits from the `Servant` class, which is a protocol processor for third-party services. The processor is responsible for processing the data passed to it by the protocol parser and is responsible for generating the response returned to the client(This service is an echo service, so the response is directly equal to the received packet). At the same time, the server will save the information state of the client, so that the `pushThread` thread can push the message to the client.
+- In addition, `TestPushServantImp` overrides the `doClose()` method that inherits from the `Servant` class, and is used to clear the saved related customer information after the client closes the connection or the connection times out.
+
+
+### Server-implemented code
+TestPushServantImp.h
+```cpp
+#ifndef _TestPushServantImp_H_
+#define _TestPushServantImp_H_
+
+#include "servant/Application.h"
+//#include "TestPushServant.h"
+
+/**
+ *
+ *
+ */
+class TestPushServantImp : public  tars::Servant
+{
+public:
+    /**
+     *
+     */
+    virtual ~TestPushServantImp() {}
+
+    /**
+     *
+     */
+    virtual void initialize();
+
+    /**
+     *
+     */
+    virtual void destroy();
+
+    /**
+     *
+     */
+    virtual int test(tars::TarsCurrentPtr current) { return 0;};
+
+
+    //Overloading the doRequest method of the Servant class
+    int doRequest(tars::TarsCurrentPtr current, vector<char>& response);
+
+    //Overloading the doClose method of the Servant class
+    int doClose(tars::TarsCurrentPtr current);
+
+};
+/////////////////////////////////////////////////////
+#endif
+```
+TestPushServantImp.cpp
+```cpp
+#include "TestPushServantImp.h"
+#include "servant/Application.h"
+#include "TestPushThread.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////
+void TestPushServantImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+
+//////////////////////////////////////////////////////
+void TestPushServantImp::destroy()
+{
+    //destroy servant here:
+    //...
+}
+
+
+int TestPushServantImp::doRequest(tars::TarsCurrentPtr current, vector<char>& response)
+{
+//Save the client's information so that the client can push the message later.
+	(PushUser::mapMutex).lock();
+	map<string, TarsCurrentPtr>::iterator it = PushUser::pushUser.find(current->getIp());
+	if(it == PushUser::pushUser.end())
+	{
+		PushUser::pushUser.insert(map<string, TarsCurrentPtr>::value_type(current->getIp(), current));
+		LOG->debug() << "connect ip: " << current->getIp() << endl;
+	}
+	(PushUser::mapMutex).unlock();
+//Return the requested packet to the client, that is, return the original packet.
+	const vector<char>& request = current->getRequestBuffer();
+	response = request;
+
+	return 0;
+}
+//The client closes its connection with the server, or the server finds that the client has not 
+//sent the packet for a long time (more than 60s), and then closes the connection.
+int TestPushServantImp::doClose(TarsCurrentPtr current)
+{
+	(PushUser::mapMutex).lock();
+	map<string, TarsCurrentPtr>::iterator it = PushUser::pushUser.find(current->getIp());
+	if(it != PushUser::pushUser.end())
+	{
+		PushUser::pushUser.erase(it);
+		LOG->debug() << "close ip: " << current->getIp() << endl;
+	}
+	(PushUser::mapMutex).unlock();
+
+	return 0;
+}
+
+```
+TestPushThread.h
+```cpp
+
+#ifndef __TEST_PUSH_THREAD_H
+#define __TEST_PUSH_THREAD_H
+
+#include "servant/Application.h"
+
+class PushUser
+{
+public:
+	static map<string, TarsCurrentPtr> pushUser;
+	static TC_ThreadMutex mapMutex;
+};
+
+class PushInfoThread : public TC_Thread, public TC_ThreadLock
+{
+public:
+	PushInfoThread():_bTerminate(false),_tLastPushTime(0),_tInterval(10),_iId(0){}
+
+	virtual void run();
+
+	void terminate();
+
+	void setPushInfo(const string &sInfo);
+
+private:
+	bool _bTerminate;
+	time_t _tLastPushTime;
+	time_t _tInterval;
+	unsigned int _iId;
+	string _sPushInfo;
+};
+#endif
+
+
+```
+TestPushThread.cpp
+```cpp
+#include "TestPushThread.h"
+#include <arpa/inet.h>
+
+map<string, TarsCurrentPtr> PushUser::pushUser;
+TC_ThreadMutex PushUser::mapMutex;
+
+
+void PushInfoThread::terminate(void)
+{
+	_bTerminate = true;
+	{
+	    tars::TC_ThreadLock::Lock sync(*this);
+	    notifyAll();
+	}
+}
+
+void PushInfoThread::setPushInfo(const string &sInfo)
+{
+	  unsigned int iBuffLength = htonl(sInfo.size()+8);
+    unsigned char * pBuff = (unsigned char*)(&iBuffLength);
+
+    _sPushInfo = "";
+    for (int i = 0; i<4; ++i)
+    {
+        _sPushInfo += *pBuff++;
+    }
+
+    unsigned int iRequestId = htonl(_iId);
+    unsigned char * pRequestId = (unsigned char*)(&iRequestId);
+
+    for (int i = 0; i<4; ++i)
+    {
+        _sPushInfo += *pRequestId++;
+    }
+
+    _sPushInfo += sInfo;
+}
+//Push messages to customers on a regular basis
+void PushInfoThread::run(void)
+{
+	time_t iNow;
+
+	setPushInfo("hello world");
+
+	while (!_bTerminate)
+	{
+		iNow =  TC_TimeProvider::getInstance()->getNow();
+
+		if(iNow - _tLastPushTime > _tInterval)
+		{
+			_tLastPushTime = iNow;
+
+			(PushUser::mapMutex).lock();
+			for(map<string, TarsCurrentPtr>::iterator it = (PushUser::pushUser).begin(); it != (PushUser::pushUser).end(); ++it)
+			{
+				(it->second)->sendResponse(_sPushInfo.c_str(), _sPushInfo.size());
+				LOG->debug() << "sendResponse: " << _sPushInfo.size() <<endl;
+			}
+			(PushUser::mapMutex).unlock();
+		}
+
+		{
+            TC_ThreadLock::Lock sync(*this);
+            timedWait(1000);
+		}
+	}
+}
+
+```
+TestPushServer.h
+```cpp
+#ifndef _TestPushServer_H_
+#define _TestPushServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+#include "TestPushThread.h"
+
+
+using namespace tars;
+
+/**
+ *
+ **/
+class TestPushServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~TestPushServer() {};
+
+    /**
+     *
+     **/
+    virtual void initialize();
+
+    /**
+     *
+     **/
+    virtual void destroyApp();
+
+    private:
+    //Thread for push messages
+    PushInfoThread  pushThread;
+
+};
+
+extern TestPushServer g_app;
+
+////////////////////////////////////////////
+#endif
+
+```
+
+TestPushServer.cpp
+```cpp
+#include "TestPushServer.h"
+#include "TestPushServantImp.h"
+
+using namespace std;
+
+TestPushServer g_app;
+
+/////////////////////////////////////////////////////////////////
+
+static int parse(string &in, string &out)
+{
+    if(in.length() < sizeof(unsigned int))
+    {
+        return TC_EpollServer::PACKET_LESS;
+    }
+
+    unsigned int iHeaderLen;
+
+    memcpy(&iHeaderLen, in.c_str(), sizeof(unsigned int));
+
+    iHeaderLen = ntohl(iHeaderLen);
+
+    if(iHeaderLen < (unsigned int)(sizeof(unsigned int))|| iHeaderLen > 1000000)
+    {
+        return TC_EpollServer::PACKET_ERR;
+    }
+
+    if((unsigned int)in.length() < iHeaderLen)
+    {
+        return TC_EpollServer::PACKET_LESS;
+    }
+
+    out = in.substr(0, iHeaderLen);
+
+    in  = in.substr(iHeaderLen);
+
+    return TC_EpollServer::PACKET_FULL;
+}
+
+
+void
+TestPushServer::initialize()
+{
+    //initialize application here:
+    //...
+
+    addServant<TestPushServantImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".TestPushServantObj");
+
+    addServantProtocol("Test.TestPushServer.TestPushServantObj", parse);
+
+    pushThread.start();
+
+}
+/////////////////////////////////////////////////////////////////
+void
+TestPushServer::destroyApp()
+{
+    //destroy application here:
+    //...
+    pushThread.terminate();
+    pushThread.getThreadControl().join();
+
+}
+/////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+/////////////////////////////////////////////////////////////////
+```
+
+## Client function implementation
+
+### Client Implementation Overview
+This section describes how the client accesses the server through the proxy mode. The specific steps are as follows:
+- The client first establishes a communicator (Communicator _comm) and obtains a proxy through the communicator. The code is as follows:
+
+ ```cpp
+  string sObjName = "Test.TestPushServer.TestPushServantObj";
+  string sObjHost = "tcp -h 10.120.129.226 -t 60000 -p 10099";
+  _prx = _comm.stringToProxy<ServantPrx>(sObjName+"@"+sObjHost);
+```
+-  Write and set the request packet encoder and response packet decoder for the proxy. The code is as follows:
+  ```
+request packet encoder:
+static void FUN1(const RequestPacket& request, string& buff)
+response packet decoder:
+static size_t FUN2(const char* recvBuffer, size_t length, list<ResponsePacket>& done)
+The code to set the proxy:
+ProxyProtocol prot;
+prot.requestFunc = FUN1;
+prot.responseFunc = FUN2 ;
+_prx->tars_set_protocol(prot);
+
+```
+ - Synchronous or asynchronous methods to access the server
+ 
+    - Synchronization method: access the service by calling the proxy rpc_call method
+   ```
+	 virtual void rpc_call(uint32_t requestId, const string& sFuncName,const char* buff, uint32_t len, ResponsePacket& rsp);  
+   ```
+   The requestId parameter needs to be unique within the object, and a unique id in the object can be obtained through the `uint32_t tars_gen_requestid()` interface of the proxy. sFuncName is mainly used for statistical analysis of interface calls to the framework layer. It can be "" by default. Buff is the content to be sent, and len is the length of the buff. Rsp is the ResponsePacket package obtained for this call.
+
+    - Asynchronous method: access the service by calling the proxy rpc_call_asyc method    
+      ```
+			virtual void rpc_call_async(uint32_t requestId, const string& sFuncName, const char* buff, uint32_t len,  const ServantProxyCallbackPtr& callback);
+      ```
+      The requestId parameter needs to be unique within the object, and a unique id in the object can be obtained through the `uint32_t tars_gen_requestid()` interface of the proxy. sFuncName is the name of the function called after the response object responds. Buff is the content to be sent, and len is the length of the buff. Callback is the callback object that is responded to after this call returns the result (that is, after the server returns the processing result).
+
+- Set the push message method to accept the server:
+```
+TestPushCallBackPtr cbPush = new TestPushCallBack();
+_prx->tars_set_push_callback(cbPush);
+ ``` 
+  
+### Client-implemented code
+
+main.cpp
+```cpp
+#include "servant/Application.h"
+#include "TestRecvThread.h"
+#include <iostream>
+
+using namespace std;
+using namespace tars;
+
+int main(int argc,char**argv)
+{
+    try
+    {
+		RecvThread thread;
+		thread.start();
+
+		int c;
+		while((c = getchar()) != 'q');
+
+		thread.terminate();
+		thread.getThreadControl().join();
+    }
+    catch(std::exception&e)
+    {
+        cerr<<"std::exception:"<<e.what()<<endl;
+    }
+    catch(...)
+    {
+        cerr<<"unknown exception"<<endl;
+    }
+    return 0;
+}
+
+```
+TestRecvThread.h
+```
+#ifndef __TEST_RECV_THREAD_H
+#define __TEST_RECV_THREAD_H
+
+#include "servant/Application.h"
+
+class TestPushCallBack : public ServantProxyCallback
+{
+public:
+	virtual int onDispatch(ReqMessagePtr msg);
+};
+typedef tars::TC_AutoPtr<TestPushCallBack> TestPushCallBackPtr;
+
+class RecvThread : public TC_Thread, public TC_ThreadLock
+{
+public:
+	RecvThread();
+
+	virtual void run();
+
+	void terminate();
+private:
+	bool _bTerminate;
+
+	Communicator _comm;
+
+	ServantPrx  _prx;
+};
+#endif
+
+```
+TestRecvThread.cpp
+```
+#include "TestRecvThread.h"
+#include <iostream>
+#include <arpa/inet.h>
+
+/*
+ Response packet decoding function: Decode data received from the server according to a specific format, and parse it into ResponsePacket
+*/
+static size_t pushResponse(const char* recvBuffer, size_t length, list<ResponsePacket>& done)
+{
+	size_t pos = 0;
+    while (pos < length)
+    {
+        unsigned int len = length - pos;
+        if(len < sizeof(unsigned int))
+        {
+            break;
+        }
+
+        unsigned int iHeaderLen = ntohl(*(unsigned int*)(recvBuffer + pos));
+
+        //Do a length protection: the length cannot be greater than M or less than sizeof (unsigned int)
+        if (iHeaderLen > 100000 || iHeaderLen < sizeof(unsigned int))
+        {
+            throw TarsDecodeException("packet length too long or too short,len:" + TC_Common::tostr(iHeaderLen));
+        }
+
+        //Did not receive the complete packet
+        if (len < iHeaderLen)
+        {
+            break;
+        }
+        else
+        {
+            ResponsePacket rsp;
+			rsp.iRequestId = ntohl(*((unsigned int *)(recvBuffer + pos + sizeof(unsigned int))));
+			rsp.sBuffer.resize(iHeaderLen - 2*sizeof(unsigned int));
+		  ::memcpy(&rsp.sBuffer[0], recvBuffer + pos + 2*sizeof(unsigned int), iHeaderLen - 2*sizeof(unsigned int));
+
+			pos += iHeaderLen;
+
+            done.push_back(rsp);
+        }
+    }
+
+    return pos;
+}
+/*
+   Request packet encoding function
+   The packing format of this function: the entire packet length (bytes) + iRequestId (bytes) + package contents
+*/
+static void pushRequest(const RequestPacket& request, string& buff)
+{
+    unsigned int net_bufflength = htonl(request.sBuffer.size()+8);
+    unsigned char * bufflengthptr = (unsigned char*)(&net_bufflength);
+
+    buff = "";
+    for (int i = 0; i<4; ++i)
+    {
+        buff += *bufflengthptr++;
+    }
+
+    unsigned int netrequestId = htonl(request.iRequestId);
+    unsigned char * netrequestIdptr = (unsigned char*)(&netrequestId);
+
+    for (int i = 0; i<4; ++i)
+    {
+        buff += *netrequestIdptr++;
+    }
+
+    string tmp;
+    tmp.assign((const char*)(&request.sBuffer[0]), request.sBuffer.size());
+    buff+=tmp;
+}
+
+static void printResult(int iRequestId, const string &sResponseStr)
+{
+	cout << "request id: " << iRequestId << endl;
+	cout << "response str: " << sResponseStr << endl;
+}
+static void printPushInfo(const string &sResponseStr)
+{
+	cout << "push message: " << sResponseStr << endl;
+}
+
+int TestPushCallBack::onDispatch(ReqMessagePtr msg)
+{
+	if(msg->request.sFuncName == "printResult")
+	{
+		string sRet;
+		cout << "sBuffer: " << msg->response.sBuffer.size() << endl;
+		sRet.assign(&(msg->response.sBuffer[0]), msg->response.sBuffer.size());
+		printResult(msg->request.iRequestId, sRet);
+		return 0;
+	}
+	else if(msg->response.iRequestId == 0)
+	{
+		string sRet;
+		sRet.assign(&(msg->response.sBuffer[0]), msg->response.sBuffer.size());
+		printPushInfo(sRet);
+		return 0;
+	}
+	else
+	{
+		cout << "no match func!" <<endl;
+	}
+	return -3;
+}
+
+RecvThread::RecvThread():_bTerminate(false)
+{
+	string sObjName = "Test.TestPushServer.TestPushServantObj";
+    string sObjHost = "tcp -h 10.120.129.226 -t 60000 -p 10099";
+
+    _prx = _comm.stringToProxy<ServantPrx>(sObjName+"@"+sObjHost);
+
+	ProxyProtocol prot;
+    prot.requestFunc = pushRequest;
+    prot.responseFunc = pushResponse;
+
+    _prx->tars_set_protocol(prot);
+}
+
+void RecvThread::terminate()
+{
+	_bTerminate = true;
+	{
+	    tars::TC_ThreadLock::Lock sync(*this);
+	    notifyAll();
+	}
+}
+
+void RecvThread::run(void)
+{
+	TestPushCallBackPtr cbPush = new TestPushCallBack();
+	_prx->tars_set_push_callback(cbPush);	
+
+	string buf("heartbeat");
+
+	while(!_bTerminate)
+	{
+		{
+			try
+			{
+				TestPushCallBackPtr cb = new TestPushCallBack();
+				_prx->rpc_call_async(_prx->tars_gen_requestid(), "printResult", buf.c_str(), buf.length(), cb);
+			}
+			catch(TarsException& e)
+			{     
+				cout << "TarsException: " << e.what() << endl;
+			}
+			catch(...)
+			{
+				cout << "unknown exception" << endl;
+			}
+		}
+
+		{
+            TC_ThreadLock::Lock sync(*this);
+            timedWait(5000);
+		}
+	}
+}
+
+```
+
+
+## Client test results
+
+If the server pushes to the client successfully, the result is as follows:
+
+![tars](../docs/images/tars_result.PNG)
+
+
+
+
+
+

BIN
docs/images/tars_cpp_quickstart_bushu1.png


BIN
docs/images/tars_cpp_quickstart_bushu2.png


BIN
docs/images/tars_cpp_quickstart_patch.png


BIN
docs/images/tars_cpp_quickstart_patchresult.png


BIN
docs/images/tars_cpp_quickstart_upload.png


BIN
docs/images/tars_cpp_third_protocol.png


BIN
docs/images/tars_web_index.png


+ 178 - 0
docs/tars_cpp_develop_specification.md

@@ -0,0 +1,178 @@
+# 目录
+> * 命名规范
+> * Tars文件目录规范
+> * Makefile规范
+
+# 1. 命名规范
+
+## 1.1.	服务命名
+
+APP:应用名,标识一组服务的一个小集合,在Tars系统中,应用名必须唯一。例如:TestApp。
+
+Server:服务名,提供服务的进程名称,Server名字根据业务服务功能命名,一般命名为:XXServer,例如LogServer,TimerServer等;
+
+Servant:服务者,提供具体服务的接口或实例。例如:HelloImp
+
+说明:
+
+一个Server可以包含多个Servant,系统会使用服务的App + Server + Servant,进行组合,来定义服务在系统中的路由名称,称为路由Obj,其名称在整个系统中必须是唯一的,以便在对外服务时,能唯一标识自身。
+
+因此在定义APP时,需要注意APP的唯一性。
+
+例如:Comm.TimerServer.TimerObj,Comm.LogServer.LogServerObj等;
+
+## 1.2. Namespace命名
+
+每个业务都有一个不同的名称,即Application名称,该名称也做为该Application下面所有代码的namespace。
+
+因此namespace一般为业务的名称,例如:
+```
+namespace Comm
+```
+
+## 1.3.	class命名(接口名)
+
+class 的名字必须由一个或多个能表达该类的意思的单词或缩写组成,单词首字母大写。
+
+例如:
+```
+class HelloWorldApp
+```
+
+## 1.4.	方法命名
+
+函数的命名是以能表达函数的动作意义为原则的,一般是由动词打头,然后跟上表示动作对象的名词。小写字母开头,后面每个单词首字母大写。
+
+另外,还有一些通用的函数命名规则。
+
+取数用get打头,然后跟上要取的对象的名字;
+
+设置用set打头,然后跟上要设的对象的名字;
+
+对象中响应消息进行动作的函数,以on打头,然后是相应的消息的名称;
+
+进行主动动作的函数,可以命名为do打头,然后是相应的动作名称;
+
+用 has 或者 can 来代替布尔型获取函数的 is 前缀,意义更加明确。
+
+例如:
+```
+getNumber(); 
+
+setNumber(); 
+      
+onProcess(); 
+
+doAddFile();
+
+hasFile();
+
+canPrint();
+
+sendMessage(); 
+```
+
+## 1.5.	变量命名规则
+
+对于各种变量的定义,都有一个共同点,就是应该使用有实际意义的英文单词或英文单词缩写,不要使用简单的没有意义的字串,尽可能不使用阿拉伯数字,更切忌使用中文拼音的首字母。
+
+如这样的名称是不提倡的:Value1,Value2,Value3,Value4…。
+
+一般规则为:小写字母开头,后面每个单词的首字母大写,一般为名词。(如果只有一个单词,则小写)
+
+userNo(手机号)、station(省份)、destNo(目的号码)、srcNo(源号码)等等
+
+其他: 对于一些比较重要的数,最好用常量替代,而不要直接写数,常量全部大写,多个单词之间以下划线分隔开。
+
+NUMBER_OF_GIRLFRIENDS
+
+# 2. Tars文件目录规范
+
+Tars文件是TARS服务的协议通信接口,因此非常重要,在管理上必须按照以下规范:
+
+tars文件原则上和相应的server放在一起;
+
+每个server在开发机上建立/home/tarsproto/[namespace]/[server]子目录;
+
+所有tars文件需要更新到/home/tarsproto下相应server的目录;
+
+使用其他server的tars文件时,需要到/home/tarsproto中使用,不能copy到本目录下,见Makefile规范;
+
+tars的接口原则上只能增加,不能减少或修改;
+
+makefile里面运行make release会自动完成相关操作,详见Makefile规范;
+
+说明:
+
+make release会将tars文件copy到/home/tarsproto/[namespace]/[server]目录下,同时生成调用tars2cpp生成.h, 并生成一个[server].mk文件;其他调用该服务时,在makefile底部包含这个mk文件即可。
+
+# 3. Makefile规范
+
+使用Tars实现的服务,强烈建议使用该Makefile规范。
+
+TARS框架提供了一个makefile.tars的基础Makefile,采用Tars编写的服务包含该Makefile会有效的帮助你对Makefile的维护;
+
+TARS框架也提供了脚本(安装目录/script/create_tars_server.sh)可以自动生成空的服务框架和Makefile;
+
+## 3.1. Makefile使用原则
+
+原则上一个目录只能是一个Server或者程序,即Makefile只能有一个Target;
+
+需要包含其他库时,根据依赖关系倒序include在Makefile文件底部;
+
+例如:
+```
+include /home/tarsproto/TestApp/HelloServer/HelloServer.mk
+include /usr/local/tars/cpp/makefile/makefile.tars
+```
+makefile.tars必须包含。
+
+## 3.2. Makefile模板解释
+
+APP:程序的名字空间(即Application)
+
+TARGET:Server名称;
+
+CONFIG:配置文件名称,make tar时将该文件包含在tar包中;
+
+INCLUDE:其他需要包含的路径;
+
+LIB: 需要的库
+
+Test.HelloServer的makefile实例如下:
+```
+#-----------------------------------------------------------------------
+
+APP           := TestApp
+TARGET        := HelloServer
+CONFIG        := HelloServer.conf
+STRIP_FLAG    := N
+TARS2CPP_FLAG  :=
+
+INCLUDE       += 
+LIB           += 
+
+#-----------------------------------------------------------------------
+
+include /home/tarsproto/TestApp/HelloServer/HelloServer.mk
+include /usr/local/tars/cpp/makefile/makefile.tars
+```
+关键的变量,通常不用,但是业务可以在这些变量后面添加自己的值:
+```
+RELEASE_TARS:需要发布在/home/tarsproto/目录下面的tars文件,如果需要把自己.h也发布到/home/tarsproto则可以如下:
+RELEASE_TARS += xxx.h
+CONFIG:配置文件名称,其实后面可以增加自己需要的文件,这样在调用make tar时也会把该文件包含到tar包中;
+```
+其他变量请阅读makefile.tars。
+
+## 3.3.	Makefile使用
+
+make help:可以看到makefile所有使用功能。
+
+make tar:生成发布文件
+
+make release:copy tars文件到/home/tarsproto相应目录,并自动生成相关的mk文件
+
+make clean:清除
+
+make cleanall:清除所有

+ 52 - 0
docs/tars_cpp_faq.md

@@ -0,0 +1,52 @@
+
+1. Tars C++开发环境如何搭建?
+> * 参考tars_install.md
+
+2. Tars C++如何快速上手?
+> * 文档参考tars_cpp_quickstart.md,相关示例代码参考cpp/examples目录
+
+3. tars/tup协议是什么?
+> * 具体参考tars_tup.md
+
+4. Tars C++是否支持自定义协议(比如:http)?
+> * Tars C++除了支持tars/tup协议之外,还支持业务自定义协议,具体参考tars_cpp_thirdprotocol.md
+
+5. Tars C++如何拉取业务配置文件?
+> * Tars C++支持通过使用addConfig方法获取指定的业务配置文件,业务配置相关远离,可以参考tars_config.md
+
+6. 在Tars框架中运行的服务是如何被监控的?
+> * 具体参考tars_server_monitor.md
+
+7. Tars C++通讯器如何创建?
+> * 如果服务基于TAF框架,请直接从Applicatin获取,不要自己创建。例如: 
+```
+Application::getCommunicator()->stringToProxy<NotifyPrx>(ServerConfig::Notify);
+```
+> * 如果服务非基于TAF框架,只是TAF客户端,可以用new Communicator(conf) 初始化通信器。例如:
+``` 
+TC_Config conf(“config.conf”);
+CommunicatorPtr c = new Communicator(conf);
+```
+
+8. Tars C++调用的超时时间如何设置?
+> * 具体参考tars_cpp_user_guide.md
+
+9. 服务发布后但没有运行怎么查看原因?
+> * 是否服务配置文件没有正确获取。例如:在web平台上配置的配置文件名与在程序add下载的配置文件名不一致。
+> * 查找问题时,首先看web上"服务当前报告"是否提示正常,例如:配置文件有没下载成功,服务启动时下载的配置文件。
+> * 再查找服务自己打印log日志。日志一般在/usr/local/app/tars/app_log/应用名/服务名/目录下。
+> * 若仍有问题请查看node日志。
+
+10. core文件如何打开,生成在什么地方?
+> * core文件是在tafnode启动脚本添加ulimite -c unlimited 打开,目前core文件生成在 /usr/local/app/tars/app_log下.
+
+11. 主控Registry故障是否会影响业务服务的正常访问?
+> * 不会影响业务服务正常访问,框架底层会缓存后端服务的ip列表。
+
+12. 通讯器Communicator是如何通过ServerName获取ip:prot的?
+> * 1.创建代理,并不会请求主控获取ip列表,而是调用代理的接口时才会触发请求主控ip列表
+> * 2.如果obj后面有ip列表信息,相当于直连,这个是不会请求主控registry的
+> * 3.如果obj后面没有ip列表信息,相当于是间接方式,会请求主控registry
+> * 4.请求主控registry的策略时,如果本地缓存有请求obj的ip列表,用本地缓存的,同时去异步请求一下主控registry获取最新的ip列表
+> * 5.请求主控registry的策略时,如果本地缓存没有请求obj的ip列表,业务的请求会先缓存到队列里,同时异步去请求主控获取ip列表,获取到ip列表后,再从队列里把业务的请求拿出来,发送这个请求
+> * 6.6.不是每次都刷新,定时刷新的(默认60s),定时刷新的触发是靠业务请求

+ 88 - 0
docs/tars_cpp_future_promise.md

@@ -0,0 +1,88 @@
+# Tars框架Future/Promise使用
+
+在采用tars2cpp工具自动生成c++文件时,相应的file.tars会自动生成file.h文件。在.h文件里会生成你自定义接口的RPC方法,一共有四种:
+
+*   同步sync方法;
+*   异步async方法;
+*   Future/Promise方法;
+*   协程coco方法;
+
+sync/async方法在文档里都有[使用的样例](https://github.com/Tencent/Tars/blob/master/docs/tars_cpp_quickstart.md),对于不满足sync/async,然后想在Tars下使用Future/Promise的同学看看此文或许会有帮助。
+
+文章内容、样例都是基于Tars框架下提供的Future/Promise进行分析,与boost、C++11、以及其他语言提供的Future/Promise不完全相同。
+
+&nbsp;
+
+## **Future/Promise是什么?**
+
+Future与Promise其实是二个完全不同的东西:
+
+> Future:用来表示一个尚未有结果的对象,而产生这个结果的行为是异步操作;
+> 
+> Promise:Future对象可以使用Promise对象来创建(getFuture),创建后,Promise对象保存的值可以被Future对象读取,同时将二个对象共享状态关联起来。可以认Promise为Future结果同步提供了一种手段;
+
+简而言之就是:**他们提供了一套非阻塞并行操作的处理方案,当然,你也可以阻塞操作来等待Future的结果返回。**
+
+&nbsp;
+
+## **Future/Promise适用什么场景?**
+
+通过一个虚拟的例子来说明:**你想买房,然后通过微信联系中介看看行情并询问一些信息,最后拿到所有的信息汇总后再评估。**
+
+我们假如有中介A、B、C,并且不考虑超时情况。
+
+**同步的做法**:我们先微信询问A,等待A的回复,接着询问B,等待B的回复,最后询问C,等待C的回复;
+
+**异步的做法**:我们先微信询问A,在等待A回复的同时,可以干干其他事情(比如看电视,处理工作),等到A回复后再依次询问B,C;
+
+**Future/Promise的做法**同时给A、B、C发消息询问,等待回复的同时干其他事情,一直到所有回复都响应;
+
+**根据经验,在这种场景下Future/Promise才是最合适的做法。**
+
+因为对于这种场景,询问中介A、B、C是三个没有任何耦合的任务(简单理解就是顺序可以打乱的任务,相互之间无依赖,A-&gt;B-&gt;C,C-&gt;B-&gt;A的结果一样),所使用Future/Promise的思想最适合。
+
+&nbsp;
+
+## **Future/Promise代码例子**
+
+假设我们有一Test应用,他的TestServer内部TestServant提供了Echo服务的接口“EchoTest”。
+
+```cpp
+//省略了对应头文件
+//回调函数
+void handleAll(const promise::Future<promise::Tuple<promise::Future<TestServantPrxCallbackPromise::PromisetestPtr>, 
+                    promise::Future<TestServantPrxCallbackPromise::PromisetestPtr> > > &result)
+{
+    promise::Tuple<promise::Future<TestServantPrxCallbackPromise::PromisetestPtr>, promise::Future<TestServantPrxCallbackPromise::PromisetestPtr> > out = result.get();
+ 
+    promise::Future<TestServantPrxCallbackPromise::PromisetestPtr> out1 = out.get<0>();
+    const tars::TC_AutoPtr<TestServantPrxCallbackPromise::Promisetest> print1 = out1.get();
+ 
+    promise::Future<TestServantPrxCallbackPromise::PromisetestPtr> out2 = out.get<1>();
+    const tars::TC_AutoPtr<TestServantPrxCallbackPromise::Promisetest> print2 = out2.get();
+ 
+    DEBUGLOG("handleAll:" << print1->_ret << "|" << print1->outStr << "|out2:" << print2->_ret << "|" << print2->outStr);
+}
+ 
+int main()
+{
+    map<string, string> ctx;
+    TestServantPrx testPrx = Application::getCommunicator()->stringToProxy<TestServantPrx>("Test.TestServer.TestServant");
+ 
+    promise::Future<TestServantPrxCallbackPromise::PromisetestPtr > result1 = testPrx->promise_async_EchoTest("manmanlu1", ctx);
+    promise::Future<TestServantPrxCallbackPromise::PromisetestPtr > result2 = testPrx->promise_async_EchoTest("manmanlu2", ctx);
+ 
+    promise::Future<promise::Tuple<promise::Future<TestServantPrxCallbackPromise::PromisetestPtr>, promise::Future<TestServantPrxCallbackPromise::PromisetestPtr> > > r =
+        promise::whenAll(result1, result2);
+    r.then(tars::TC_Bind(&handleAll));
+ 
+    DEBUGLOG("Test Future-Promise done");
+}
+```
+输出的结果为:
+```
+Test Future-Promise done
+handleAll:0|manmanlu1|out2:0|manmanlu2
+```
+
+可以看到异步回调正常触发。

+ 237 - 0
docs/tars_cpp_http_demo.md

@@ -0,0 +1,237 @@
+# 其他协议支持
+
+## 概述
+TARS服务框架默认情况下只支持TARS自有的tars协议,但是在实际的应用场景中,需要在TARS服务框架中支持其他协议,例如HTTP,这种情况下就不能用通信器来发送据,需要业务自己来实现这部分代码。对于自定义的协议, 处理方式也类似
+
+具体程序示例,参见cpp/examples/httpDemo/.
+
+开发第三方协议服务端,要实现协议解析器并将其加载到服务中,同时需要建立一个非TAF框架的服务对象,该类继承于Servant类,通过重载Servant类中的doRequest方法来建立协议处理器。
+而客户端要访问服务,需要通过调用proxy的rpc函数,在调用之前,要为proxy设置请求包编码函数和响应包解码函数。
+
+![tars](images/tars_cpp_third_protocol.png)
+
+图中的黑色线代表了数据流向:数据(客户端)-〉请求包的编码器(客户端)-〉协议解析器(服务端)-〉doRequest协议处理器(服务端)-〉生成返回数据(服务端)-〉响应包的解码器(客户端)-〉响应数据(客户端)
+
+其中请求包的编码器(客户端)负责对客户端发送的数据进行打包,协议解析器(服务端)负责对收到的数据进行解析并交给协议处理器(服务端)去处理并生成返回数据,而响应包的解码器(客户端)负责对返回的数据进行解码。
+
+## 	服务端Http协议实例
+
+
+/usr/local/tars/cpp/script/create_tars_server.sh TestApp HttpServer Http
+
+在目录下会生成六个文件,将http.tars 删除(因为不是tars协议),然后手动的实现一些方法
+
+以HelloServer为例,需要支持http协议
+
+在HttpImp中修改继承自Servant类的doRequest方法,该方法为第三方服务的处理器,该处理器负责处理协议解析器传送给其的数据,并负责生成返回给客户端的response
+
+HttpImp.h
+```cpp
+#ifndef _HttpImp_H_
+#define _HttpImp_H_
+
+#include "servant/Application.h"
+
+/**
+ *
+ *
+ */
+class HttpImp : public Servant
+{
+public:
+    /**
+     *
+     */
+    virtual ~HttpImp() {}
+
+    /**
+     *
+     */
+    virtual void initialize();
+
+    /**
+     *
+     */
+    virtual void destroy();
+
+    /**
+     *
+     */
+    int doRequest(TarsCurrentPtr current, vector<char> &buffer);
+
+};
+/////////////////////////////////////////////////////
+#endif
+```
+HttpImp.cpp
+```cpp
+#include "HttpImp.h"
+#include "servant/Application.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////
+void HttpImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+
+//////////////////////////////////////////////////////
+void HttpImp::destroy()
+{
+    //destroy servant here:
+    //...
+}
+
+int HttpImp::doRequest(TarsCurrentPtr current, vector<char> &buffer)
+{
+    TC_HttpRequest request; 
+    vector<char> v = current->getRequestBuffer();
+    string sBuf;
+    sBuf.assign(&v[0],v.size());
+    request.decode(sBuf);
+    TC_HttpResponse rsp;
+    string s="hello";
+    rsp.setResponse(s.c_str(),s.size());
+    rsp.encode(buffer);
+   
+    return 0;
+}
+```
+
+
+在其中HttpServer类的initialize(),加载服务对象HttpImp,并设置第三方协议解析器parse。
+我们在函数中实现HttpProtocol::parse函数,用于解析协议。
+```cpp
+#ifndef _HttpServer_H_
+#define _HttpServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+
+using namespace tars;
+
+/**
+ *
+ **/
+class HttpServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~HttpServer() {};
+
+    /**
+     *
+     **/
+    virtual void initialize();
+
+    /**
+     *
+     **/
+    virtual void destroyApp();
+};
+
+extern HttpServer g_app;
+
+////////////////////////////////////////////
+#endif
+```
+
+```cpp
+#include "HttpServer.h"
+#include "HttpImp.h"
+
+using namespace std;
+
+HttpServer g_app;
+
+/////////////////////////////////////////////////////////////////
+struct HttpProtocol
+{
+    /**
+     * 解析http请求
+     * @param in
+     * @param out
+     *
+     * @return int
+     */
+    static int parseHttp(string &in, string &out)
+    {
+        try
+        {
+            //判断请求是否是HTTP请求
+            bool b = TC_HttpRequest ::checkRequest(in.c_str(), in.length());
+            //完整的HTTP请求
+            if(b)
+            {
+                out = in;
+                in  = "";
+                //TLOGDEBUG("out size: " << out.size() << endl);
+                return TC_EpollServer::PACKET_FULL;
+            }
+            else
+            {
+                return TC_EpollServer::PACKET_LESS;
+            }
+        }
+        catch(exception &ex)
+        {
+            return TC_EpollServer::PACKET_ERR;
+        }
+
+        return TC_EpollServer::PACKET_LESS;             //表示收到的包不完全
+    }
+
+};
+
+void
+HttpServer::initialize()
+{
+    //initialize application here:
+    //...
+
+    addServant<HttpImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".HttpObj");
+    addServantProtocol(ServerConfig::Application + "." + ServerConfig::ServerName + ".HttpObj",&HttpProtocol::parseHttp);
+}
+/////////////////////////////////////////////////////////////////
+void
+HttpServer::destroyApp()
+{
+    //destroy application here:
+    //...
+}
+/////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+/////////////////////////////////////////////////////////////////
+```
+
+
+
+
+
+
+
+
+
+
+

+ 486 - 0
docs/tars_cpp_quickstart.md

@@ -0,0 +1,486 @@
+# 目录
+> * [1.环境搭建] (#main-chapter-1)
+> * [2.服务命名] (#main-chapter-2)
+> * [3.Tars管理系统] (#main-chapter-3)
+> * [4.服务部署] (#main-chapter-4)
+> * [5.服务开发] (#main-chapter-5)
+> * [6.服务发布] (#main-chapter-6)
+
+# 1. 环境搭建  <a id="main-chapter-1"></a>
+
+Tars C++环境搭建参考tars_install.md
+ 
+# 2. 服务命名  <a id="main-chapter-2"></a>
+
+使用Tars框架的服务,其的服务名称有三个部分:
+
+APP:    应用名,标识一组服务的一个小集合,在Tars系统中,应用名必须唯一。例如:TestApp;
+
+Server: 服务名,提供服务的进程名称,Server名字根据业务服务功能命名,一般命名为:XXServer,例如HelloServer;
+
+Servant:服务者,提供具体服务的接口或实例。例如:HelloImp;
+
+说明:
+
+一个Server可以包含多个Servant,系统会使用服务的App + Server + Servant,进行组合,来定义服务在系统中的路由名称,称为路由Obj,其名称在整个系统中必须是唯一的,以便在对外服务时,能唯一标识自身。
+
+因此在定义APP时,需要注意APP的唯一性。
+
+例如:TestApp.HelloServer.HelloObj。
+
+# 3. Tars管理系统  <a id="main-chapter-3"></a>
+
+用户登录成功后,会进入Tars管理系统,如下图
+
+![tars](images/tars_web_index.png)
+
+TARS管理系统的菜单树下,有以下功能:
+
+- 业务管理:包括已部署的服务,以及服务管理、发布管理、服务配置、服务监控、特性监控等;
+
+- 运维管理:包括服务部署、扩容、模版管理等;
+
+# 4. 服务部署   <a id="main-chapter-4"></a>
+
+服务部署,其实也可以在服务开发后进行,不过建议先做。
+
+如下图:
+
+![tars](images/tars_cpp_quickstart_bushu1.png)
+
+-	“应用”指你的服务程序归在哪一个应用下,例如:“TestApp”。
+-	“服务名称”指你的服务程序的标识名字,例如:“HelloServer”。
+-	“服务类型”指你的服务程序用什么语言写的,例如:c++的选择“tars_cpp”。
+-	“模版“ 指你的服务程序在启动时,设置的配置文件的名称,默认用”tars.default“即可。
+-	“节点“ 指服务部署的机器IP。
+-	“Set分组“ 指设置服务的Set分组信息,Set信息包括3部分:Set名、Set地区、Set组名。
+-	“OBJ名称“ 指Servant的名称。
+-	“OBJ绑定IP“ 指服务绑定的机器IP,一般与节点一样。
+-	“端口“ 指OBJ要绑定的端口。
+-	“端口类型“ 指使用TCP还是UDP。
+-	“协议“ 指应用层使用的通信协议,Tars框架默认使用tars协议。
+-	“线程数“ 指业务处理线程的数目。
+-	“最大连接数“ 指支持的最大连接数。
+-	“队列最大长度“ 指请求接收队列的大小。
+-	“队列超时时间“ 指请求接收队列的超时时间。
+
+点击“提交“,成功后,菜单数下的TestApp应用将出现HelloServer名称,同时将在右侧看到你新增的服务程序信息,如下图:
+
+![tars](images/tars_cpp_quickstart_bushu2.png)
+
+在管理系统上的部署暂时先到这里,到此为止,只是使你的服务在管理系统上占了个位置,真实程序尚未发布。
+
+# 5. 服务开发  <a id="main-chapter-5"></a>
+
+## 5.1. 创建服务
+
+### 5.1.1. 运行tars脚本
+``` shell
+/usr/local/tars/cpp/script/create_tars_server.sh [App] [Server] [Servant]
+```
+
+本例中执行:/usr/local/tars/cpp/script/create_tars_server.sh TestApp HelloServer Hello
+
+命令执行后,会在当前目录的TestApp/HelloServer/ 目录下,生成下面文件:
+``` shell
+HelloServer.h HelloServer.cpp Hello.tars HelloImp.h HelloImp.cpp makefile
+```
+这些文件,已经包含了最基本的服务框架和默认测试接口实现。
+
+### 5.1.2. tars接口文件
+
+定义tars接口文件的语法和使用,参见tars_tup.md。
+
+如下:
+
+Hello.tars:
+``` cpp
+
+module TestApp
+{
+
+interface Hello
+{
+    int test();
+};
+
+}; 
+
+
+```
+采用tars2cpp工具自动生成c++文件:/usr/local/tars/cpp/tools/tars2cpp hello.tars会生成hello.h文件,里面包含客户端和服务端的代码。
+
+### 5.1.3. HelloImp是Servant的接口实现类
+
+实现服务定义的tars件中的接口,如下:
+
+HelloImp.h
+
+```cpp
+
+#ifndef _HelloImp_H_
+#define _HelloImp_H_
+
+#include "servant/Application.h"
+#include "Hello.h"
+
+/**
+ * HelloImp继承hello.h中定义的Hello对象
+ *
+ */
+class HelloImp : public TestApp::Hello
+{
+public:
+    /**
+     *
+     */
+    virtual ~HelloImp() {}
+
+    /**
+     * 初始化,Hello的虚拟函数,HelloImp初始化时调用
+     */
+    virtual void initialize();
+
+    /**
+     * 析构,Hello的虚拟函数,服务析构HelloImp退出时调用
+     */
+    virtual void destroy();
+
+    /**
+     * 实现tars文件中定义的test接口
+     */
+    virtual int test(tars::TarsCurrentPtr current) { return 0;};
+
+};
+/////////////////////////////////////////////////////
+#endif
+
+```
+HelloImp.cpp:
+
+```cpp
+
+#include "HelloImp.h"
+#include "servant/Application.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////
+void HelloImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+
+//////////////////////////////////////////////////////
+void HelloImp::destroy()
+{
+    //destroy servant here:
+    //...
+}
+
+```
+### 5.1.4. HelloServer是服务的实现类
+
+如下:
+
+HelloServer.h:
+
+```cpp
+#ifndef _HelloServer_H_
+#define _HelloServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+
+using namespace tars;
+
+/**
+ * HelloServer继承框架的Application类
+ **/
+class HelloServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~HelloServer() {};
+
+    /**
+     * 服务的初始化接口
+     **/
+    virtual void initialize();
+
+    /**
+     * 服务退出时的清理接口
+     **/
+    virtual void destroyApp();
+};
+
+extern HelloServer g_app;
+
+////////////////////////////////////////////
+#endif
+
+```
+HelloServer.cpp
+```cpp
+#include "HelloServer.h"
+#include "HelloImp.h"
+
+using namespace std;
+
+HelloServer g_app;
+
+/////////////////////////////////////////////////////////////////
+void
+HelloServer::initialize()
+{
+    //initialize application here:
+
+    //添加Servant接口实现类HelloImp与路由Obj绑定关系
+    addServant<HelloImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".HelloObj");
+}
+/////////////////////////////////////////////////////////////////
+void
+HelloServer::destroyApp()
+{
+    //destroy application here:
+    //...
+}
+/////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+/////////////////////////////////////////////////////////////////
+
+```
+## 5.2. 服务编译
+
+进入代码目录,首先做
+```shell
+make cleanall
+make	
+make tar
+``` 
+## 5.3. 扩展功能
+
+Tars框架提供了接口定义语言的功能,可以在tars文件中,增加一下接口和方法,扩展服务的功能。 
+
+可以修改由create_tars_server.sh生成的tars文件,以下3个接口方法中,test是默认生成的,testHello是新增加的接口。
+```cpp
+
+module TestApp
+{
+
+interface Hello
+{
+    int test();
+    int testHello(string sReq, out string sRsp);
+};
+
+}; 
+
+```
+
+使用/usr/local/tars/cpp/tools/tars2cpp hello.tars,重新生成hello.h。 
+
+修改HelloImp.h/HelloImp.cpp,实现新的接口代码。 
+
+其中HelloImp.h中继承Hello类的testHello方法: 
+```cpp
+virtual int testHello(const std::string &sReq, std::string &sRsp, tars::TarsCurrentPtr current);
+```
+
+HelloImp.cpp实现testHello方法:
+
+```cpp
+int HelloImp::testHello(const std::string &sReq, std::string &sRsp, tars::TarsCurrentPtr current)
+{
+    TLOGDEBUG("HelloImp::testHellosReq:"<<sReq<<endl);
+    sRsp = sReq;
+    return 0;
+}
+```
+重新make cleanall;make;make tar,会重新生成HelloServer.tgz发布包。
+
+## 5.4. 客户端同步/异步调用服务
+
+在开发环境上,创建/home/tarsproto/[APP]/[Server]目录。 
+
+例如:/home/tarsproto/TestApp/HelloServer在刚才编写服务器的代码目录下,
+
+执行 make release 这时会在/home/tarsproto/TestApp/HelloServer目录下生成h、tars和mk文件。
+
+这样在有某个服务需要访问HelloServer时,就直接引用HelloServer服务make release的内容,不需要把HelloServer的tars拷贝过来(即代码目录下不需要存放HelloServer的tars文件)。
+
+建立客户端代码目录,如TestHelloClient/。 
+
+编写main.cpp,创建实例并调用刚编写的接口函数进行测试。 
+
+同步方式:
+
+```cpp
+#include <iostream>
+#include "servant/Communicator.h"
+#include "Hello.h"
+
+using namespace std;
+using namespace TestApp;
+using namespace tars;
+
+int main(int argc,char ** argv)
+{
+    Communicator comm;
+
+    try
+    {
+        HelloPrx prx;
+        comm.stringToProxy("TestApp.HelloServer.HelloObj@tcp -h 10.120.129.226 -p 20001" , prx);
+
+        try
+        {
+            string sReq("hello world");
+            string sRsp("");
+
+            int iRet = prx->testHello(sReq, sRsp);
+            cout<<"iRet:"<<iRet<<" sReq:"<<sReq<<" sRsp:"<<sRsp<<endl;
+
+        }
+        catch(exception &ex)
+        {
+            cerr << "ex:" << ex.what() << endl;
+        }
+        catch(...)
+        {
+            cerr << "unknown exception." << endl;
+        }
+    }
+    catch(exception& e)
+    {
+        cerr << "exception:" << e.what() << endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << endl;
+    }
+
+    return 0;
+}
+```
+异步方式
+```cpp
+#include <iostream>
+#include "servant/Communicator.h"
+#include "Hello.h"
+
+using namespace std;
+using namespace TestApp;
+using namespace tars;
+
+class HelloCallBack : public HelloPrxCallback
+{
+public:
+    HelloCallBack(){}
+
+    virtual ~HelloCallBack(){}
+
+    virtual void callback_testHello(tars::Int32 ret,  const std::string& sRsp)
+    {
+        cout<<"callback_testHello ret:"<< ret << "|sRsp:" << sRsp <<endl; 
+    }
+
+    virtual void callback_testHello_exception(tars::Int32 ret)
+    {
+        cout<<"callback_testHello_exception ret:"<< ret <<endl;
+    }
+};
+
+int main(int argc,char ** argv)
+{
+    Communicator comm;
+
+    try
+    {
+        HelloPrx prx;
+        comm.stringToProxy("TestApp.HelloServer.HelloObj@tcp -h 10.120.129.226 -p 20001" , prx);
+
+        try
+        {
+            string sReq("hello world");
+            HelloPrxCallbackPtr cb = new HelloCallBack();
+            prx->async_testHello(cb, sReq);
+            cout<<" sReq:"<<sReq<<endl;
+        }
+        catch(exception &ex)
+        {
+            cerr<<"ex:"<<ex.what() <<endl;
+        }
+        catch(...)
+        {
+            cerr<<"unknown exception."<<endl;
+        }
+    }
+    catch(exception& e)
+    {
+        cerr<<"exception:"<<e.what() <<endl;
+    }
+    catch (...)
+    {
+        cerr<<"unknown exception."<<endl;
+    }
+
+    getchar();
+
+    return 0;
+}
+```
+编写makefile,里面包含刚才通过make release生成的/home/tarsproto/APP/Server目录下的mk文件,如下:
+
+```makefile
+#-----------------------------------------------------------------------
+APP         :=TestApp
+TARGET      :=TestHelloClient
+CONFIG      :=
+STRIP_FLAG  := N
+
+INCLUDE     += 
+LIB         +=
+#-----------------------------------------------------------------------
+include /home/tarsproto/TestApp/HelloServer/HelloServer.mk
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------
+```
+make出目标文件,上传到能访问服务器的环境中进行运行测试即可
+
+# 6. 服务发布  <a id="main-chapter-6"></a>
+在管理系统的菜单树下,找到你部署的服务,点击进入服务页面。 
+
+选择“发布管理”,选中要发布的节点,点击“发布选中节点”,点击“上传发布包”,选择已经编译好的发布包,如下图:
+
+![tars](images/tars_cpp_quickstart_upload.png)
+
+ 上传好发布包后,点击“选择发布版本”下拉框就会出现你上传的服务程序,选择最上面的一个(最新上传的)。如下图:
+
+ ![tars](images/tars_cpp_quickstart_patch.png)
+
+ 点击“发布”,服务开始发布,发布成功后,出现下面的界面,如下图:
+
+ ![tars](images/tars_cpp_quickstart_patchresult.png)
+ 
+若失败的话,可能是命名问题,上传问题,以及其他环境问题。

+ 74 - 0
docs/tars_cpp_server_thread.md

@@ -0,0 +1,74 @@
+# 目录
+> * 概述
+> * Tars C++框架服务线程组成
+> * 分析运行中线程任务
+> * 改变线程数目的方法
+
+# 1. 概述
+
+Tars C++框架服务是单进程多线程RPC系统。本文讲述一个标准的Tars C++框架服务启动的线程数目,以及各线程的职责。
+
+# 2. Tars C++框架服务线程组成
+
+启动者 |线程功能|线程数目
+------|--------|-----
+SERVER |服务主线程,负责服务端初始化|1
+SERVER|服务端网络线程,负责服务端网络收发数据包(数目可配置)|可配置
+SERVER|管理端口业务逻辑线程,负责接受和处理用户自定义命令、服务关闭命令等|1
+SERVER|时间辅助线程,负责定期计算时间,减少系统对gettimeofday的调用|1
+SERVER|滚动日志线程,负责本地的文件创建和日志写入|1
+SERVER|本地日志线程,负责本地、染色日志的文件创建和日志写入(有打印按天日志或者相关初始化,线程才会创建)|1
+SERVER|远程日志线程,负责同步本地、染色日志到远程(有打印按天日志或者相关初始化,线程才会创建)|1
+SERVER|业务逻辑处理线程,负责处理用户业务逻辑,完成服务的主要功能。(默认各个ServantObj有自己对应的业务逻辑处理线程,也可以共用)|可配置
+通信器|客户端网络线程,负责管理对外服务链接、监听读写事件、网络读写|可配置
+通信器|统计属性上报线程,负责收集统计和属性信息,定时同步到stat和property|1
+通信器|异步回调线程,负责执行异步回调函数,客户端每个网络线程有自己的异步线程|可配置
+
+# 3. 分析运行中线程任务
+
+我们观察一个运行中的TAF框架服务,看下每个线程的特征,并对各个线程功能做下区分。
+
+实验场景:
+
+> * 服务端配置1个ServantObj,其配置5个业务逻辑线程。
+
+> * 服务端配置1个网络线程
+
+> * 客户端配置2个网络线程
+
+> * 异步回调线程设置为2个。
+
+按照上节所述的线程启动策略,这种场景下这个服务应该有:
+
+7(固定数)+ 1(服务端网络线程数目) + 5(业务处理线程数目)+ 2(客户端网络线程数目) + 2(异步回调线程数目)* 2(客户端网络线程数目) = 19个线程。
+
+
+
+# 4. 改变线程数目的方法
+
+上面看到了一个标准的Tars C++服务是如何组成的,凡是表明线程数目为1的部分是框架内部实现的,用户不能改变数目。
+
+能改变的就是服务端网络线程、业务逻辑处理线程、客户端网络线程、异步回调处理线程。
+
+## 4.1. 改变业务处理线程数目的方法
+
+改变业务逻辑处理线程数据,可以在Tars管理平台配置Servant对象时,在“线程数”输入自己想要的线程,那么框架将会为本Servant启动相应的线程数。
+
+
+注意:
+
+如果服务拥有两个Servant对象,分别属于不同的线程组,计算线程数目时,我们只需将不同Servant对象的线程数简单相加即可。
+
+可如果设置了线程组,那么计算方法就有所不同了。
+
+比如:
+
+ServantA            属于线程组HandleGroupA,启动线程数为10
+
+ServantB和ServantC  属于线程组HandleGroupBC,启动线程数为10
+
+那么总的业务线程数应该是:10 + 10
+
+## 4.2. 改变服务端网络线程、客户端网络线程、异步回调处理线程的方法
+
+如果要改变服务端网络线程、客户端网络线程、异步回调线程数目,可以在模版上修改,或者增加对应的服务私有模版。

+ 1341 - 0
docs/tars_cpp_user_guide.md

@@ -0,0 +1,1341 @@
+# 目录
+> * C++服务端
+> * C++客户端
+> * 异步嵌套
+> * 染色
+> * tars协议数据包大小
+> * tars定义的返回码
+> * 业务配置
+> * 日志
+> * 服务管理
+> * 统计上报
+> * 异常上报
+> * 属性统计
+
+# 框架使用指南
+
+# 1. C++服务端
+
+下面通过一个完整的例子介绍如何使用TARS来实现自己的服务。
+
+以下代码示例描述了客户端发送hello world字符串到服务端,服务端返回hello word字符串的例子。
+
+## 1.1. 定义接口
+
+编写tars文件如下,Hello.tars:
+```
+
+module TestApp
+{
+
+interface Hello
+{
+    int test();
+    int testHello(string sReq, out string sRsp);
+};
+
+}; 
+
+```
+## 1.2. 编译接口文件
+
+采用tars2cpp工具自动生成c++文件:/usr/local/tars/cpp/tools/tars2cpp hello.tars会生成hello.h文件,该文件被客户端和服务端包含;
+
+## 1.3. 接口实现
+
+服务端代码实现tars文件中的接口:
+
+HelloImp.h
+
+```
+#ifndef _HelloImp_H_
+#define _HelloImp_H_
+
+#include "servant/Application.h"
+#include "Hello.h"
+
+/**
+ * HelloImp继承hello.h中定义的Hello对象
+ *
+ */
+class HelloImp : public TestApp::Hello
+{
+public:
+    /**
+     *
+     */
+    virtual ~HelloImp() {}
+
+    /**
+     * 初始化,Hello的虚拟函数,HelloImp初始化时调用
+     */
+    virtual void initialize();
+
+    /**
+     * 析构,Hello的虚拟函数,服务析构HelloImp退出时调用
+     */
+    virtual void destroy();
+
+    /**
+     * 实现tars文件中定义的test接口
+     */
+    virtual int test(tars::TarsCurrentPtr current) { return 0;};
+
+    /**
+     * 实现tars文件中定义的test接口
+     */
+    virtual int testHello(const std::string &sReq, std::string &sRsp, tars::TarsCurrentPtr current);
+
+};
+/////////////////////////////////////////////////////
+#endif
+
+```
+HelloImp.cpp
+```
+#include "HelloImp.h"
+#include "servant/Application.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////
+void HelloImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+
+//////////////////////////////////////////////////////
+void HelloImp::destroy()
+{
+    //destroy servant here:
+    //...
+}
+
+int HelloImp::testHello(const std::string &sReq, std::string &sRsp, tars::TarsCurrentPtr current)
+{
+    TLOGDEBUG("HelloImp::testHellosReq:"<<sReq<<endl);
+    sRsp = sReq;
+    return 0;
+}
+```
+
+服务的框架代码
+
+HelloServer.h如下:
+```
+#ifndef _HelloServer_H_
+#define _HelloServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+
+using namespace tars;
+
+/**
+ * HelloServer继承框架的Application类
+ **/
+class HelloServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~HelloServer() {};
+
+    /**
+     * 服务的初始化接口
+     **/
+    virtual void initialize();
+
+    /**
+     * 服务退出时的清理接口
+     **/
+    virtual void destroyApp();
+};
+
+extern HelloServer g_app;
+
+////////////////////////////////////////////
+#endif
+
+```
+HelloServer.cpp如下:
+```
+#include "HelloServer.h"
+#include "HelloImp.h"
+
+using namespace std;
+
+HelloServer g_app;
+
+/////////////////////////////////////////////////////////////////
+void
+HelloServer::initialize()
+{
+    //initialize application here:
+
+    //添加Servant接口实现类HelloImp与路由Obj绑定关系
+    addServant<HelloImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".HelloObj");
+}
+/////////////////////////////////////////////////////////////////
+void
+HelloServer::destroyApp()
+{
+    //destroy application here:
+    //...
+}
+/////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+////////////////////////////////////////////////////////////////
+```
+
+说明:
+> * 对象HelloImp对服务的每个线程都有一个具体的实例,并且该HelloImp接口处理过程中,如果只是对HelloImp的成员变量来操作则是线程安全的,如果HelloImp接口中需要访问全局的对象,则需要加锁;
+> * ServerConfig::Application+“.”+ ServerConfig::ServerName + ".HelloObj"表示服务的Hello对象的名称,后续客户端通过这个名称来访问服务;
+> * 所有函数最有一个参数都是TarsCurrentPtr,通过该结构体可以获取请求包的所有原始内容;
+> * HelloServer是自己实现的服务类,继承于服务框架的tars::Application类;
+
+## 1.4. ServerConfig
+
+服务框架中有全局的结构ServerConfig,它记录了服务的基本信息。
+
+ServerConfig的成员变量都是静态的,在服务框架初始化时会自动从服务配置文件中初始化这些参数。
+
+ServerConfig的定义如下:
+```
+struct ServerConfig
+{
+    static std::string Application;         //应用名称
+    static std::string ServerName;          //服务名称,一个服务名称含一个或多个服务标识
+    static std::string BasePath;            //应用程序路径,用于保存远程系统配置的本地目录
+    static std::string DataPath;            //应用程序数据路径用于保存普通数据文件
+    static std::string LocalIp;             //本机IP
+    static std::string LogPath;             //log路径
+    static int         LogSize;             //log大小(字节)
+    static int         LogNum;              //log个数()
+    static std::string LogLevel;            //log日志级别
+    static std::string Local;               //本地套接字
+    static std::string Node;                //本机node地址
+    static std::string Log;                 //日志中心地址
+    static std::string Config;              //配置中心地址
+    static std::string Notify;              //信息通知中心
+    static std::string ConfigFile;          //框架配置文件路径
+    static int         ReportFlow;          //是否服务端上报所有接口stat流量 0不上报 1上报(用于非tars协议服务流量统计)
+    static int         IsCheckSet;          //是否对按照set规则调用进行合法性检查 0,不检查,1检查
+    static bool        OpenCoroutine;	    //是否启用协程处理方式
+    static size_t      CoroutineMemSize;    //协程占用内存空间的最大大小
+    static uint32_t    CoroutineStackSize;  //每个协程的栈大小(默认128k)
+};
+
+```
+参数说明:
+> * Application:应用名称,如果配置文件没有配置,默认为UNKNOWN;
+> * ServerName:服务名称,默认为可执行文件名名称;
+> * BasePath:基本路径,通常表示可执行文件的路径,默认为”./” ;
+> * DataPath:数据文件路径,通常表示存在服务自己的数据,比如mmap文件之类,默认为”./”;
+> * LocalIp:本地ip,默认是本机非127.0.0.1的第一块网卡IP;
+> * LogPath:日志文件路径,日志的写法请参考后续;
+> * LogSize:滚动日志文件的大小;
+> * LogNum:滚动日志文件的个数;
+> * LogLevel:滚动log日志级别;
+> * Local:服务可以有管理端口,可以通过管理端口发送命令给服务,该参数表示绑定的管理端口的地址,例如tcp -h 127.0.0.1 -p 8899,如果没有设置则没有管理端口;
+> * Node:本地NODE地址,如果设置,则定时给NODE发送心跳,否则不发送心跳,通常只有发布到框架上面的服务才有该参数;
+> * Log:日志中心地址,例如:tars.tarslog.LogObj@tcp –h .. –p …,如果没有配置,则不记录远程日志;
+> * Config:配置中心地址,例如:tars.tarsconfig.ConfigObj@tcp –h … -p …,如果没有配置,则addConfig函数无效,无法从远程配置中心拉取配置;
+> * Notify:信息上报中心地址,例如:tars.tarsnotify.NotifyObj@tcp –h … -p …,如果没有配置,则上报的信息直接丢弃;
+> * ConfigFile:框架配置文件路径
+> * IsCheckSet:是否对按照set规则调用进行合法性检查 0,不检查,1检查
+> * OpenCoroutine:是否启用协程处理方式,默认为0,不启用
+> * CoroutineMemSize:协程占用内存空间的最大大小
+> * CoroutineStackSize:每个协程的栈大小(默认128k)
+
+服务的配置文件格式如下:
+```
+<tars>
+  <application>
+    <server>
+       #本地node的ip:port
+       node=tars.tarsnode.ServerObj@tcp -h 10.120.129.226 -p 19386 -t 60000
+       #应用名称
+       app=TestApp
+       #服务名称
+       server=HelloServer
+       #本机ip
+       localip=10.120.129.226
+       #管理端口
+       local=tcp -h 127.0.0.1 -p 20001 -t 3000
+       #服务可执行文件,配置文件等
+       basepath=/usr/local/app/tars/tarsnode/data/TestApp.HelloServer/bin/
+       #服务数据目录
+       datapath=/usr/local/app/tars/tarsnode/data/TestApp.HelloServer/data/
+       #日志路径
+       logpath=/usr/local/app/tars/app_log/
+       #滚动日志大小
+       logsize=10M
+       #配置中心的地址
+       config=tars.tarsconfig.ConfigObj
+       #通知上报的地址[可选]
+       notify=tars.tarsnotify.NotifyObj
+       #远程日志的地址[可选]
+       log=tars.tarslog.LogObj
+       #服务停止的超时时间
+       deactivating-timeout=2000
+       #日志等级
+       logLevel=DEBUG
+    </server>
+  </application>
+</tars>
+```
+
+## 1.5. Adapter
+
+Adapter对应代码中的TC_EpollServer::BindAdapter,表示了绑定端口。
+
+服务新增一个绑定端口,则新建立一个BindAdapter,并设置相关的参数和处理对象则可以非常方便的完成对这个端口上的处理,通常用这个功能来完成在其他协议的支撑。
+
+对于TARS服务而言,在服务配置文件中增加adapter项,即可以完成TARS增加一个Servant处理对象。
+
+Adapter配置如下:
+```
+<tars>
+  <application>
+    <server>
+       #配置绑定端口
+       <TestApp.HelloServer.HelloObjAdapter>
+            #允许的IP地址
+            allow
+            #监听IP地址
+            endpoint=tcp -h 10.120.129.226 -p 20001 -t 60000
+            #处理组
+            handlegroup=TestApp.HelloServer.HelloObjAdapter
+            #最大连接数
+            maxconns=200000
+            #协议
+            protocol=tars
+            #队列大小
+            queuecap=10000
+            #队列超时时间毫秒
+            queuetimeout=60000
+            #处理对象
+            servant=TestApp.HelloServer.HelloObj
+            #当前线程个数
+            threads=5
+       </TestApp.HelloServer.HelloObjAdapter>
+    </server>
+  </application>
+</tars>
+```
+关注servant项,在HelloServer::initialize()中,完成配置和代码中对象的对应,如下:
+```
+void HelloServer::initialize ()
+{
+    //增加对象
+    addServant<HelloImp>(ServerConfig::Application+“.”+ ServerConfig::ServerName + ".HelloObj");
+}
+```
+
+## 1.6. 服务启动
+
+服务启动命令如下:
+```
+HelloServer --config=config.conf
+```
+注意:config.conf为配置文件,服务端的配置文件和客户端的配置文件必须合并到这一个文件中。
+
+就服务而言,可以单独运行,不需要发布到TARS系统框架上。
+
+完整的如下:
+```
+<tars>
+  <application>
+    enableset=n
+    setdivision=NULL
+    <server>
+       #本地node的ip:port
+       node=tars.tarsnode.ServerObj@tcp -h 10.120.129.226 -p 19386 -t 60000
+       #应用名称
+       app=TestApp
+       #服务名称
+       server=HelloServer
+       #本机ip
+       localip=10.120.129.226
+       #管理端口
+       local=tcp -h 127.0.0.1 -p 20001 -t 3000
+       #服务可执行文件,配置文件等
+       basepath=/usr/local/app/tars/tarsnode/data/TestApp.HelloServer/bin/
+       #服务数据目录
+       datapath=/usr/local/app/tars/tarsnode/data/TestApp.HelloServer/data/
+       #日志路径
+       logpath=/usr/local/app/tars/app_log/
+       #滚动日志大小
+       logsize=10M
+       #配置中心的地址
+       config=tars.tarsconfig.ConfigObj
+       #通知上报的地址[可选]
+       notify=tars.tarsnotify.NotifyObj
+       #远程日志的地址[可选]
+       log=tars.tarslog.LogObj
+       #服务停止的超时时间
+       deactivating-timeout=2000
+       #日志等级
+       logLevel=DEBUG
+        #配置绑定端口
+       <TestApp.HelloServer.HelloObjAdapter>
+            #允许的IP地址
+            allow
+            #监听IP地址
+            endpoint=tcp -h 10.120.129.226 -p 20001 -t 60000
+            #处理组
+            handlegroup=TestApp.HelloServer.HelloObjAdapter
+            #最大连接数
+            maxconns=200000
+            #协议
+            protocol=tars
+            #队列大小
+            queuecap=10000
+            #队列超时时间毫秒
+            queuetimeout=60000
+            #处理对象
+            servant=TestApp.HelloServer.HelloObj
+            #当前线程个数
+            threads=5
+       </TestApp.HelloServer.HelloObjAdapter>
+    </server>
+    <client>
+       #主控的地址
+       locator=tars.tarsregistry.QueryObj@tcp -h 10.120.129.226 -p 17890
+       #同步超时时间
+       sync-invoke-timeout=3000
+       #异步超时时间
+       async-invoke-timeout=5000
+       #刷新ip列表的时间间隔
+       refresh-endpoint-interval=60000
+       #上报数据的时间间隔
+       report-interval=60000
+       #采样率
+       sample-rate=100000
+       #最大采样数
+       max-sample-count=50
+       #异步线程数
+       asyncthread=3
+       #模版名称
+       modulename=TestApp.HelloServer
+    </client>
+  </application>
+</tars>
+```
+
+# 2. C++客户端
+
+客户端可以不用写任何协议通信代码即可完成远程调用。客户端代码同样需要包含hello.h文件。
+## 2.1. 通信器
+
+完成服务端以后,客户端需要对服务端完成收发包的工作。客户端对服务端完成收发包的操作是通过通信器(communicator)来实现的。
+
+** 注意:一个Tars服务只能使用一个Communicator,用Application::getCommunicator()获取即可(若不是Tars服务,要使用通讯器,则自己创建,也只能一个)。
+
+通信器是客户端的资源载体,包含了一组资源,用于收发包、状态统计等功能。
+
+通信器的初始化如下:
+```cpp
+TC_Config conf("config.conf");
+CommunicatorPtr c = new Communicator();
+//用配置文件初始化通信器
+c-> setProperty(conf);
+//直接用属性初始化
+c->setProperty("property", "tars.tarsproperty.PropertyObj");
+c->setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h ... -p ...");
+```
+说明:
+> * 通信器的配置文件格式后续会介绍;
+> * 通信器缺省不采用配置文件也可以使用,所有参数都有默认值;
+> * 通信器也可以直接通过属性来完成初始化;
+> * 如果需要通过名字来获取客户端调用代理,则必须设置locator参数;
+
+通信器属性说明:
+> * locator: registry服务的地址,必须是有ip port的,如果不需要registry来定位服务,则不需要配置;
+> * sync-invoke-timeout:调用最大超时时间(同步),毫秒,没有配置缺省为3000
+> * async-invoke-timeout:调用最大超时时间(异步),毫秒,没有配置缺省为5000
+> * refresh-endpoint-interval:定时去registry刷新配置的时间间隔,毫秒,没有配置缺省为1分钟
+> * stat:模块间调用服务的地址,如果没有配置,则上报的数据直接丢弃;
+> * property:属性上报地址,如果没有配置,则上报的数据直接丢弃;
+> * report-interval:上报给stat/property的时间间隔,默认为60000毫秒;
+> * asyncthread:异步调用时,回调线程的个数,默认为1;
+> * modulename:模块名称,默认为可执行程序名称;
+
+通信器配置文件格式如下:
+```
+<tars>
+  <application>
+    #proxy需要的配置
+    <client>
+        #地址
+        locator                     = tars.tarsregistry.QueryObj@tcp -h 127.0.0.1 -p 17890
+        #同步最大超时时间(毫秒)
+        sync-invoke-timeout         = 3000
+        #异步最大超时时间(毫秒)
+        async-invoke-timeout        = 5000
+        #刷新端口时间间隔(毫秒)
+        refresh-endpoint-interval   = 60000
+        #模块间调用
+        stat                        = tars.tarsstat.StatObj
+        #属性上报地址
+        property                    = tars.tarsproperty.PropertyObj
+        #report time interval
+        report-interval             = 60000
+        #网络异步回调线程个数
+        asyncthread                 = 3
+        #模块名称
+        modulename                  = Test.HelloServer
+    </client>
+  </application>
+</tars>
+```
+使用说明:
+> * 当使用Tars框架做服务端使用时,通信器不要自己创建,直接采用服务框架中的通信器就可以了,例如:Application::getCommunicator()->stringToProxy(...),对于纯客户端情形,则要用户自己定义个通信器并生成代理(proxy);
+> * getCommunicator()是框架Application类的静态函数,随时可以获取;
+> * 对于通信器创建出来的代理,也不需要每次需要的时候都stringToProxy,初始化时建立好,后面直接使用就可以了;
+> * 代理的创建和使用,请参见下面几节;
+> * 对同一个Obj名称,多次调用stringToProxy返回的Proxy其实是一个,多线程调用是安全的,且不会影响性能;
+> * 可以通过Application::getCommunicator()->getEndpoint(”obj”)获取bj对应ip列表。另外一种获取方式为直接从通信器生成的proxy获取如Application::getCommunicator()->stringToProxy(…) ->getEndpoint()
+
+## 2.2. 超时控制
+
+超时控制是对客户端proxy(代理)而言。上节中通信器的配置文件中有记录:
+```cpp
+#同步最大超时时间(毫秒)
+sync-invoke-timeout          = 3000
+#异步最大超时时间(毫秒)
+async-invoke-timeout         = 5000
+```
+上面的超时时间对通信器生成的所有proxy都有效。
+
+如果需要单独设置超时时间,设置如下:
+
+针对proxy设置超时时间:
+```cpp
+ProxyPrx  pproxy;
+//设置该代理的同步的调用超时时间 单位毫秒
+pproxy->tars_timeout(3000);
+//设置该代理的异步的调用超时时间 单位毫秒
+pproxy->tars_async_timeout(4000);
+```
+
+针对接口设置超时时间:
+```cpp
+//设置该代理的本次接口调用的超时时间.单位是毫秒,设置单次有效
+pproxy->tars_set_timeout(2000)->a(); 
+```
+
+## 2.3. 调用
+
+本节会详细阐述tars的远程调用的方式。
+
+首先简述tars客户端的寻址方式,其次会介绍客户端的调用方式,包括但不限于单向调用、同步调用、异步调用、hash调用等。
+
+### 2.3.1. 寻址方式简介
+
+Tars服务的寻址方式通常可以分为如下两种方式,即服务名在主控注册和不在主控注册,主控是指专用于注册服务节点信息的名字服务(路由服务)。
+名字服务中的服务名添加则是通过操作管理平台实现的。
+
+对于没有在主控注册的服务,可以归为直接寻址方式,即在服务的obj后面指定要访问的ip地址。客户端在调用的时候需要指定HelloObj对象的具体地址:
+
+即:Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985
+
+Test.HelloServer.HelloObj:对象名称
+
+tcp:tcp协议
+
+-h:指定主机地址,这里是127.0.0.1 
+
+-p:端口地址,这里是9985
+
+如果HelloServer在两台服务器上运行,则HelloPrx初始化方式如下:
+```cpp
+HelloPrx pPrx = c->stringToProxy<HelloPrx>("Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985:tcp -h 192.168.1.1 -p 9983");
+```
+即,HelloObj的地址设置为两台服务器的地址。此时请求会分发到两台服务器上(分发方式可以指定,这里不做介绍),如果一台服务器down,则自动将请求分到另外一台,并定时重试开始down的那一台服务器。
+
+对于在主控中注册的服务,服务的寻址方式是基于服务名进行的,客户端在请求服务端的时候则不需要指定HelloServer的具体地址,但是需要在生成通信器或初始化通信器的时候指定registry(主控中心)的地址。
+
+这里指定registry的地址通过设置通信器的参数实现,如下:
+```
+CommunicatorPtr c = new Communicator();
+c->setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h .. -p ..")
+```
+由于依赖registry的地址,因此registry必须也能够容错,这里registry的容错方式与上面中一样,指定两个registry的地址即可。
+
+### 2.3.2. 单向调用
+
+所谓单项调用,表示客户端只管发送数据,而不接收服务端的响应,也不管服务端是否接收到请求。
+```cpp
+TC_Config conf("config.conf");
+CommunicatorPtr c = new Communicator();
+//用配置文件初始化通信器
+c-> setProperty(conf);
+//生成客户端代理
+HelloPrx pPrx = c->stringToProxy<HelloPrx>("Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985");
+//发起远程调用
+string s = "hello word";
+string r;
+pPrx->async_testHello(NULL, s);
+```
+### 2.3.3. 同步调用
+
+请看如下调用示例:
+```cpp
+TC_Config conf("config.conf");
+CommunicatorPtr c = new Communicator();
+//用配置文件初始化通信器
+c-> setProperty(conf);
+//生成客户端代理
+HelloPrx pPrx = c->stringToProxy<HelloPrx>("Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985");
+//发起远程同步调用
+string s = "hello word";
+string r;
+int ret = pPrx->testHello(s, r);
+assert(ret == 0);
+assert(s == r);
+```
+上述例子中表示:客户端向HelloServer的HelloObj对象发起远程同步调用。
+
+### 2.3.4. 异步调用
+
+定义异步回调对象:
+```cpp
+struct HelloCallback : public HelloPrxCallback
+{
+//回调函数
+virtual void callback_testHello(int ret, const string &r)
+{
+    assert(r == "hello word");
+}
+
+virtual void callback_testHello_exception(tars::Int32 ret)
+{
+    assert(ret == 0);
+    cout << "callback exception:" << ret << endl;
+}
+};
+
+TC_Config conf("config.conf");
+CommunicatorPtr c = new Communicator();
+//用配置文件初始化通信器
+c-> setProperty(conf);
+//生成客户端代理
+HelloPrx pPrx = c->stringToProxy<HelloPrx>("Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985");
+//定义远程回调对象
+HelloPrxCallbackPtr cb = new HelloCallback;
+
+//发起远程调用
+string s = "hello word";
+string r;
+pPrx->async_testHello(cb, s);
+```
+注意:
+> * 当接收到服务端返回时,HelloPrxCallback的callback_testHello会被响应。
+> * 如果调用返回异常或超时,则callback_testHello_exception会被调用,ret的值定义如下:
+
+
+```cpp
+//定义TARS服务给出的返回码
+const int TARSSERVERSUCCESS       = 0;       //服务器端处理成功
+const int TARSSERVERDECODEERR     = -1;      //服务器端解码异常
+const int TARSSERVERENCODEERR     = -2;      //服务器端编码异常
+const int TARSSERVERNOFUNCERR     = -3;      //服务器端没有该函数
+const int TARSSERVERNOSERVANTERR  = -4;      //服务器端没有该Servant对象
+const int TARSSERVERRESETGRID     = -5;      //服务器端灰度状态不一致
+const int TARSSERVERQUEUETIMEOUT  = -6;      //服务器队列超过限制
+const int TARSASYNCCALLTIMEOUT    = -7;      //异步调用超时
+const int TARSINVOKETIMEOUT       = -7;      //调用超时
+const int TARSPROXYCONNECTERR     = -8;      //proxy链接异常
+const int TARSSERVEROVERLOAD      = -9;      //服务器端超负载,超过队列长度
+const int TARSADAPTERNULL         = -10;     //客户端选路为空,服务不存在或者所有服务down掉了
+const int TARSINVOKEBYINVALIDESET = -11;     //客户端按set规则调用非法
+const int TARSCLIENTDECODEERR     = -12;     //客户端解码异常
+const int TARSSERVERUNKNOWNERR    = -99;     //服务器端位置异常
+```
+
+### 2.3.5. 指定set方式调用
+
+目前框架已经支持业务按set方式进行部署,按set部署之后,各个业务之间的调用对开业务发来说是透明的。但是由于有些业务有特殊需求,需要在按set部署之后,客户端可以指定set名称来调用服务端,因此框架则按set部署的基础上增加了客户端可以指定set名称去调用业务服务的功能。
+
+详细使用规则如下,
+
+假设业务服务端HelloServer部署在两个set上,分别为Test.s.1和Test.n.1。那么客户端指定set方式调用如下:
+```cpp
+TC_Config conf("config.conf");
+CommunicatorPtr c = new Communicator();
+//用配置文件初始化通信器
+c-> setProperty(conf);
+//生成客户端代理
+HelloPrx pPrx_Tests1 = c->stringToProxy<HelloPrx>("Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985","Test.s.1");
+
+HelloPrx pPrx_Testn1 = c->stringToProxy<HelloPrx>("Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 9985","Test.n.1");
+
+//发起远程调用
+string s = "hello word";
+string r;
+
+int ret = pPrx_Tests1->testHello(s, r);
+
+int ret = pPrx_Testn1->testHello(s, r);
+```
+注意:
+> * 指定set调用的优先级高于客户端和服务端自身启用set的优先级,例如,客户端和服务端都启用了Test.s.1,如果客户端创建服务端代理实例时指定了Test.n.1,那么实际请求就会发送到Test.n.1的节点上(前提是这个set有部署服务端)。
+> * 创建的代理实例也是只需调用一次
+
+### 2.3.6. Hash调用
+
+由于服务可以部署多台,请求也是随机分发到服务上,但是在某些场合下,希望某些请求总是在某一台服务器上,对于这种情况Tars提供了简单的方式实现:
+
+假如有一个根据QQ号查询资料的请求,如下:
+```cpp
+QQInfo qi = pPrx->query(uin);
+```
+通常情况下,同一个uin调用,每次请求落在的服务器地址都不一定,但是采用如下调用:
+```cpp
+QQInfo qi = pPrx->tars_hash(uin)->query(uin);
+```
+则可以保证,每次uin的请求都在某一台服务器。
+
+注意:
+> * 这种方式并不严格,如果后台某台服务器down,则这些请求会迁移到其他服务器,当它正常后,会迁移回来。
+> * Hash参数必须是int,对于string来说,Tars基础库(util目录下)也提供了方法:tars::hash<string>()("abc"),具体请参见util/tc_hash_fun.h
+
+# 3. 异步嵌套
+
+异步嵌套代表如下情况:
+
+> * A 异步调用B,B接收到请求后再异步调用C,等C返回后,B再将结果返回A。
+
+通常情况下面,B接收到请求后,在接口处理完毕以后就需要返回应答给A,因此如果B在接口中又发起异步请求到C,则无法实现。
+
+因此需要采用下面方法实现跨服务的异步调用,具体可以参考cpp/examples/QuickStartDemo/ProxyServer示例。
+
+还是采用hello world的例子,client发起请求给Proxy,Proxy接收到请求后,异步发起testHello给HelloServer,请求返回后,Proxy再将HelloServer返回的结果给client。
+
+这个处理过程中,关键的逻辑在ProxyServer。以下代码是B中的逻辑处理:
+```cpp
+//ProxyServer中的异步回调对象
+class HelloCallback : public HelloPrxCallback
+{
+
+public:
+    HelloCallback(TarsCurrentPtr &current)
+    : _current(current)
+    {}
+
+    virtual void callback_testHello(tars::Int32 ret,  const std::string& sOut)
+    {
+        Proxy::async_response_testProxy(_current, ret, sOut);
+    }
+    virtual void callback_testHello_exception(tars::Int32 ret)
+    { 
+        TLOGERROR("HelloCallback callback_testHello_exception ret:" << ret << endl); 
+
+        Proxy::async_response_testProxy(_current, ret, "");
+    }
+
+    TarsCurrentPtr _current;
+};
+
+//定义ProxyServer中接口
+tars::Int32 ProxyImp::testProxy(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current)
+{
+    try
+    {
+        current->setResponse(false);
+
+        TestApp::HelloPrxCallbackPtr cb = new HelloCallback(current);
+
+        _prx->tars_set_timeout(3000)->async_testHello(cb,sIn);
+    }
+    catch(std::exception &ex)
+    {
+        current->setResponse(true);
+
+        TLOGERROR("ProxyImp::testProxy ex:" << ex.what() << endl);
+    }
+
+    return 0;
+}
+```
+说明:
+> * 回调对象HelloCallback保存了上下文current;
+> * 回调对象收到HelloServer返回的请求以后,通过Proxy::async_response_testProxy再将请求返回client;
+> * 在ProxyServer的接口testProxy实现中,需要设置不自动回复current->setResponse(false);
+> * 这里testProxy的返回值,返回参数其实都没有意义了,无论返回什么都可以;
+> * 如果回调对象中需要其他参数,可以再构造的时候传进去;
+> * 回调对象必须是new出来放在智能指针中,例如:HelloPrxCallbackPtr cb = new HelloCallback(current); 它的生命周期,业务不用管理,框架层会自动管理;
+
+# 4. 染色
+
+## 4.1. 功能概述
+
+染色功能的主要作用是可以在某服务某接口中对特定用户号码的消息进行染色,方便地实时察看该用户引起后续所有相关调用消息流的日志。
+
+染色日志打开后,要看染色日志需要到tarslog所在的服务器上查看,具体的路径请参考:
+
+滚动日志,即程序中调用LOG宏所写的日志全部向tarslog打印一份,日志文件为:tars_dyeing.dyeing_roll_yyyymmdd.log,每天一个文件,比如:
+
+/usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/tars_dyeing.dyeing_roll_20161227.log
+
+按天日志,即程序中调用DLOG、FDLOG以及FFDLOG所写的日志全部向tarslog打印一份,日志文件为:tars_dyeing.dyeing_day_yyyymmdd.log,每天一个文件,比如:
+
+/usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/tars_dyeing.dyeing_day_20161227.log
+
+## 4.2.	规则说明
+
+染色日志有主动打开和被动打开两种方法。
+
+所谓主动打开指的是,在请求的客户端打开框架中的染色日志开关。
+
+具体使用步骤如下:
+> * 在客户端程序适当的地方埋下锚点,该锚点用来根据某条件来决定是否打开染色日志开关--tars.TarsDyeingSwitch。染色作用范围从打开日志开始,到该开关析构为止。
+> * 调用开关的enableDyeing方法即为打开染色日志。后续对应该请求所有日志(包括本服务,以及后面调用的所有服务的日志额外打印一份到tarslog。
+> * 被调服务根据请求标志位打开染色开关,该被调服务打印日志到tarslog。如果该被调服务还要调用其他服务,则自动将该标志位传递给下个服务。该请求完毕后,自动关闭染色日志。
+
+所谓被动打开指的是,在请求的服务端预先设定染色条件,判断传递的key值,由服务端来打开本服务的染色日志开关。
+具体使用步骤如下:
+> * 被染色的入口接口,需在Tars接口定义的时候,对用户关键字指定为routekey
+> * 染色的方法:.通过管理命令接口,往目标服务设置需要染色的用户号码、远程对象和接口(接口参数可选)。
+> * 服务收到匹配的请求(匹配用户号码、远程对象和接口)后,对请求包进行染色处理。
+> * 对已经染色的请求,相关的系统日志及按天日志,除了正常的打印外,会额外再集中打印一份到本地及远程的染色日志目录,目录位置在tars日志根目录的/tars_dyeing目录下。
+> * 服务处理过程如果继续调用其他tars服务,请求将通过状态字段继续传递染色信息,被调服务收到请求后也会以以上的方式打印染色日志,并将染色状态继续往下传递。
+
+## 4.3. 主动打开使用实例
+主动打开的使用方法:
+```cpp
+#include <iostream>
+#include "servant/Communicator.h"
+#include "Hello.h"
+#include "servant/TarsLogger.h"
+#include "util/tc_option.h"
+#include "util/tc_file.h"
+
+#include <string>
+using namespace std;
+using namespace TestApp;
+using namespace tars;
+
+int main(int argc,char ** argv)
+{
+try
+{
+    CommunicatorPtr comm =new Communicator();
+    comm->setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h 10.120.129.226 -p 17890 -t 10000");
+    TarsRollLogger::getInstance()->setLogInfo("TestApp", "HelloServer", "./log", 100000, 10, comm, "tars.tarslog.LogObj");
+    TarsRollLogger::getInstance()->sync(false);
+    TarsTimeLogger::getInstance()->setLogInfo(comm, "tars.tarslog.LogObj", "TestApp", "HelloServer", "./log");
+    {
+            //在打开染色日志之前,打印日志,这条日志只会打印到本地日中。
+            TLOGDEBUG    (__FILE__ << "|" << __LINE__ <<"Test Before Dyeing"  <<endl);
+            DLOG        <<__FILE__ << "|" << __LINE__ <<"D/Test Before Dyeing"<<endl;
+            FDLOG("T_D")<<__FILE__ << "|" << __LINE__ <<"F/Test Before Dyeing"<<endl;
+    }
+         try
+         {
+        	{
+
+        	   //声明一个日志打开开关,调用enableDyeing打开染色日志
+        	   TarsDyeingSwitch dye;
+        	   dye.enableDyeing();
+
+        	   //在打开染色日志之后,打印日志,会在本地日志和染色日志中看到
+        	   {
+        	      TLOGDEBUG    (__FILE__ << "|" << __LINE__ <<"Test Before Dyeing before call other function"  <<endl);
+        	      DLOG        <<__FILE__ << "|" << __LINE__ <<"D/Test Before Dyeing before call other function"<<endl;
+        	      FDLOG("T_D")<<__FILE__ << "|" << __LINE__ <<"F/Test Before Dyeing before call other function"<<endl;
+        	   }
+        	   
+
+        	   string sReq("hello");
+        	   std::string sServant="TestApp.HelloServer.HelloObj";
+        	   TestApp::HelloPrx prx = comm->stringToProxy<TestApp::HelloPrx>(sServant);
+        	   tars::Int32 iRet = prx->test();
+        	   string sRsp;
+        	   prx->testHello(sReq,sRsp);
+
+			
+        	   TLOGDEBUG    (__FILE__ << "|" << __LINE__ <<"Test Before Dyeing after call other function"  <<endl);
+        	   DLOG        <<__FILE__ << "|" << __LINE__ <<"D/Test Before Dyeing after call other function"<<endl;
+        	   FDLOG("T_D")<<__FILE__ << "|" << __LINE__ <<"F/Test Before Dyeing after call other function"<<endl;
+        	}
+		
+        	{
+        	   //染色日志开关已经析构,染色功能失效,以后的日志不会打印到染色日志中
+        	   TLOGDEBUG    (__FILE__ << "|" << __LINE__ <<"~Dyeing"<<endl);
+        	   DLOG        <<__FILE__ << "|" << __LINE__ <<"D/~Dyeing"<<endl;
+        	   FDLOG("T_D")<<__FILE__ << "|" << __LINE__ <<"F/~Dyeing"<<endl;
+        	}
+        }
+        catch(exception &ex)
+        {
+             cerr << "ex:" << ex.what() << endl;
+        }
+        catch(...)
+        {
+             cerr << "unknown exception." << endl;
+        }
+    }
+    catch(exception& e)
+    {
+        cerr << "exception:" << e.what() << endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << endl;
+    }
+    sleep(10); //等待异步写日志线程同步日志数据到logserver
+    return 0;
+}
+
+
+```
+
+在 tars_dyeing.dyeing_roll_20161227.log
+```
+//这条日志是服务端使用TLOGDEBUG打印的滚动日志
+10.120.129.226|TestApp.HelloServer|2016-12-27 11:30:47|7670|DEBUG|main.cpp|37Test Before Dyeing before call other function
+//这条日志是服务端使用TLOGDEBUG打印的滚动日志
+10.120.129.226|TestApp.HelloServer|2016-12-27 11:30:47|7670|DEBUG|main.cpp|59Test Before Dyeing after call other function
+```
+在 tars_dyeing.dyeing_day_20161227.log
+```
+//使用DLOG打印的滚动日志
+10.120.129.226|TestApp.HelloServer|2016-12-27 11:30:47|main.cpp|38D/Test Before Dyeing before call other function
+10.120.129.226|TestApp.HelloServer|2016-12-27 11:30:47|main.cpp|60D/Test Before Dyeing after call other function
+//使用FLOG打印的滚动日志
+10.120.129.226|TestApp.HelloServer|2016-12-27 11:30:47|main.cpp|39F/Test Before Dyeing before call other function
+10.120.129.226|TestApp.HelloServer|2016-12-27 11:30:47|main.cpp|61F/Test Before Dyeing after call other function
+```
+## 4.4. 被动打开的使用方法:
+即将被染色的接口定义
+```
+interface HelloRouteObj
+{
+    int testHello(routekey string sInput, out string sOutput);
+};
+```
+可以通过框架命令进行染色,染色的命令格式为:
+```
+tars.setdyeing dyeingKey dyeingServant [dyeingInterface]
+```
+三个参数分别为用户号码(routekey对应的值),远程对象名称,接口名称(可选)。
+假设以上接口的远程对象为 TestApp.HelloServer.HelloObj testHello
+可以通过管理平台发布命令:tars.setdyeing 123456 TestApp.HelloServer.HelloObj testHello
+
+当有sInput为123456的请求发到该服务,出了正常的日志输出外,还将集中打印到本地系统日志:
+
+/usr/local/app/tars/app_log/tars_dyeing/dyeing_20161227.log 
+TestApp.HelloServer|2016-12-27 15:38:49|11454|DEBUG|HelloImp::testHello sReq:123456
+
+本地按条日志:
+
+/usr/local/app/tars/app_log/tars_dyeing/dyeing_20161227.log 
+TestApp.HelloServer|2016-12-27 15:38:49|11454|DEBUG|HelloImp::testHello sReq:123456
+
+远程日志将打印到tarslog所在机器:
+远程系统日志:
+/usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/tars_dyeing.dyeing_roll_20161227.log
+
+远程按天日志:
+/usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/tars_dyeing.dyeing_day_20161227.log
+
+其中,日志中首字段为染色请求处理过程的服务名称,后续其他被调服务的相关日志也打印到同一文件,通过首字段区分不同服务的日志。
+
+# 5. tars协议数据包大小
+
+目前tars协议对数据包的大小进行了限制。
+
+通信器(客户端)对发出去的包大小没有限制,对收到的回包有限制,默认是10000000字节(接近10M)。
+
+服务端对发送的包没有限制,对收到的包有大小限制,默认是100000000字节(接近100M)。
+
+## 5.1. 修改客户端接收数据包大小
+通过修改ServantProxy的tars_set_protocol来修改数据包的大小。
+```cpp
+ProxyProtocol prot;
+prot.responseFunc = ProxyProtocol::tarsResponseLen<100000000>;
+prot.requestFunc  = ProxyProtocol::tarsRequest;
+ccserverPrx ->tars_set_protocol(prot);
+```
+100000000表示限制的大小,单位是字节。
+
+ccserverPrx是全局唯一的,只要设置一次即可。
+
+为了写代码方便,建议在业务线程的initialize里面设置一次。
+
+要先调用stringToProxy然后再设置。
+```cpp
+prot.requestFunc = ProxyProtocol::tarsRequest //必须有,默认不是这个函数。
+```
+如果是tup方式调用。设置len
+```cpp
+prot.responseFunc  = ProxyProtocol:: tupResponseLen<100000000>;
+```
+## 5.2. 修改服务端接收数据包大小
+
+通过设置ServantProtocol的形式来修改数据包大小。
+```cpp
+addServantProtocol(ServerConfig::Application + "." + ServerConfig::ServerName + ".BObj",AppProtocol::parseLenLen<100000000>);
+```
+建议在server的initialize里面设置,在addServant之后设置。
+
+# 6. Tars定义的返回码
+```
+//定义TARS服务给出的返回码
+const int TARSSERVERSUCCESS       = 0;       //服务器端处理成功
+const int TARSSERVERDECODEERR     = -1;      //服务器端解码异常
+const int TARSSERVERENCODEERR     = -2;      //服务器端编码异常
+const int TARSSERVERNOFUNCERR     = -3;      //服务器端没有该函数
+const int TARSSERVERNOSERVANTERR  = -4;      //服务器端没有该Servant对象
+const int TARSSERVERRESETGRID     = -5;      //服务器端灰度状态不一致
+const int TARSSERVERQUEUETIMEOUT  = -6;      //服务器队列超过限制
+const int TARSASYNCCALLTIMEOUT    = -7;      //异步调用超时
+const int TARSINVOKETIMEOUT       = -7;      //调用超时
+const int TARSPROXYCONNECTERR     = -8;      //proxy链接异常
+const int TARSSERVEROVERLOAD      = -9;      //服务器端超负载,超过队列长度
+const int TARSADAPTERNULL         = -10;     //客户端选路为空,服务不存在或者所有服务down掉了
+const int TARSINVOKEBYINVALIDESET = -11;     //客户端按set规则调用非法
+const int TARSCLIENTDECODEERR     = -12;     //客户端解码异常
+const int TARSSERVERUNKNOWNERR    = -99;     //服务器端位置异常
+```
+
+# 7. 业务配置
+Tars服务框架提供了从tarsconfig拉取服务的配置到本地目录的功能。
+
+使用方法很简单,在Server的initialize中,调用addConfig拉取配置文件。
+
+以HelloServer为例:
+```
+HelloServer::initialize()
+{
+    //增加对象
+    addServant<HelloImp>(ServerConfig::Application+“.”+ ServerConfig::ServerName + ".HelloObj");
+
+    //拉取配置文件
+    addConfig("HelloServer.conf");
+}
+```
+说明:
+> * HelloServer.conf配置文件可以在web管理平台上配置;
+> * HelloServer.conf拉取到本地后, 可以通过ServerConfig::BasePath + “HelloServer.conf”表示配置文件的绝对路径;
+> * 配置文件的管理都在web管理平台上,同时web管理平台可以主动push配置文件到Server;
+> * 配置中心支持ip级别的配置,即一个服务部署在多台服务上,只有部分不同(与IP相关),这种情况下,配置中心可以支持配置文件的合并,同时支持在web管理平台查看和修改;
+
+注意:
+> * 对于没有发布到管理平台上的服务,需要在服务的配置文件中指定Config的地址,否则不能使用远程配置。
+
+# 8. 日志
+
+Tars服务框架提供了宏定义方式用于记录系统的滚动日志/按天日志。这几个宏都是线程安全的,可以随意使用。
+
+## 8.1. TLOGXXX说明
+
+TLOGXXX用于记录滚动日志,用于调试服务,XXX分别包括了 DEBUG/WARN/ERROR/NONE四种级别,含义如下,
+> * INFO: 信息级别,框架内部的日志都是以INFO级别打印,除非是错误
+> * DEBUG:调试级别,最低级别;
+> * WARN: 警告级别;
+> * ERROR:错误级别;
+
+使用方式:
+```cpp
+TLOGINFO("test" << endl);
+TLOGDEBUG("test" << endl);
+TLOGWARN("test" << endl);
+TLOGERROR("test" << endl);
+```
+说明:
+> * 可以在web管理设置服务LOG的当前级别;
+> * Tars框架的日志都通过info打印,设置成info后可以看见Tars的框架日志;
+> * TLOGXXX的按大小滚动,可以在服务的模板配置文件中修改滚动大小和个数,通常都不用动;
+> * TLOGXXX表示循环日志,是不会发送到远程tarslog服务的;
+> * TLOGXXX的文件名称和服务名称相关,通常是app.server.log;
+> * TLOGXXX是全局的单件,任何地方可以使用,不过如果在框架完成对LOG初始化前就使用,则直接cout出来了;
+> * 在使用的地方需要#include  "servant/TarsLogger.h"
+
+TLOGXXX是宏,它的定义如下:
+```cpp
+#define LOG             (TarsRollLogger::getInstance()->logger())
+
+#define LOGMSG(level,msg...) do{if(LOG->IsNeedLog(level)) LOG->log(level)<<msg;}while(0)
+
+#define TLOGINFO(msg...)  LOGMSG(TarsRollLogger::INFO_LOG,msg)
+#define TLOGDEBUG(msg...) LOGMSG(TarsRollLogger::DEBUG_LOG,msg)
+#define TLOGWARN(msg...)  LOGMSG(TarsRollLogger::WARN_LOG,msg)
+#define TLOGERROR(msg...) LOGMSG(TarsRollLogger::ERROR_LOG,msg)
+```
+
+TarsRollLogger::getInstance()->logger()返回的类型是TC_RollLogger*,因此可以通过它对LOG进行设置,比如:
+设置为Info级别:
+```cpp
+TarsRollLogger::getInstance()->logger()->setLogLevel(TC_RollLogger::INFO_LOG);
+```
+LOG记录日志默认是异步的,也可以设置为同步:
+```cpp
+TarsRollLogger::getInstance()->sync(true);
+```
+在任何ostream的地方也可以使用LOG,例如:
+```cpp
+ostream &print(ostream &os);
+```
+可以如下使用:
+```cpp
+print(LOG->debug());
+```
+
+## 8.2.	DLOG/FDLOG
+
+用于记录按天日志,即所谓的按天日志,主要用于记录重要的业务信息;
+> * DLOG是默认的按条日志,FDLOG可以指定按条日志的文件名称;
+> * DLOG/FDLOG的日志会自动上传到tarslog,可以设置为不上传到tarslog;
+> * DLOG/FDLOG可以修改滚动的时间,比如按分钟,小时等;
+> * DLOG/FDLOG记录日志默认是异步的,如果有必要也可以设置为同步,但是对于远程上传到tarslog一定是异步的,不能设置为同步;
+> * DLOG/FDLOG可以设置不记录到本地,只上传到远程;
+> * 在使用的地方需要#include  "servant/TarsLogger.h"
+
+## 8.3.	代码示例
+```cpp
+CommunicatorPtr c = new Communicator();
+
+string logObj = "tars.tarslog.LogObj@tcp -h 127.0.0.1 -p 20500";
+
+//初始化本地滚动日志
+TarsRollLogger::getInstance()->setLogInfo("Test", "TestServer", "./");
+
+//初始化时间日志
+TarsTimeLogger::getInstance()->setLogInfo(c, logObj , "Test", "TestServer", "./");
+
+//如果是Tars服务,不需要上面部分的代码,框架已经自动完成初始化,不用业务自己初始化
+
+//缺省的按天日志不用上传到服务器
+TarsTimeLogger::getInstance()->enableRemote("", false);
+
+//缺省的按天日志按分钟滚动
+TarsTimeLogger::getInstance()->initFormat("", "%Y%m%d%H%M");
+
+//abc2文件不用上传到服务器
+TarsTimeLogger::getInstance()->enableRemote("abc2", false);
+
+//abc2文件按小时滚动
+TarsTimeLogger::getInstance()->initFormat("abc2", "%Y%m%d%H");
+
+//abc3文件不记本地
+TarsTimeLogger::getInstance()->enableLocal("abc3", false);
+
+int i = 100000;
+while(i--)
+{
+    //与上一个一样
+    TLOGDEBUG(i << endl);
+    
+    //error级别
+    TLOGERROR(i << endl);
+
+    DLOG << i << endl;
+    
+    FDLOG("abc1") << i << endl;
+    FDLOG("abc2") << i << endl;
+    FDLOG("abc3") << i << endl;
+
+    if(i % 1000 == 0)
+    {
+        cout << i << endl;
+    }
+    usleep(10);
+}
+```
+
+# 9. 服务管理
+Tars服务框架可以支持动态接收命令,来处理相关的业务逻辑,例如:动态更新配置等。
+
+框架中定义两个宏:
+> * TARS_ADD_ADMIN_CMD_PREFIX:添加前置的命令处理方法,在所有Normal方法之前执行,多个前置方法之间顺序不确定
+> * TARS_ADD_ADMIN_CMD_NORMAL:添加Normal命令处理方法,在所有前置方法最后执行,多个Normal方法之间顺序不确定
+
+通过使用这两个宏,可以注册命令处理接口,当通过web管理平台向服务发送响应的命令的时候,注册的接口会被调用。
+
+通常注册的接口处理有两种:全局的接口处理和基于对象的接口处理。
+
+下面以HelloServer为例,介绍管理命令的使用。
+
+## 9.1. 全局接口处理
+
+所谓全局接口处理表示,该处理接口是和服务相关的,而不是和HelloImp这种对象相关的。
+
+假设HelloServer增加一个功能,需要接收管理命令,将FDLOG某配置文件设置为不上传到远程tarslog,这种处理与HelloImp对象是没有关系的,因此属于全局的变动,处理步骤:
+
+在HelloServer类中增加处理函数,用于处理该命令,注意函数必须是这种声明方式:
+```cpp
+bool HelloServer::procDLOG(const string& command, const string& params, string& result)
+{
+    TarsTimeLogger::getInstance()->enableLocal(params, false);
+    return false;
+}
+```
+
+在HelloServer::initialize()中注册该函数:
+```cpp
+void HelloServer::initialize()
+{
+    addServant(...);
+    addConfig(…);
+
+	//注册处理函数:
+    TARS_ADD_ADMIN_CMD_NORMAL("DISABLEDLOG", HelloServer::procDLOG);
+}
+```
+说明:
+> * 可以在web管理平台上直接给服务发送命令,例如:DISABLEDLOG,表示对缺省的按条日志设置为不写本地,再例如DISABLEDLOG test,表示对test的按条日志不写本地;
+> * 命令处理函数的声明方式必须一样:
+> * 返回值为bool:表示该命令是否往下传,即如果在一个命令上注册了多个接口函数,如果返回false,则执行当前的接口后,后续接口都不在调用;
+> * 第一个参数command:表示注册的命令字符串,这个例子中表示:DISABLEDOG;
+> * 第二个参数params:表示命令参数,会将命令按空格分解出来,后面那部分内容,例如test;
+> * 注册宏采用TARS_ADD_ADMIN_CMD_NORMAL或TARS_ADD_ADMIN_CMD_PREFIX取决于你对命令执行顺序的要求;
+> * 注册宏第一个参数表示命令字(不能包含空格),第二个参数表示对该命令执行的函数;
+
+# 9.2. 基于对象接口处理
+
+所谓基于对象接口的处理表示该命令接口是针对服务中的对象的。
+
+例如针对HelloImp对象,这个时候如果发送一个命令给服务,则每个线程中的HelloImp的命令接口都会被执行一次,并且执行这些接口的过程和执行HelloImp的自身的接口是互斥的(即线程安全的)。
+
+假设HelloImp有成员变量string _hello,需要发送命令通知每个HelloImp对象将_hello修改为自定义的值,步骤如下:
+
+在HelloImp中增加处理函数
+```cpp
+bool HelloImp::procHello(const string& command, const string& params, string& result)
+{
+    _hello = params;
+    return false;
+}
+```
+在HelloImp的初始化中注册函数:
+```cpp
+void HelloImp::initialize()
+{
+    //注册处理函数:
+    TARS_ADD_ADMIN_CMD_NORMAL("SETHELLO", HelloImp::procHello);
+}
+```
+完成上面操作即可,在web页面上发送SETHELLO test,则将_hello赋值为test;
+
+# 9.3. 发送管理命令
+服务的管理命令的发送方式:通过web管理平台,将TARS服务发布到平台上,通过管理平台发送命令;
+	
+TARS服务框架目前内置了八种命令:
+
+> * tars.help    		//查看所有管理命令
+> * tars.loadconfig     //从配置中心, 拉取配置下来: tars.loadconfig filename
+> * tars.setloglevel    //设置滚动日志的等级: tars.setloglevel [NONE, ERROR, WARN, DEBUG]
+> * tars.viewstatus     //查看服务状态
+> * tars.connection     //查看当前链接情况
+> * tars.loadproperty	//使配置文件的property信息生效
+> * tars.setdyeing    //设置染色信息 tars.setdyeing key servant [interface]
+
+# 10. 统计上报
+所谓的上报统计信息是Tars框架内部,向tarsstat上报调用耗时等信息的逻辑。不需用户开发,在程序初始化时正确设置相关信息后,框架内部(包括客户端和服务端)即可自动上报。
+
+客户端调用上报接口后,实际先暂存在内存中,当到达某个时间点后才正式上报到tarsstat服务(默认是1分钟上报一次)。我们称两个上报时间点之间的时间为一个统计区间,在一个统计区间相同key进行累加、对比等操作。
+示例代码如下
+```cpp
+//初始化通信器
+CommunicatorPtr pcomm = new Communicator();
+//初始化tarsregistry服务地址
+pcomm->setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h xxx.xxx.xxx.xx -p xxxx"
+//初始化stat服务
+pcomm->setProperty("stat", "tars.tarsstat.StatObj");
+//设置上报间隔
+pcomm->setProperty("report-interval", "1000");
+//设置上报主调名称
+pcomm->setProperty("modulename", "Test.TestServer_Client");
+
+```
+说明:
+> * 如果主调的服务是在web管理系统上部署的,不需要定义Communicator,也不需要设置tarsregistry、tarsstat等配置,服务会自动上报
+> * 如果主调的服务或程序不是在web管理系统上部署,则需要定义Communicator,设置tarsregistry、tarsstat等配置,这样在web管理系统上才能查看被调服务的服务监控时,才有流量
+> * 上报数据是定时上报的,可以在通信器的配置中设置;
+
+# 11. 异常上报
+为了更好监控,TARS框架支持在程序中将异常直接上报到tarsnotify,并可以在WEB管理页面上查看到。
+
+框架提供的三种宏用户上报不同种类的异常:
+```cpp
+//上报普通信息
+TARS_NOTIFY_NORMAL(info) 
+//上报警告信息
+TARS_NOTIFY_WARN(info) 
+//上报错误信息
+TARS_NOTIFY_ERROR(info)
+```
+Info为字符串, 可以直接上报字符串到tarsnotify,页面可以看到上报的字符串,后续可以根据上报的信息进行报警。
+
+# 12. 属性统计
+为了方便业务做统计,TARS框架中也支持能够在web管理平台看上报的信息展示。
+
+目前支持的统计类型包括以下几种:
+> * 求和(sum)
+> * 平均(avg)
+> * 分布(distr)
+> * 最大值(max)
+> * 最小值(min)
+> * 计数(count)
+
+示例代码如下:
+```cpp
+//初始化通信器
+Communicator _comm;
+//初始化property服务地址
+_comm.setProperty("property", "tars.tarsproperty.PropertyObj@ tcp -h xxx.xxx.xxx.xxx -p xxxx");
+
+//初始化分布数据范围
+vector<int> v;
+v.push_back(10);
+v.push_back(30);
+v.push_back(50);
+v.push_back(80);
+v.push_back(100);
+
+//创建test1属性,该属性用到了上诉所有的集中统计方式,注意distrv的初始化
+PropertyReportPtr srp = _comm.getStatReport()->createPropertyReport("test1", 
+PropertyReport::sum(), 
+PropertyReport::avg(), 
+PropertyReport::count(),
+PropertyReport::max(), 
+PropertyReport::min(),
+PropertyReport::distr(v));
+
+//上报数据,property只支持int类型的数据上报
+int iValue = 0;
+for ( int i = 0; i < 10000000; i++ )
+{
+        sleep(1);
+     srp->report(rand() % 100 );
+}
+```
+
+说明:
+> * 上报数据是定时上报的,可以在通信器的配置中设置,目前是1分钟一次;
+> * 创建PropertyReportPtr的函数:createPropertyReport的参数可以是任何统计方式的集合,例子中是用到6六种统计方式,通常情况下可能只需要用到一种或两种;
+> * 注意调用createPropertyReport时,必须在服务启动以后创建并保存好创建的对象,后续拿这个对象report即可,不要每次使用的时候create;
+

+ 44 - 0
docs/tars_protobuf_cpp.md

@@ -0,0 +1,44 @@
+# tars支持protobuf service描述文件
+
+如果当你了解到tars的时候,你已经有不少已有业务采用了protobuf协议;如果想要把这些业务迁移到tars,你还需要手动把proto文件翻译成tars文件,非常麻烦而且容易出错。
+现在tars使用protoc的插件机制,提供了对proto文件的直接支持,能够生成tars rpc相关代码,使得迁移平滑省心。
+
+
+## 使用方法
+
+
+### 1. 准备proto文件
+proto文件的语法是不限制的,你可以使用proto2或proto3;
+但注意,一定加上**option cc_generic_services=false;**
+因为我们的目标就是不使用protoc生成的pb rpc接口,而是要用tars插件接管,生成符合tars框架的rpc接口.
+一个proto文件的示例如下:
+
+
+```cpp
+syntax = "proto2";
+
+option cc_generic_services=false;
+
+package TestApp;
+
+message PbRequest {
+    required int32 a = 1;
+    required int32 b = 2;
+}
+
+message PbResponse { 
+    required int32 c = 1;
+}  
+
+service Hello {
+    rpc add(PbRequest) returns (PbResponse) {
+    }
+}
+```
+
+
+### 2. 直接执行make即可
+因为调用tars pb插件的语句,已经内置在框架makefile.tars文件中。
+由于protoc默认生成的文件名带有.pb.h后缀,tars插件也遵循这个命名规则,生成的文件后缀是.tars.h
+
+

+ 684 - 0
docs/tars_push.md

@@ -0,0 +1,684 @@
+# Tars的push功能
+
+# 目录
+> * [1.环境和背景] 
+> * [2.push模式的流程图] 
+> * [3.服务端功能的实现] 
+> * [4.客户端功能的实现] 
+> * [5.测试结果] 
+
+
+## 环境和背景
+
+但是在实际的应用场景中,需要在TARS服务框架中支持其他服务端到客户端的push模式
+
+具体程序示例,参见cpp/examples/pushDemo/.
+
+## push模式的流程图
+下面是push模式的示意图
+
+![tars](images/tars_flow.PNG)
+
+- 黑色线代表了数据流向:数据(客户端)-〉请求包的编码器(客户端)-〉协议解析器(服务端)-〉doRequest协议处理器(服务端)-〉生成返回数据(服务端)-〉响应包的解码器(客户端)-〉响应数据(客户端)
+- 黄色线代表客户端访问服务端
+- 蓝色线代表服务端向客户端push消息
+- 其中**请求包的编码器**(客户端)负责对客户端发送的数据进行打包编码,**协议解析器**(服务端)负责对收到的数据进行解包并交给*
+- **协议处理器**(服务端)去处理并生成返回数据,而**响应包的解码器**(客户端)负责对返回的数据进行解码。
+
+## Tars中实现服务端到客户端的push模式:
+
+- 对于服务端,首先服务端需要按照开发第三方协议的模式(即非tars协议),实现协议包的解析器,并将其加载到服务中,同时需要建立一个非TARS框架的服务对象,该类继续继承TARS框架的Servant类,通过重载Servant类中的doRequest方法建立客户端和服务端之间的协议处理器,同时在该方法中保存连接到服务端的客户信息,以便服务端向客户端push消息,另外需要重载Servant类中的doClose方法,在服务器得知客户关闭连接后,释放doRequest方法中保存的客户信息,这样就可以不需要对该客户进行push消息。另外,服务端需要建立一个专门用于向客户端push消息的线程。
+- 对应客户端,首先要按照第三方协议的模式,实现协议包的编解码函数,并将其设置到相应的ServantProxy代理的协议解析器中,通过ServantProxy类tars_set_protocol方法实现;然后需要自定义一个回调类,该类继承ServantProxyCallback类,(因为服务端push消息给客户端时,客户端收到消息是异步的,所以客户端对消息的处理以异步方法进行),同时需要重载其中的onDispatch方法,在该方法中,对客户端和服务端之间定义的协议进行解析处理;最后需要new一个上面自定义的回调类,然后将其作为参数传入到ServantProxy的tars_set_push_callback方法中。另外,客户端需要定期的发送消息给服务端(相当于心跳包),以便告诉服务端,客户端是存活的(因为服务端在一定时间内没收到来自客户端的消息,会自动关闭其之间的连接)。
+另外,在服务端与客户端push模式交互之前,客户端要访问服务,需要通过调用ServantProxy类的rpc相关函数。
+
+## 服务端功能的实现
+
+### 服务端实现概述
+首先我们按照第三方协议代码部署一个TestPushServant 服务
+如下图所示在管理平台部署一个服务端
+
+![tars](images/tars_push_deploy.PNG)
+
+参考tars 支持第三方协议
+
+- 其中TestPushServer类的initialize( ) 加载服务对象TestPushServantImp,并设置第三方协议解析器parse,这里解析器不做任何处理,把接收到的数据包原封不动的传给服务对象去处理(但通常情况下,要对数据进行解析后才交给服务对象去处理),
+- 而TestPushServantImp重载继承自Servant类的doRequest方法,该方法为第三方服务的协议处理器,该处理器负责处理协议解析器传送给其的数据,并负责生成返回给客户端的response(本服务为echo服务,因此直接让response等于收到的数据包),同时保存客户的信息状态,以便让pushThread线程对客户进行push消息;
+- 另外TestPushServantImp重载继承自Servant类的doClose方法,用于客户关闭连接或者连接超时后清除保存相关的客户信息。
+
+
+### 服务端代码实现
+TestPushServantImp.h
+```cpp
+#ifndef _TestPushServantImp_H_
+#define _TestPushServantImp_H_
+
+#include "servant/Application.h"
+//#include "TestPushServant.h"
+
+/**
+ *
+ *
+ */
+class TestPushServantImp : public  tars::Servant
+{
+public:
+    /**
+     *
+     */
+    virtual ~TestPushServantImp() {}
+
+    /**
+     *
+     */
+    virtual void initialize();
+
+    /**
+     *
+     */
+    virtual void destroy();
+
+    /**
+     *
+     */
+    virtual int test(tars::TarsCurrentPtr current) { return 0;};
+
+
+    //重载Servant的doRequest方法
+    int doRequest(tars::TarsCurrentPtr current, vector<char>& response);
+
+    //重载Servant的doClose方法
+    int doClose(tars::TarsCurrentPtr current);
+
+};
+/////////////////////////////////////////////////////
+#endif
+```
+TestPushServantImp.cpp
+```cpp
+#include "TestPushServantImp.h"
+#include "servant/Application.h"
+#include "TestPushThread.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////
+void TestPushServantImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+
+//////////////////////////////////////////////////////
+void TestPushServantImp::destroy()
+{
+    //destroy servant here:
+    //...
+}
+
+
+int TestPushServantImp::doRequest(tars::TarsCurrentPtr current, vector<char>& response)
+{
+//保存客户端的信息,以便对客户端进行push消息
+	(PushUser::mapMutex).lock();
+	map<string, TarsCurrentPtr>::iterator it = PushUser::pushUser.find(current->getIp());
+	if(it == PushUser::pushUser.end())
+	{
+		PushUser::pushUser.insert(map<string, TarsCurrentPtr>::value_type(current->getIp(), current));
+		LOG->debug() << "connect ip: " << current->getIp() << endl;
+	}
+	(PushUser::mapMutex).unlock();
+//返回给客户端它自己请求的数据包,即原包返回
+	const vector<char>& request = current->getRequestBuffer();
+	response = request;
+
+	return 0;
+}
+//客户端关闭到服务端的连接,或者服务端发现客户端长时间未发送包过来,然后超过60s就关闭连接
+//调用的方法
+int TestPushServantImp::doClose(TarsCurrentPtr current)
+{
+	(PushUser::mapMutex).lock();
+	map<string, TarsCurrentPtr>::iterator it = PushUser::pushUser.find(current->getIp());
+	if(it != PushUser::pushUser.end())
+	{
+		PushUser::pushUser.erase(it);
+		LOG->debug() << "close ip: " << current->getIp() << endl;
+	}
+	(PushUser::mapMutex).unlock();
+
+	return 0;
+}
+
+```
+TestPushThread.h
+```cpp
+
+#ifndef __TEST_PUSH_THREAD_H
+#define __TEST_PUSH_THREAD_H
+
+#include "servant/Application.h"
+
+class PushUser
+{
+public:
+	static map<string, TarsCurrentPtr> pushUser;
+	static TC_ThreadMutex mapMutex;
+};
+
+class PushInfoThread : public TC_Thread, public TC_ThreadLock
+{
+public:
+	PushInfoThread():_bTerminate(false),_tLastPushTime(0),_tInterval(10),_iId(0){}
+
+	virtual void run();
+
+	void terminate();
+
+	void setPushInfo(const string &sInfo);
+
+private:
+	bool _bTerminate;
+	time_t _tLastPushTime;
+	time_t _tInterval;
+	unsigned int _iId;
+	string _sPushInfo;
+};
+#endif
+
+
+```
+TestPushThread.cpp
+```cpp
+#include "TestPushThread.h"
+#include <arpa/inet.h>
+
+map<string, TarsCurrentPtr> PushUser::pushUser;
+TC_ThreadMutex PushUser::mapMutex;
+
+
+void PushInfoThread::terminate(void)
+{
+	_bTerminate = true;
+	{
+	    tars::TC_ThreadLock::Lock sync(*this);
+	    notifyAll();
+	}
+}
+
+void PushInfoThread::setPushInfo(const string &sInfo)
+{
+	  unsigned int iBuffLength = htonl(sInfo.size()+8);
+    unsigned char * pBuff = (unsigned char*)(&iBuffLength);
+
+    _sPushInfo = "";
+    for (int i = 0; i<4; ++i)
+    {
+        _sPushInfo += *pBuff++;
+    }
+
+    unsigned int iRequestId = htonl(_iId);
+    unsigned char * pRequestId = (unsigned char*)(&iRequestId);
+
+    for (int i = 0; i<4; ++i)
+    {
+        _sPushInfo += *pRequestId++;
+    }
+
+    _sPushInfo += sInfo;
+}
+//定期向客户push消息
+void PushInfoThread::run(void)
+{
+	time_t iNow;
+
+	setPushInfo("hello world");
+
+	while (!_bTerminate)
+	{
+		iNow =  TC_TimeProvider::getInstance()->getNow();
+
+		if(iNow - _tLastPushTime > _tInterval)
+		{
+			_tLastPushTime = iNow;
+
+			(PushUser::mapMutex).lock();
+			for(map<string, TarsCurrentPtr>::iterator it = (PushUser::pushUser).begin(); it != (PushUser::pushUser).end(); ++it)
+			{
+				(it->second)->sendResponse(_sPushInfo.c_str(), _sPushInfo.size());
+				LOG->debug() << "sendResponse: " << _sPushInfo.size() <<endl;
+			}
+			(PushUser::mapMutex).unlock();
+		}
+
+		{
+            TC_ThreadLock::Lock sync(*this);
+            timedWait(1000);
+		}
+	}
+}
+
+```
+TestPushServer.h
+```cpp
+#ifndef _TestPushServer_H_
+#define _TestPushServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+#include "TestPushThread.h"
+
+
+using namespace tars;
+
+/**
+ *
+ **/
+class TestPushServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~TestPushServer() {};
+
+    /**
+     *
+     **/
+    virtual void initialize();
+
+    /**
+     *
+     **/
+    virtual void destroyApp();
+
+    private:
+    //用于push消息的线程
+    PushInfoThread  pushThread;
+
+};
+
+extern TestPushServer g_app;
+
+////////////////////////////////////////////
+#endif
+
+```
+
+TestPushServer.cpp
+```cpp
+#include "TestPushServer.h"
+#include "TestPushServantImp.h"
+
+using namespace std;
+
+TestPushServer g_app;
+
+/////////////////////////////////////////////////////////////////
+
+static int parse(string &in, string &out)
+{
+    if(in.length() < sizeof(unsigned int))
+    {
+        return TC_EpollServer::PACKET_LESS;
+    }
+
+    unsigned int iHeaderLen;
+
+    memcpy(&iHeaderLen, in.c_str(), sizeof(unsigned int));
+
+    iHeaderLen = ntohl(iHeaderLen);
+
+    if(iHeaderLen < (unsigned int)(sizeof(unsigned int))|| iHeaderLen > 1000000)
+    {
+        return TC_EpollServer::PACKET_ERR;
+    }
+
+    if((unsigned int)in.length() < iHeaderLen)
+    {
+        return TC_EpollServer::PACKET_LESS;
+    }
+
+    out = in.substr(0, iHeaderLen);
+
+    in  = in.substr(iHeaderLen);
+
+    return TC_EpollServer::PACKET_FULL;
+}
+
+
+void
+TestPushServer::initialize()
+{
+    //initialize application here:
+    //...
+
+    addServant<TestPushServantImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".TestPushServantObj");
+
+    addServantProtocol("Test.TestPushServer.TestPushServantObj", parse);
+
+    pushThread.start();
+
+}
+/////////////////////////////////////////////////////////////////
+void
+TestPushServer::destroyApp()
+{
+    //destroy application here:
+    //...
+    pushThread.terminate();
+    pushThread.getThreadControl().join();
+
+}
+/////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+/////////////////////////////////////////////////////////////////
+```
+
+## 客户端实现
+
+### 客户端实现概述
+本节介绍客户端通过proxy的方式来访问服务端,具体步骤如下:
+- 客户端首先建立通信器(Communicator _comm),并通过该通信器获取proxy,代码格式如下:
+
+ ```cpp
+  string sObjName = "Test.TestPushServer.TestPushServantObj";
+  string sObjHost = "tcp -h 10.120.129.226 -t 60000 -p 10099";
+	_prx = _comm.stringToProxy<ServantPrx>(sObjName+"@"+sObjHost);
+```
+-  编写proxy的请求包的编码器和响应包的解码器并设置,代码格式如下:
+  ```
+请求包的编码器格式:
+static void FUN1(const RequestPacket& request, string& buff)
+响应包的解码器格式:
+static size_t FUN2(const char* recvBuffer, size_t length, list<ResponsePacket>& done)
+proxy设置代码为:
+ProxyProtocol prot;
+prot.requestFunc = FUN1;
+prot.responseFunc = FUN2 ;
+_prx->tars_set_protocol(prot);
+```
+ - 同步方法或者异步方法访问服务端
+ 
+	  - 同步方法通过调用proxy的rpc_call方法访问服务
+   ```
+	 virtual void rpc_call(uint32_t requestId, const string& sFuncName,const char* buff, uint32_t len, ResponsePacket& rsp);  
+   ```
+   其中参数requestId需要在一个object内唯一,可以通过proxy的 uint32_t tars_gen_requestid()接口获得一个该object内唯一的id。sFuncName主要用于框架层对接口调用的统计分析,可以缺省为""。buff为要发送的内容,len为buff的长度。rsp则为本次调用得到的ResponsePacket包。
+
+    - 异步方法通过调用proxy的rpc_call_asyc方法访问服务
+    
+      ```
+			virtual void rpc_call_async(uint32_t requestId, const string& sFuncName, const char* buff, uint32_t len,  const ServantProxyCallbackPtr& callback);
+      ```
+      其中参数requestId需要在一个object内唯一,可以通过proxy的 uint32_t tars_gen_requestid()接口获得一个该object内唯一的id。sFuncName为回调对象响应后调用的函数名。buff为要发送的内容,len为buff的长度。callback则为本次调用返回结果后,即服务端返回处理结果后,此回调对象会被响应。
+
+- 设置接受服务端的push消息方法:
+```
+TestPushCallBackPtr cbPush = new TestPushCallBack();
+_prx->tars_set_push_callback(cbPush);
+ ``` 
+  
+### 客户端具体实现
+
+main.cpp
+```cpp
+#include "servant/Application.h"
+#include "TestRecvThread.h"
+#include <iostream>
+
+using namespace std;
+using namespace tars;
+
+int main(int argc,char**argv)
+{
+    try
+    {
+		RecvThread thread;
+		thread.start();
+
+		int c;
+		while((c = getchar()) != 'q');
+
+		thread.terminate();
+		thread.getThreadControl().join();
+    }
+    catch(std::exception&e)
+    {
+        cerr<<"std::exception:"<<e.what()<<endl;
+    }
+    catch(...)
+    {
+        cerr<<"unknown exception"<<endl;
+    }
+    return 0;
+}
+
+```
+TestRecvThread.h
+```
+#ifndef __TEST_RECV_THREAD_H
+#define __TEST_RECV_THREAD_H
+
+#include "servant/Application.h"
+
+class TestPushCallBack : public ServantProxyCallback
+{
+public:
+	virtual int onDispatch(ReqMessagePtr msg);
+};
+typedef tars::TC_AutoPtr<TestPushCallBack> TestPushCallBackPtr;
+
+class RecvThread : public TC_Thread, public TC_ThreadLock
+{
+public:
+	RecvThread();
+
+	virtual void run();
+
+	void terminate();
+private:
+	bool _bTerminate;
+
+	Communicator _comm;
+
+	ServantPrx  _prx;
+};
+#endif
+
+```
+TestRecvThread.cpp
+```
+#include "TestRecvThread.h"
+#include <iostream>
+#include <arpa/inet.h>
+
+/*
+ 响应包解码函数,根据特定格式解码从服务端收到的数据,解析为ResponsePacket
+*/
+static size_t pushResponse(const char* recvBuffer, size_t length, list<ResponsePacket>& done)
+{
+	size_t pos = 0;
+    while (pos < length)
+    {
+        unsigned int len = length - pos;
+        if(len < sizeof(unsigned int))
+        {
+            break;
+        }
+
+        unsigned int iHeaderLen = ntohl(*(unsigned int*)(recvBuffer + pos));
+
+        //做一下保护,长度大于M
+        if (iHeaderLen > 100000 || iHeaderLen < sizeof(unsigned int))
+        {
+            throw TarsDecodeException("packet length too long or too short,len:" + TC_Common::tostr(iHeaderLen));
+        }
+
+        //包没有接收全
+        if (len < iHeaderLen)
+        {
+            break;
+        }
+        else
+        {
+            ResponsePacket rsp;
+			rsp.iRequestId = ntohl(*((unsigned int *)(recvBuffer + pos + sizeof(unsigned int))));
+			rsp.sBuffer.resize(iHeaderLen - 2*sizeof(unsigned int));
+		  ::memcpy(&rsp.sBuffer[0], recvBuffer + pos + 2*sizeof(unsigned int), iHeaderLen - 2*sizeof(unsigned int));
+
+			pos += iHeaderLen;
+
+            done.push_back(rsp);
+        }
+    }
+
+    return pos;
+}
+/*
+   请求包编码函数,本函数的打包格式为
+   整个包长度(字节)+iRequestId(字节)+包内容
+*/
+static void pushRequest(const RequestPacket& request, string& buff)
+{
+    unsigned int net_bufflength = htonl(request.sBuffer.size()+8);
+    unsigned char * bufflengthptr = (unsigned char*)(&net_bufflength);
+
+    buff = "";
+    for (int i = 0; i<4; ++i)
+    {
+        buff += *bufflengthptr++;
+    }
+
+    unsigned int netrequestId = htonl(request.iRequestId);
+    unsigned char * netrequestIdptr = (unsigned char*)(&netrequestId);
+
+    for (int i = 0; i<4; ++i)
+    {
+        buff += *netrequestIdptr++;
+    }
+
+    string tmp;
+    tmp.assign((const char*)(&request.sBuffer[0]), request.sBuffer.size());
+    buff+=tmp;
+}
+
+static void printResult(int iRequestId, const string &sResponseStr)
+{
+	cout << "request id: " << iRequestId << endl;
+	cout << "response str: " << sResponseStr << endl;
+}
+static void printPushInfo(const string &sResponseStr)
+{
+	cout << "push message: " << sResponseStr << endl;
+}
+
+int TestPushCallBack::onDispatch(ReqMessagePtr msg)
+{
+	if(msg->request.sFuncName == "printResult")
+	{
+		string sRet;
+		cout << "sBuffer: " << msg->response.sBuffer.size() << endl;
+		sRet.assign(&(msg->response.sBuffer[0]), msg->response.sBuffer.size());
+		printResult(msg->request.iRequestId, sRet);
+		return 0;
+	}
+	else if(msg->response.iRequestId == 0)
+	{
+		string sRet;
+		sRet.assign(&(msg->response.sBuffer[0]), msg->response.sBuffer.size());
+		printPushInfo(sRet);
+		return 0;
+	}
+	else
+	{
+		cout << "no match func!" <<endl;
+	}
+	return -3;
+}
+
+RecvThread::RecvThread():_bTerminate(false)
+{
+	string sObjName = "Test.TestPushServer.TestPushServantObj";
+    string sObjHost = "tcp -h 10.120.129.226 -t 60000 -p 10099";
+
+    _prx = _comm.stringToProxy<ServantPrx>(sObjName+"@"+sObjHost);
+
+	ProxyProtocol prot;
+    prot.requestFunc = pushRequest;
+    prot.responseFunc = pushResponse;
+
+    _prx->tars_set_protocol(prot);
+}
+
+void RecvThread::terminate()
+{
+	_bTerminate = true;
+	{
+	    tars::TC_ThreadLock::Lock sync(*this);
+	    notifyAll();
+	}
+}
+
+void RecvThread::run(void)
+{
+	TestPushCallBackPtr cbPush = new TestPushCallBack();
+	_prx->tars_set_push_callback(cbPush);	
+
+	string buf("heartbeat");
+
+	while(!_bTerminate)
+	{
+		{
+			try
+			{
+				TestPushCallBackPtr cb = new TestPushCallBack();
+				_prx->rpc_call_async(_prx->tars_gen_requestid(), "printResult", buf.c_str(), buf.length(), cb);
+			}
+			catch(TarsException& e)
+			{     
+				cout << "TarsException: " << e.what() << endl;
+			}
+			catch(...)
+			{
+				cout << "unknown exception" << endl;
+			}
+		}
+
+		{
+            TC_ThreadLock::Lock sync(*this);
+            timedWait(5000);
+		}
+	}
+}
+
+```
+
+
+## 客户端测试结果
+
+如果push 成功,结果如下
+
+![tars](images/tars_result.PNG)
+
+
+
+
+
+

+ 14 - 0
examples/CoroutineDemo/AServer/AServant.tars

@@ -0,0 +1,14 @@
+
+module Test
+{
+
+interface AServant
+{
+    int test();
+    
+    int testInt(int iIn,out int iOut);
+    
+    int testStr(string sIn, out string sOut);
+};
+
+}; 

+ 56 - 0
examples/CoroutineDemo/AServer/AServantImp.cpp

@@ -0,0 +1,56 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "AServantImp.h"
+#include "AServer.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////
+void AServantImp::initialize()
+{
+	//initialize servant here:
+	//...
+}
+
+//////////////////////////////////////////////////////
+void AServantImp::destroy()
+{
+	//destroy servant here:
+	//...
+}
+
+
+int AServantImp::test(tars::TarsCurrentPtr current) 
+{
+	return 0;
+}
+
+tars::Int32 AServantImp::testInt(tars::Int32 iIn,tars::Int32 &iOut,tars::TarsCurrentPtr current)
+{
+
+    iOut = iIn;
+    
+    return 0;
+}
+
+tars::Int32 AServantImp::testStr(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current)
+{
+
+	sOut = sIn;
+
+	return 0;
+}

+ 58 - 0
examples/CoroutineDemo/AServer/AServantImp.h

@@ -0,0 +1,58 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#ifndef _AServantImp_H_
+#define _AServantImp_H_
+
+#include "servant/Application.h"
+#include "AServant.h"
+
+/**
+ *
+ *
+ */
+class AServantImp : public Test::AServant
+{
+public:
+	/**
+	 *
+	 */
+	virtual ~AServantImp() {}
+
+	/**
+	 *
+	 */
+	virtual void initialize();
+
+	/**
+	 *
+	 */
+    virtual void destroy();
+
+	/**
+	 *
+	 */
+	virtual int test(tars::TarsCurrentPtr current); 
+
+	tars::Int32 testInt(tars::Int32 iIn,tars::Int32 &iOut,tars::TarsCurrentPtr current);
+
+	tars::Int32 testStr(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current);
+
+private:
+
+};
+/////////////////////////////////////////////////////
+#endif

+ 58 - 0
examples/CoroutineDemo/AServer/AServer.cpp

@@ -0,0 +1,58 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "AServer.h"
+#include "AServantImp.h"
+
+using namespace std;
+
+AServer g_app;
+
+/////////////////////////////////////////////////////////////////
+void
+AServer::initialize()
+{
+	//initialize application here:
+	//...
+
+	addServant<AServantImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".AServantObj");
+}
+/////////////////////////////////////////////////////////////////
+void
+AServer::destroyApp()
+{
+	//destroy application here:
+	//...
+}
+/////////////////////////////////////////////////////////////////
+int main(int argc, char* argv[])
+{
+	try
+	{
+		g_app.main(argc, argv);
+		g_app.waitForShutdown();
+	}
+	catch (std::exception& e)
+	{
+		cerr << "std::exception:" << e.what() << std::endl;
+	}
+	catch (...)
+	{
+		cerr << "unknown exception." << std::endl;
+	}
+	return -1;
+}
+/////////////////////////////////////////////////////////////////

+ 51 - 0
examples/CoroutineDemo/AServer/AServer.h

@@ -0,0 +1,51 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#ifndef _AServer_H_
+#define _AServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+
+using namespace tars;
+
+/**
+ *
+ **/
+class AServer : public Application
+{
+public:
+	/**
+	 *
+	 **/
+	virtual ~AServer() {};
+
+	/**
+	 *
+	 **/
+	virtual void initialize();
+
+	/**
+	 *
+	 **/
+	virtual void destroyApp();
+
+};
+
+extern AServer g_app;
+
+////////////////////////////////////////////
+#endif

+ 12 - 0
examples/CoroutineDemo/AServer/makefile

@@ -0,0 +1,12 @@
+
+#-----------------------------------------------------------------------
+APP       := Test
+TARGET    := AServer
+CONFIG    := 
+STRIP_FLAG:= N
+
+INCLUDE   +=
+
+#-----------------------------------------------------------------------
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 14 - 0
examples/CoroutineDemo/BServer/AServant.tars

@@ -0,0 +1,14 @@
+
+module Test
+{
+
+interface AServant
+{
+    int test();
+    
+    int testInt(int iIn,out int iOut);
+    
+    int testStr(string sIn, out string sOut);
+};
+
+}; 

+ 15 - 0
examples/CoroutineDemo/BServer/BServant.tars

@@ -0,0 +1,15 @@
+
+module Test
+{
+	
+interface BServant
+{
+    int test();
+    
+    int testCoroSerial(string sIn, out string sOut);
+    
+    int testCoroParallel(string sIn, out string sOut);
+
+};
+
+}; 

+ 140 - 0
examples/CoroutineDemo/BServer/BServantImp.cpp

@@ -0,0 +1,140 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "BServantImp.h"
+#include "BServer.h"
+#include "servant/Application.h"
+#include "servant/Communicator.h"
+
+using namespace std;
+using namespace tars;
+
+
+//////////////////////////////////////////////////////
+void BServantImp::initialize()
+{
+	//initialize servant here:
+	//...
+	_pPrx = Application::getCommunicator()->stringToProxy<AServantPrx>("Test.AServer.AServantObj");
+}
+//////////////////////////////////////////////////////
+void BServantImp::destroy()
+{
+}
+
+class AServantCoroCallback : public AServantCoroPrxCallback
+{
+public:
+    virtual ~AServantCoroCallback(){}
+
+    virtual void callback_testInt(tars::Int32 ret, tars::Int32 iOut)
+    { 
+		_iRet = ret;
+		_iOut = iOut;
+	}
+    virtual void callback_testInt_exception(tars::Int32 ret)
+    { 
+		_iException = ret; 
+	}
+
+    virtual void callback_testStr(tars::Int32 ret,  const std::string& sOut)
+    { 
+		_iRet = ret;
+		_sOut = sOut; 
+	}
+    virtual void callback_testStr_exception(tars::Int32 ret)
+    { 
+		_iException = ret;  
+	}
+
+public:
+	int		_iException;
+	int		_iRet;
+	int		_iOut;
+	string	_sOut;
+};
+typedef tars::TC_AutoPtr<AServantCoroCallback> AServantCoroCallbackPtr;
+
+int BServantImp::test(tars::TarsCurrentPtr current) { return 0;}
+
+tars::Int32 BServantImp::testCoroSerial(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current)
+{
+    try
+    {
+        int	iRet = -1;
+
+	    int	iIn  = 5;
+	    int	iOut = 0;
+
+	    iRet = _pPrx->testInt(iIn, iOut);
+
+        if(iRet == 0)
+        {
+            string	sRet("");
+
+	        iRet =	_pPrx->testStr(sIn, sRet);
+
+            if(iRet == 0)
+            {
+                sOut = sRet;
+            }
+        }
+
+        return iRet;
+    }
+    catch(exception &ex)
+    {
+        TLOGERROR("BServantImp::testCoroSerial exception:" << ex.what() << endl);
+    }
+
+    return -1;
+}
+
+tars::Int32 BServantImp::testCoroParallel(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current)
+{
+    try
+    {
+        int iRet = -1;
+
+        int iIn  = 5;
+
+	    CoroParallelBasePtr sharedPtr = new CoroParallelBase(2);
+
+	    AServantCoroCallbackPtr cb1 = new AServantCoroCallback();
+	    cb1->setCoroParallelBasePtr(sharedPtr);
+	    _pPrx->coro_testInt(cb1, iIn);
+
+	    AServantCoroCallbackPtr cb2 = new AServantCoroCallback();
+	    cb2->setCoroParallelBasePtr(sharedPtr);
+	    _pPrx->coro_testStr(cb2, sIn);
+
+	    coroWhenAll(sharedPtr);
+
+	    if(cb1->_iRet == 0 && cb2->_iRet == 0)
+	    {
+		    sOut = cb2->_sOut;
+            iRet = 0;
+	    }
+
+        return iRet;
+    }
+    catch(exception &ex)
+    {
+        TLOGERROR("BServantImp::testCoroParallel exception:" << ex.what() << endl);
+    }
+
+    return -1;
+}

+ 62 - 0
examples/CoroutineDemo/BServer/BServantImp.h

@@ -0,0 +1,62 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#ifndef _BServantImp_H_
+#define _BServantImp_H_
+
+#include "servant/Application.h"
+#include "BServant.h"
+#include "AServant.h"
+
+using namespace Test;
+
+/**
+ *
+ *
+ */
+class BServantImp : public Test::BServant
+{
+public:
+	/**
+	 *
+	 */
+	virtual ~BServantImp() {}
+
+	/**
+	 *
+	 */
+	virtual void initialize();
+
+	/**
+	 *
+	 */
+    virtual void destroy();
+
+	/**
+	 *
+	 */
+	virtual int test(tars::TarsCurrentPtr current);
+
+	tars::Int32 testCoroSerial(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current);
+
+    tars::Int32 testCoroParallel(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current);
+
+private:
+	AServantPrx _pPrx;
+
+};
+/////////////////////////////////////////////////////
+#endif

+ 55 - 0
examples/CoroutineDemo/BServer/BServer.cpp

@@ -0,0 +1,55 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "BServer.h"
+#include "BServantImp.h"
+
+using namespace std;
+
+BServer g_app;
+
+/////////////////////////////////////////////////////////////////
+void BServer::initialize()
+{
+	//initialize application here:
+	//...
+	addServant<BServantImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".BServantObj");
+}
+/////////////////////////////////////////////////////////////////
+void BServer::destroyApp()
+{
+	//destroy application here:
+	//...
+}
+
+int main(int argc, char* argv[])
+{
+	try
+	{
+		g_app.main(argc, argv);
+		g_app.waitForShutdown();
+	}
+	catch (std::exception& e)
+	{
+		cerr << "std::exception:" << e.what() << std::endl;
+	}
+	catch (...)
+	{
+		cerr << "unknown exception." << std::endl;
+	}
+	return -1;
+}
+/////////////////////////////////////////////////////////////////

+ 51 - 0
examples/CoroutineDemo/BServer/BServer.h

@@ -0,0 +1,51 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#ifndef _BServer_H_
+#define _BServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+
+using namespace tars;
+
+/**
+ *
+ **/
+class BServer : public Application
+{
+public:
+	/**
+	 *
+	 **/
+	virtual ~BServer() {};
+
+	/**
+	 *
+	 **/
+	virtual void initialize();
+
+	/**
+	 *
+	 **/
+	virtual void destroyApp();
+
+};
+
+extern BServer g_app;
+
+////////////////////////////////////////////
+#endif

+ 12 - 0
examples/CoroutineDemo/BServer/makefile

@@ -0,0 +1,12 @@
+
+#-----------------------------------------------------------------------
+APP       := Test
+TARGET    := BServer
+CONFIG    := 
+STRIP_FLAG:= N
+
+INCLUDE   +=
+
+#-----------------------------------------------------------------------
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 7 - 0
examples/CoroutineDemo/README.md

@@ -0,0 +1,7 @@
+该工程是Tars 协程编程示例的代码
+
+
+目录名称 |功能
+-----------------|----------------
+client/BServer/AServer   |   协程编程的示例程序,client访问BServer,BServer用协程方式去并行和串行访问AServer
+testCoro/testParallelCoro   |  协程编程的示例程序,自定义或者继承框架的协程类

+ 15 - 0
examples/CoroutineDemo/client/BServant.tars

@@ -0,0 +1,15 @@
+
+module Test
+{
+	
+interface BServant
+{
+    int test();
+    
+    int testCoroSerial(string sIn, out string sOut);
+    
+    int testCoroParallel(string sIn, out string sOut);
+
+};
+
+}; 

+ 144 - 0
examples/CoroutineDemo/client/main.cpp

@@ -0,0 +1,144 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "BServant.h"
+#include "servant/Communicator.h"
+#include "util/tc_thread_pool.h"
+#include <iostream>
+
+using namespace std;
+using namespace Test;
+using namespace tars;
+
+class Test1
+{
+public:
+    Test1(const string &sStr);
+
+    ~Test1();
+
+    void  queryResult(int iFlag, int iExecuteNum);
+
+private:
+    Communicator    _comm;
+    BServantPrx     _prx;
+};
+
+Test1::Test1(const string &sStr)
+{
+    _comm.setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h 10.208.139.242 -p 17890 -t 10000");
+    _comm.setProperty("stat", "tars.tarsstat.StatObj");
+    _comm.stringToProxy(sStr, _prx);
+}
+
+Test1::~Test1()
+{
+    
+}
+
+void Test1::queryResult(int iFlag, int iExecuteNum)
+{
+    string sIn(10,'a');
+    string sOut("");
+
+    tars::Int32 count = 0;
+    unsigned long sum = 0;
+
+    time_t _iTime=TC_TimeProvider::getInstance()->getNowMs();
+
+    for(int i=0; i<iExecuteNum; i++) 
+    {
+        sOut = "";
+        try
+        {
+            int ret = -1;
+            if(iFlag == 0)
+            {
+                ret = _prx->testCoroSerial(sIn, sOut);
+            }
+            else
+            {
+                ret = _prx->testCoroParallel(sIn, sOut);
+            }
+
+            if(ret == 0)
+            {
+                ++sum;
+                ++count;
+                if(count == iExecuteNum)
+                {
+                    cout << "pthread id: " << pthread_self() << " | " << TC_TimeProvider::getInstance()->getNowMs() - _iTime << endl;
+                    _iTime=TC_TimeProvider::getInstance()->getNowMs();
+                    count = 0;
+                }
+            }
+        }
+        catch(TC_Exception &e)
+        {
+            cout << "pthread id: " << pthread_self() << "id: " << i << "exception: " << e.what() << endl;
+        }
+        catch(...)
+        {
+            cout << "pthread id: " << pthread_self() << "id: " << i << "unknown exception." << endl;
+        }
+    }
+    cout << "succ:" << sum << endl;
+    cout << "sOut:" << sOut << endl;
+}
+
+int main(int argc,char ** argv)
+{
+    if(argc != 5)
+    {
+        cout << "usage: " << argv[0] << " sObj ThreadNum CallTimes  CallMode" << endl;
+        return -1;
+    }
+
+    string s = string(argv[1]);
+
+    Test1 test1(s);
+
+    try
+    {
+        tars::Int32 threads = TC_Common::strto<tars::Int32>(string(argv[2]));
+
+        TC_ThreadPool tp;
+        tp.init(threads);
+        tp.start();
+
+        tars::Int32 times = TC_Common::strto<tars::Int32>(string(argv[3]));
+        tars::Int32 callMode = TC_Common::strto<tars::Int32>(string(argv[4]));
+        
+        for(int i = 0; i<threads; i++) 
+        {
+            auto fw = std::bind(&Test1::queryResult, &test1, callMode, times);
+            tp.exec(fw);
+            cout << "********************" <<endl;
+        }
+
+        tp.wait(); 
+    }
+    catch(exception &e)
+    {
+        cout<<e.what()<<endl;
+    }
+    catch(...)
+    {
+        
+    }
+    
+    return 0;
+}

+ 12 - 0
examples/CoroutineDemo/client/makefile

@@ -0,0 +1,12 @@
+
+#-----------------------------------------------------------------------
+APP       := Test
+TARGET    := client
+CONFIG    := 
+STRIP_FLAG:= N
+
+INCLUDE   +=
+
+#-----------------------------------------------------------------------
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 15 - 0
examples/CoroutineDemo/testCoro/BServant.tars

@@ -0,0 +1,15 @@
+
+module Test
+{
+	
+interface BServant
+{
+    int test();
+    
+    int testCoroSerial(string sIn, out string sOut);
+    
+    int testCoroParallel(string sIn, out string sOut);
+
+};
+
+}; 

+ 107 - 0
examples/CoroutineDemo/testCoro/main.cpp

@@ -0,0 +1,107 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "BServant.h"
+#include "servant/Communicator.h"
+#include "servant/CoroutineScheduler.h"
+#include <iostream>
+
+using namespace std;
+using namespace Test;
+using namespace tars;
+
+//继承框架的协程类
+class TestCoroutine : public Coroutine
+{
+public:
+	TestCoroutine(int iNum, const string &sObj);
+
+	~TestCoroutine() {}
+
+	void handle();
+
+private:
+	int _num;
+	string _sObj;
+	Communicator _comm;
+	BServantPrx _prx;
+};
+
+TestCoroutine::TestCoroutine(int iNum, const string &sObj)
+: _num(iNum)
+, _sObj(sObj)
+{
+	_comm.setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h 10.208.139.242 -p 17890 -t 10000");
+	_comm.stringToProxy(_sObj, _prx);
+}
+
+void TestCoroutine::handle()
+{
+	string sIn(32,'a');
+	string sOut("");
+	unsigned long sum = 0;
+
+	for(int i = 0; i < _num; i++) 
+	{
+		try
+		{
+			int iRet = _prx->testCoroSerial(sIn, sOut);
+			if(iRet == 0)
+			{
+				++sum;
+			}
+
+            sOut = "";
+			iRet = _prx->testCoroParallel(sIn, sOut);
+			if(iRet == 0)
+			{
+				++sum;
+			}
+		}
+		catch(TC_Exception &e)
+		{
+			cout << "i: " << i << "exception: " << e.what() << endl;
+		}
+		catch(...)
+		{
+			cout << "i: " << i << "unknown exception." << endl;
+		}
+	}
+	cout << "succ:" << sum <<endl;
+}
+
+int main(int argc,char ** argv)
+{
+	if(argc != 3)
+	{
+		cout << "usage: " << argv[0] << " CallTimes sObj" << endl;
+		return -1;
+	}
+
+	tars::Int32 iNum = TC_Common::strto<tars::Int32>(string(argv[1]));
+
+	string sObj = string(argv[2]);
+
+	TestCoroutine testCoro(iNum, sObj);
+
+	testCoro.setCoroInfo(10, 128, 128*1024);
+
+	testCoro.start();
+		
+	testCoro.getThreadControl().join();
+	
+    return 0;
+}

+ 12 - 0
examples/CoroutineDemo/testCoro/makefile

@@ -0,0 +1,12 @@
+
+#-----------------------------------------------------------------------
+APP       := Test
+TARGET    := testCoro
+CONFIG    := 
+STRIP_FLAG:= N
+
+INCLUDE   +=
+
+#-----------------------------------------------------------------------
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 15 - 0
examples/CoroutineDemo/testParallelCoro/BServant.tars

@@ -0,0 +1,15 @@
+
+module Test
+{
+	
+interface BServant
+{
+    int test();
+    
+    int testCoroSerial(string sIn, out string sOut);
+    
+    int testCoroParallel(string sIn, out string sOut);
+
+};
+
+}; 

+ 276 - 0
examples/CoroutineDemo/testParallelCoro/main.cpp

@@ -0,0 +1,276 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "BServant.h"
+#include "servant/Communicator.h"
+#include "servant/CoroutineScheduler.h"
+#include <iostream>
+
+using namespace std;
+using namespace Test;
+using namespace tars;
+
+class BServantCoroCallback : public BServantCoroPrxCallback
+{
+public:
+    virtual ~BServantCoroCallback(){}
+
+    virtual void callback_testCoroSerial(tars::Int32 ret, const std::string &sOut) // override
+    {
+    		_iRet = ret;
+    		_sOut = sOut;
+    }
+    virtual void callback_testCoroSerial_exception(tars::Int32 ret) // override
+    {
+    		_iException = ret;
+    }
+
+  virtual void callback_testCoroParallel(tars::Int32 ret, const std::string &sOut) // override
+    {
+    		_iRet = ret;
+    		_sOut = sOut;
+    }
+
+  virtual void callback_testCoroParallel_exception(tars::Int32 ret) // override
+  {
+    		_iException = ret;
+  }
+
+public:
+	int		_iException;
+	int		_iRet;
+	int		_iOut;
+	string	_sOut;
+};
+typedef tars::TC_AutoPtr<BServantCoroCallback> BServantCoroCallbackPtr;
+
+//自定义协程类
+class CoroutineClass : public TC_Thread
+{
+public:
+	/**
+     * 构造函数
+     */
+	CoroutineClass();
+
+	/**
+     * 析构函数
+     */
+	virtual ~CoroutineClass();
+
+	/**
+     * 返回0,代表成功,-1,表示失败
+     */
+	int registerFunc(const vector< tars::TC_Callback<void ()> > &vFunc);
+
+	/**
+     * 线程初始化
+     */
+	virtual void initialize() {}
+
+	/**
+	 * 线程处理方法
+	 */
+	virtual void run();
+
+	/**
+	 * 停止线程
+	 */
+	void terminate();
+
+protected:
+	/**
+	 * 线程已经启动, 进入具体协程处理前调用
+	 */
+	virtual void startCoro() {}
+
+	/**
+	 * 线程马上要退出时调用
+	 */
+	virtual void stopCoro() {}
+
+	/**
+	 * 具体的处理逻辑
+	 */
+	virtual void handleCoro();
+
+protected:
+	CoroutineScheduler *_coroSched;
+	uint32_t			_iPoolSize;
+	size_t				_iStackSize;
+	vector< tars::TC_Callback<void ()> > _vFunc;
+};
+
+CoroutineClass::CoroutineClass()
+: _coroSched(NULL)
+, _iPoolSize(1024)
+, _iStackSize(128*1024)
+{
+}
+
+CoroutineClass::~CoroutineClass()
+{
+	if(isAlive())
+    {
+        terminate();
+
+        getThreadControl().join();
+    }
+}
+
+int CoroutineClass::registerFunc(const vector< tars::TC_Callback<void ()> > &vFunc)
+{
+	if(vFunc.size() > _iPoolSize || vFunc.size() <= 0)
+	{
+		return -1;
+	}
+
+	_vFunc = vFunc;
+
+	return 0;
+}
+
+void CoroutineClass::run()
+{
+	initialize();
+
+	startCoro();
+
+	handleCoro();
+
+	stopCoro();
+}
+
+void CoroutineClass::terminate()
+{
+	if(_coroSched)
+	{
+		_coroSched->terminate();
+	}
+}
+
+void CoroutineClass::handleCoro()
+{
+	_coroSched = new CoroutineScheduler();
+
+	_coroSched->init(_iPoolSize, _iStackSize);
+
+	ServantProxyThreadData * pSptd = ServantProxyThreadData::getData();
+
+	assert(pSptd != NULL);
+
+	pSptd->_sched = _coroSched;
+
+	for(size_t i = 0; i < _vFunc.size(); ++i)
+	{
+		_coroSched->createCoroutine(_vFunc[i]);
+	}
+
+	_coroSched->run();
+
+	delete _coroSched;
+	_coroSched = NULL;
+}
+
+////////////////////////////////////////////
+//继承框架的协程类
+class TestCoroutine : public Coroutine
+{
+public:
+	TestCoroutine(int iNum, const string &sObj);
+
+	~TestCoroutine() {}
+
+	void handle();
+
+private:
+	int _num;
+	string _sObj;
+	Communicator _comm;
+	BServantPrx _prx;
+};
+
+TestCoroutine::TestCoroutine(int iNum, const string &sObj)
+: _num(iNum)
+, _sObj(sObj)
+{
+	_comm.setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h 10.208.139.242 -p 17890 -t 10000");
+	_comm.stringToProxy(_sObj, _prx);
+}
+
+void TestCoroutine::handle()
+{
+	string sIn(32,'a');
+	unsigned long sum = 0;
+
+	for(int i = 0; i < _num; i++) 
+	{
+		try
+		{
+            CoroParallelBasePtr sharedPtr = new CoroParallelBase(2);
+
+			BServantCoroCallbackPtr cb1 = new BServantCoroCallback();
+			cb1->setCoroParallelBasePtr(sharedPtr);
+			_prx->coro_testCoroSerial(cb1, sIn);
+
+			BServantCoroCallbackPtr cb2 = new BServantCoroCallback();
+			cb2->setCoroParallelBasePtr(sharedPtr);
+			_prx->coro_testCoroParallel(cb2, sIn);
+
+			coroWhenAll(sharedPtr);
+
+			cout << "ret1:" << cb1->_sOut << "|ret2:" << cb2->_sOut << endl;
+			;
+			if(cb1->_iRet == 0 && cb2->_iRet == 0 && cb1->_iException == 0 && cb2->_iException == 0)
+			{
+				++sum;
+			}
+		}
+		catch(TC_Exception &e)
+		{
+			cout << "i: " << i << "exception: " << e.what() << endl;
+		}
+		catch(...)
+		{
+			cout << "i: " << i << "unknown exception." << endl;
+		}
+
+	}
+	cout << "succ:" << sum <<endl;
+}
+
+int main(int argc,char ** argv)
+{
+	if(argc != 3)
+	{
+		cout << "usage: " << argv[0] << " CallTimes sObj" << endl;
+		return -1;
+	}
+
+	tars::Int32 iNum = TC_Common::strto<tars::Int32>(string(argv[1]));
+
+	string sObj = string(argv[2]);
+
+	TestCoroutine testCoro(iNum, sObj);
+
+	testCoro.setCoroInfo(10, 128, 128*1024);
+
+	testCoro.start();
+		
+	testCoro.getThreadControl().join();
+	
+    return 0;
+}

+ 12 - 0
examples/CoroutineDemo/testParallelCoro/makefile

@@ -0,0 +1,12 @@
+
+#-----------------------------------------------------------------------
+APP       := Test
+TARGET    := testCoro
+CONFIG    := 
+STRIP_FLAG:= N
+
+INCLUDE   +=
+
+#-----------------------------------------------------------------------
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 175 - 0
examples/HttpDemo/HttpClient/main.cpp

@@ -0,0 +1,175 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include <iostream>
+#include "util/tc_http.h"
+#include "util/tc_common.h"
+#include "util/tc_clientsocket.h"
+#include "util/tc_thread_pool.h"
+#include "tup/Tars.h"
+#include "tup/tup.h"
+#include "util/tc_timeprovider.h"
+using namespace std;
+using namespace tars;
+using namespace tup;
+
+int doRequest(TC_HttpRequest& stHttp,TC_TCPClient&tcpClient, TC_HttpResponse &stHttpRsp, int iTimeout)
+{
+    string sSendBuffer = stHttp.encode();
+
+    int iRet = tcpClient.send(sSendBuffer.c_str(), sSendBuffer.length());
+    if(iRet != TC_ClientSocket::EM_SUCCESS)
+    {
+        return iRet;
+    }
+
+    stHttpRsp.reset();
+
+    string sBuffer;
+
+    char *sTmpBuffer = new char[10240];
+    size_t iRecvLen  = 10240;
+
+    while(true)
+    {
+        iRecvLen = 10240;
+
+        iRet = tcpClient.recv(sTmpBuffer, iRecvLen);
+
+        if(iRet == TC_ClientSocket::EM_SUCCESS)
+        sBuffer.append(sTmpBuffer, iRecvLen);
+
+        switch(iRet)
+        {
+        case TC_ClientSocket::EM_SUCCESS:
+            if(stHttpRsp.incrementDecode(sBuffer))
+            {
+                delete []sTmpBuffer;
+                return TC_ClientSocket::EM_SUCCESS;
+            }
+            continue;
+        case TC_ClientSocket::EM_CLOSE:
+            delete []sTmpBuffer;
+            stHttpRsp.incrementDecode(sBuffer);
+            return TC_ClientSocket::EM_SUCCESS;
+        default:
+            delete []sTmpBuffer;
+            return iRet;
+        }
+    }
+
+    assert(true);
+
+    return 0;
+}
+
+void th_dohandle(int excut_num, int iSplit)
+{
+    tars::Int32 count = 0;
+    unsigned long sum = 0;
+    unsigned long id = 1;
+    int64_t _iTime = TC_TimeProvider::getInstance()->getNowMs();
+
+    TC_HttpRequest stHttpReq;
+    stHttpReq.setCacheControl("no-cache");
+
+    string sServer1("http://10.120.129.226:10024/");
+
+    TC_TCPClient tcpClient1;
+    tcpClient1.init("10.120.129.226", 10024, 3000);
+
+    int iRet = 0;
+
+    for (int i = 0; i<excut_num; i++)
+    {
+        try
+        {
+            TC_HttpResponse stHttpRsp;
+
+            stHttpReq.setGetRequest(sServer1);
+
+            iRet = doRequest(stHttpReq, tcpClient1, stHttpRsp, 3000);  //³¤Á´½Ó
+            
+            if (iRet == 0)
+            {
+                ++sum;
+                ++count;
+
+                if (excut_num == count)
+                {
+                    cout << "pthread id: " << pthread_self() << " | " << TC_TimeProvider::getInstance()->getNowMs() - _iTime <<"(ms)"<< endl;
+                    _iTime=TC_TimeProvider::getInstance()->getNowMs();
+                    count = 0;
+                }
+            }
+            else
+            {
+                 cout <<"pthread id: " << pthread_self()<< "|iRet:"<<iRet<<endl;
+            }
+        }
+        catch(TC_Exception &e)
+        {
+               cout << "pthread id: " << pthread_self() << " id: " << i << " exception: " << e.what() << endl;
+        }
+        catch(...)
+        {
+             cout << "pthread id: " << pthread_self() << " id: " << i << " unknown exception." << endl;
+        }
+        id += iSplit;
+    }
+    cout << "succ:" << sum <<endl;
+}
+
+int main(int argc,char ** argv)
+{
+    if(argc != 3 && argc != 4)
+    {
+        cout << "usage: " << argv[0] << " ThreadNum CallTimes Split" << endl;
+        return -1;
+    }
+
+    try
+    {
+        tars::Int32 threads = TC_Common::strto<tars::Int32>(string(argv[1]));
+        TC_ThreadPool tp;
+        tp.init(threads);
+        tp.start(); 
+        cout << "init tp succ" << endl;
+        tars::Int32 times = TC_Common::strto<tars::Int32>(string(argv[2]));
+ 
+        int iSplit = 1;
+        if(argc == 4)
+        {
+             iSplit = TC_Common::strto<tars::Int32>(string(argv[3]));
+        }
+        auto fwrapper3 = std::bind(&th_dohandle, times, iSplit);
+        for(int i = 0; i<threads; i++)
+        {
+            tp.exec(fwrapper3);
+            cout << "********************" <<endl;
+        }
+        tp.wait();
+    }catch(exception &e)
+    {
+        cout<<e.what()<<endl;
+    }
+    catch(...)
+    {
+
+    }
+
+    return 0;
+}

+ 16 - 0
examples/HttpDemo/HttpClient/makefile

@@ -0,0 +1,16 @@
+
+#-----------------------------------------------------------------------
+
+APP       := Test
+TARGET    := HttpClient 
+CONFIG    := 
+STRIP_FLAG:= N
+
+INCLUDE   += 
+LIB       += 
+
+
+#-----------------------------------------------------------------------
+
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 49 - 0
examples/HttpDemo/HttpServer/HttpImp.cpp

@@ -0,0 +1,49 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "HttpImp.h"
+#include "servant/Application.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////
+void HttpImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+
+//////////////////////////////////////////////////////
+void HttpImp::destroy()
+{
+    //destroy servant here:
+    //...
+}
+
+int HttpImp::doRequest(TarsCurrentPtr current, vector<char> &buffer)
+{
+    TC_HttpRequest request; 
+    vector<char> v = current->getRequestBuffer();
+    string sBuf;
+    sBuf.assign(&v[0],v.size());
+    request.decode(sBuf);
+    TC_HttpResponse rsp;
+    string s="hello";
+    rsp.setResponse(s.c_str(),s.size());
+    rsp.encode(buffer);
+   
+    return 0;
+}

+ 51 - 0
examples/HttpDemo/HttpServer/HttpImp.h

@@ -0,0 +1,51 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#ifndef _HttpImp_H_
+#define _HttpImp_H_
+
+#include "servant/Application.h"
+
+/**
+ *
+ *
+ */
+class HttpImp : public Servant
+{
+public:
+    /**
+     *
+     */
+    virtual ~HttpImp() {}
+
+    /**
+     *
+     */
+    virtual void initialize();
+
+    /**
+     *
+     */
+    virtual void destroy();
+
+    /**
+     *
+     */
+    int doRequest(TarsCurrentPtr current, vector<char> &buffer);
+
+};
+/////////////////////////////////////////////////////
+#endif

+ 98 - 0
examples/HttpDemo/HttpServer/HttpServer.cpp

@@ -0,0 +1,98 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "HttpServer.h"
+#include "HttpImp.h"
+
+using namespace std;
+
+HttpServer g_app;
+
+/////////////////////////////////////////////////////////////////
+struct HttpProtocol
+{
+    /**
+     * 解析http请求
+     * @param in
+     * @param out
+     *
+     * @return int
+     */
+    static int parseHttp(string &in, string &out)
+    {
+        try
+        {
+                        //判断请求是否是HTTP请求
+            bool b = TC_HttpRequest ::checkRequest(in.c_str(), in.length());
+                        //完整的HTTP请求
+            if(b)
+            {
+                out = in;
+                in  = "";
+                //TLOGDEBUG("out size: " << out.size() << endl);
+                return TC_EpollServer::PACKET_FULL;
+            }
+            else
+            {
+                return TC_EpollServer::PACKET_LESS;
+            }
+        }
+        catch(exception &ex)
+        {
+            return TC_EpollServer::PACKET_ERR;
+        }
+
+        return TC_EpollServer::PACKET_LESS;             //表示收到的包不完全
+    }
+
+};
+
+void
+HttpServer::initialize()
+{
+    //initialize application here:
+    //...
+
+    addServant<HttpImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".HttpObj");
+    addServantProtocol(ServerConfig::Application + "." + ServerConfig::ServerName + ".HttpObj",&HttpProtocol::parseHttp);
+}
+/////////////////////////////////////////////////////////////////
+void
+HttpServer::destroyApp()
+{
+    //destroy application here:
+    //...
+}
+/////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+/////////////////////////////////////////////////////////////////

+ 50 - 0
examples/HttpDemo/HttpServer/HttpServer.h

@@ -0,0 +1,50 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#ifndef _HttpServer_H_
+#define _HttpServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+
+using namespace tars;
+
+/**
+ *
+ **/
+class HttpServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~HttpServer() {};
+
+    /**
+     *
+     **/
+    virtual void initialize();
+
+    /**
+     *
+     **/
+    virtual void destroyApp();
+};
+
+extern HttpServer g_app;
+
+////////////////////////////////////////////
+#endif

+ 14 - 0
examples/HttpDemo/HttpServer/makefile

@@ -0,0 +1,14 @@
+
+#-----------------------------------------------------------------------
+
+APP       := TestApp
+TARGET    := HttpServer
+CONFIG    := 
+STRIP_FLAG:= N
+
+INCLUDE   += 
+LIB       += 
+
+#-----------------------------------------------------------------------i
+
+include /usr/local/tars/cpp/makefile/makefile.tars

+ 27 - 0
examples/PromiseDemo/AServer/AServant.tars

@@ -0,0 +1,27 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+module Test
+{
+
+interface AServant
+{
+    int queryResultSerial(string sIn, out string sOut);
+    
+    int queryResultParallel(string sIn, out string sOut);
+};
+
+}; 

+ 252 - 0
examples/PromiseDemo/AServer/AServantImp.cpp

@@ -0,0 +1,252 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "AServantImp.h"
+#include "AServer.h"
+#include "servant/Application.h"
+#include "servant/Communicator.h"
+
+using namespace std;
+using namespace tars;
+
+//////////////////////////////////////////////////////
+class BServantCallback : public BServantPrxCallback
+{
+
+public:
+    BServantCallback(TarsCurrentPtr &current)
+    : _current(current)
+    {}
+
+    BServantCallback(TarsCurrentPtr &current, const promise::Promise<std::string> &promise)
+    : _current(current)
+    , _promise(promise)
+    {}
+
+    void callback_queryResult(tars::Int32 ret, const std::string &sOut)
+    {
+        if(ret == 0)
+        {
+            _promise.setValue(sOut);
+        }
+        else
+        {
+            handExp("callback_queryResult", ret);
+        }
+    }
+    void callback_queryResult_exception(tars::Int32 ret)
+    {
+        handExp("callback_queryResult_exception", ret);
+    }
+
+private:
+    void handExp(const std::string &sFuncName, tars::Int32 ret)
+    {
+        string s("sFuncName:");
+        s += sFuncName;
+        s += "|ret:";
+        s += TC_Common::tostr(ret);
+
+        _promise.setException(promise::copyException(s));
+
+        TLOGDEBUG("ServerPrxCallback handExp:" << s << endl);
+    }
+
+private:
+
+    TarsCurrentPtr                    _current;
+    promise::Promise<std::string>    _promise;
+};
+//////////////////////////////////////////////////////
+class CServantCallback : public CServantPrxCallback
+{
+
+public:
+    CServantCallback(TarsCurrentPtr &current)
+    : _current(current)
+    {}
+
+    CServantCallback(TarsCurrentPtr &current, const promise::Promise<std::string> &promise)
+    : _current(current)
+    , _promise(promise)
+    {}
+
+    void callback_queryResult(tars::Int32 ret, const std::string &sOut)
+    {
+        if(ret == 0)
+        {
+            _promise.setValue(sOut);
+        }
+        else
+        {
+            handExp("callback_queryResult", ret);
+        }
+    }
+    void callback_queryResult_exception(tars::Int32 ret)
+    {
+        handExp("callback_queryResult_exception", ret);
+    }
+
+private:
+    void handExp(const std::string &sFuncName, tars::Int32 ret)
+    {
+        string s("sFuncName:");
+        s += sFuncName;
+        s += "|ret:";
+        s += TC_Common::tostr(ret);
+
+        _promise.setException(promise::copyException(s));
+
+        TLOGDEBUG("ServerPrxCallback handExp:" << s << endl);
+    }
+
+private:
+
+    TarsCurrentPtr                    _current;
+    promise::Promise<std::string>    _promise;
+};
+//////////////////////////////////////////////////////
+promise::Future<std::string> sendBReq(BServantPrx prx, const std::string& sIn, tars::TarsCurrentPtr current)
+{
+    promise::Promise<std::string> promise;
+
+    Test::BServantPrxCallbackPtr cb = new BServantCallback(current, promise);
+
+    prx->async_queryResult(cb, sIn);
+
+    return promise.getFuture();
+}
+//////////////////////////////////////////////////////
+promise::Future<std::string> sendCReq(CServantPrx prx, const std::string& sIn, tars::TarsCurrentPtr current)
+{
+    promise::Promise<std::string> promise;
+
+    Test::CServantPrxCallbackPtr cb = new CServantCallback(current, promise);
+
+    prx->async_queryResult(cb, sIn);
+
+    return promise.getFuture();
+}
+//////////////////////////////////////////////////////
+promise::Future<std::string> handleBRspAndSendCReq(CServantPrx prx, TarsCurrentPtr current, const promise::Future<std::string>& future)
+{
+    std::string sResult("");
+    std::string sException("");
+    try 
+    {
+        sResult = future.get();
+
+        return sendCReq(prx, sResult, current);
+    } 
+    catch (exception& e) 
+    {
+        TLOGDEBUG("Exception:" << e.what() << endl);
+        sException = e.what();
+    }
+
+    promise::Promise<std::string> promise;
+    promise.setValue(sException);
+
+    return promise.getFuture();
+}
+//////////////////////////////////////////////////////
+int handleCRspAndReturnClient(TarsCurrentPtr current, const promise::Future<std::string>& future)
+{
+    int ret = 0;
+    std::string sResult("");
+    try 
+    {
+        sResult = future.get();
+    } 
+    catch (exception& e) 
+    {
+        ret = -1;
+        sResult = e.what();
+
+        TLOGDEBUG("Exception:" << e.what() << endl);
+    }
+
+    AServant::async_response_queryResultSerial(current, ret, sResult);
+
+    return 0;
+}
+//////////////////////////////////////////////////////
+int handleBCRspAndReturnClient(TarsCurrentPtr current, const promise::Future<promise::Tuple<promise::Future<std::string>, promise::Future<std::string> > >& allFuture)
+{
+    int ret = 0;
+    std::string sResult("");
+    try 
+    {
+        promise::Tuple<promise::Future<std::string>, promise::Future<std::string> > tupleFuture = allFuture.get();
+
+        std::string sResult1 = tupleFuture.get<0>().get();
+        std::string sResult2 = tupleFuture.get<1>().get();
+
+        sResult = sResult1;
+        sResult += "|";
+        sResult += sResult2;
+    } 
+    catch (exception& e) 
+    {
+        ret = -1;
+        sResult = e.what();
+
+        TLOGDEBUG("Exception:" << e.what() << endl);
+    }
+
+    AServant::async_response_queryResultParallel(current, ret, sResult);
+
+    return 0;
+}
+//////////////////////////////////////////////////////
+void AServantImp::initialize()
+{
+    //initialize servant here:
+    //...
+    _pPrxB = Application::getCommunicator()->stringToProxy<BServantPrx>("Test.BServer.BServantObj");
+    _pPrxC = Application::getCommunicator()->stringToProxy<CServantPrx>("Test.CServer.CServantObj");
+}
+//////////////////////////////////////////////////////
+void AServantImp::destroy()
+{
+}
+//////////////////////////////////////////////////////
+tars::Int32 AServantImp::queryResultSerial(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current)
+{
+    current->setResponse(false);
+
+    promise::Future<std::string> f = sendBReq(_pPrxB, sIn, current);
+
+    f.then(tars::TC_Bind(&handleBRspAndSendCReq, _pPrxC, current)).then(tars::TC_Bind(&handleCRspAndReturnClient, current));
+
+    return 0;
+}
+//////////////////////////////////////////////////////
+tars::Int32 AServantImp::queryResultParallel(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current)
+{
+    current->setResponse(false);
+
+    promise::Future<std::string> f1 = sendBReq(_pPrxB, sIn, current);
+
+    promise::Future<std::string> f2 = sendCReq(_pPrxC, sIn, current);
+
+    promise::Future<promise::Tuple<promise::Future<std::string>, promise::Future<std::string> > > f_all = promise::whenAll(f1, f2);
+
+    f_all.then(tars::TC_Bind(&handleBCRspAndReturnClient, current));
+
+    return 0;
+}
+

+ 63 - 0
examples/PromiseDemo/AServer/AServantImp.h

@@ -0,0 +1,63 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#ifndef _BServantImp_H_
+#define _BServantImp_H_
+
+#include "servant/Application.h"
+#include "AServant.h"
+#include "BServant.h"
+#include "CServant.h"
+#include "promise/promise.h"
+//#include "promise/tuple.h"
+
+#include "promise/when_all.h"
+
+using namespace Test;
+
+///////////////////////////////////
+promise::Future<std::string> sendBReq(BServantPrx prx, const std::string& sIn, tars::TarsCurrentPtr current);
+
+promise::Future<std::string> handleBRspAndSendCReq(CServantPrx prx, TarsCurrentPtr current, const promise::Future<std::string>& future);
+
+promise::Future<std::string> sendCReq(CServantPrx prx, const std::string& sIn, tars::TarsCurrentPtr current);
+
+int handleCRspAndReturnClient(TarsCurrentPtr current, const promise::Future<std::string>& future);
+
+///////////////////////////////////
+int handleBCRspAndReturnClient(TarsCurrentPtr current, const promise::Future<promise::Tuple<promise::Future<std::string>, promise::Future<std::string> > >& allFuture);
+
+///////////////////////////////////
+class AServantImp : public Test::AServant
+{
+public:
+
+    virtual ~AServantImp() {}
+
+    virtual void initialize();
+
+    virtual void destroy();
+
+    tars::Int32 queryResultSerial(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current);
+
+    tars::Int32 queryResultParallel(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current);
+
+private:
+    BServantPrx _pPrxB;
+    CServantPrx _pPrxC;
+};
+/////////////////////////////////////////////////////
+#endif

+ 57 - 0
examples/PromiseDemo/AServer/AServer.cpp

@@ -0,0 +1,57 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "AServer.h"
+#include "AServantImp.h"
+
+using namespace std;
+
+AServer g_app;
+
+/////////////////////////////////////////////////////////////////
+void AServer::initialize()
+{
+    //initialize application here:
+    //... 
+
+    addServant<AServantImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".AServantObj");
+}
+/////////////////////////////////////////////////////////////////
+void AServer::destroyApp()
+{
+    //destroy application here:
+    //...
+}
+
+/////////////////////////////////////////////////////////////////
+int main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+/////////////////////////////////////////////////////////////////

+ 52 - 0
examples/PromiseDemo/AServer/AServer.h

@@ -0,0 +1,52 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#ifndef _BServer_H_
+#define _BServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+
+using namespace tars;
+
+/**
+ *
+ **/
+class AServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~AServer() {};
+
+    /**
+     *
+     **/
+    virtual void initialize();
+
+    /**
+     *
+     **/
+    virtual void destroyApp();
+protected:
+    bool cmdprofile(const string& command, const string& params, string& result);
+};
+
+extern AServer g_app;
+
+////////////////////////////////////////////
+#endif

+ 25 - 0
examples/PromiseDemo/AServer/BServant.tars

@@ -0,0 +1,25 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+module Test
+{
+
+interface BServant
+{
+    int queryResult(string sIn, out string sOut);
+};
+
+}; 

+ 25 - 0
examples/PromiseDemo/AServer/CServant.tars

@@ -0,0 +1,25 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+module Test
+{
+
+interface CServant
+{
+    int queryResult(string sIn, out string sOut);
+};
+
+}; 

+ 12 - 0
examples/PromiseDemo/AServer/makefile

@@ -0,0 +1,12 @@
+
+#-----------------------------------------------------------------------
+APP       := Test
+TARGET    := AServer
+CONFIG    := 
+STRIP_FLAG:= N
+
+INCLUDE   +=
+
+#-----------------------------------------------------------------------
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 25 - 0
examples/PromiseDemo/BServer/BServant.tars

@@ -0,0 +1,25 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+module Test
+{
+
+interface BServant
+{
+    int queryResult(string sIn, out string sOut);
+};
+
+}; 

+ 45 - 0
examples/PromiseDemo/BServer/BServantImp.cpp

@@ -0,0 +1,45 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "BServantImp.h"
+#include "BServer.h"
+#include "servant/Application.h"
+#include "servant/Communicator.h"
+
+using namespace std;
+using namespace tars;
+
+//////////////////////////////////////////////////////
+void BServantImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+//////////////////////////////////////////////////////
+void BServantImp::destroy()
+{
+}
+//////////////////////////////////////////////////////
+tars::Int32 BServantImp::queryResult(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current)
+{
+    sOut = "[sResult:";
+    sOut += sIn;
+    sOut += "]";
+
+    return 0;
+}
+
+

+ 40 - 0
examples/PromiseDemo/BServer/BServantImp.h

@@ -0,0 +1,40 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#ifndef _BServantImp_H_
+#define _BServantImp_H_
+
+#include "servant/Application.h"
+#include "BServant.h"
+#include "promise/promise.h"
+
+using namespace Test;
+
+class BServantImp : public Test::BServant
+{
+public:
+
+    virtual ~BServantImp() {}
+
+    virtual void initialize();
+
+    virtual void destroy();
+
+    tars::Int32 queryResult(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current);
+
+};
+/////////////////////////////////////////////////////
+#endif

+ 57 - 0
examples/PromiseDemo/BServer/BServer.cpp

@@ -0,0 +1,57 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "BServer.h"
+#include "BServantImp.h"
+
+using namespace std;
+
+BServer g_app;
+
+/////////////////////////////////////////////////////////////////
+void BServer::initialize()
+{
+    //initialize application here:
+    //... 
+
+    addServant<BServantImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".BServantObj");
+}
+/////////////////////////////////////////////////////////////////
+void BServer::destroyApp()
+{
+    //destroy application here:
+    //...
+}
+
+/////////////////////////////////////////////////////////////////
+int main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+/////////////////////////////////////////////////////////////////

+ 52 - 0
examples/PromiseDemo/BServer/BServer.h

@@ -0,0 +1,52 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#ifndef _BServer_H_
+#define _BServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+
+using namespace tars;
+
+/**
+ *
+ **/
+class BServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~BServer() {};
+
+    /**
+     *
+     **/
+    virtual void initialize();
+
+    /**
+     *
+     **/
+    virtual void destroyApp();
+protected:
+    bool cmdprofile(const string& command, const string& params, string& result);
+};
+
+extern BServer g_app;
+
+////////////////////////////////////////////
+#endif

+ 11 - 0
examples/PromiseDemo/BServer/makefile

@@ -0,0 +1,11 @@
+#-----------------------------------------------------------------------
+
+APP       := Test
+TARGET    := BServer
+CONFIG    := 
+STRIP_FLAG:= N
+INCLUDE   +=
+
+#-----------------------------------------------------------------------
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 25 - 0
examples/PromiseDemo/CServer/CServant.tars

@@ -0,0 +1,25 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+module Test
+{
+
+interface CServant
+{
+    int queryResult(string sIn, out string sOut);
+};
+
+}; 

+ 45 - 0
examples/PromiseDemo/CServer/CServantImp.cpp

@@ -0,0 +1,45 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "CServantImp.h"
+#include "CServer.h"
+#include "servant/Application.h"
+#include "servant/Communicator.h"
+
+using namespace std;
+using namespace tars;
+
+//////////////////////////////////////////////////////
+void CServantImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+//////////////////////////////////////////////////////
+void CServantImp::destroy()
+{
+}
+//////////////////////////////////////////////////////
+tars::Int32 CServantImp::queryResult(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current)
+{
+    sOut = "[sResult:";
+    sOut += sIn;
+    sOut += "]";
+
+    return 0;
+}
+
+

+ 40 - 0
examples/PromiseDemo/CServer/CServantImp.h

@@ -0,0 +1,40 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#ifndef _BServantImp_H_
+#define _BServantImp_H_
+
+#include "servant/Application.h"
+#include "CServant.h"
+#include "promise/promise.h"
+
+using namespace Test;
+
+class CServantImp : public Test::CServant
+{
+public:
+
+    virtual ~CServantImp() {}
+
+    virtual void initialize();
+
+    virtual void destroy();
+
+    tars::Int32 queryResult(const std::string& sIn, std::string &sOut, tars::TarsCurrentPtr current);
+
+};
+/////////////////////////////////////////////////////
+#endif

+ 57 - 0
examples/PromiseDemo/CServer/CServer.cpp

@@ -0,0 +1,57 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "CServer.h"
+#include "CServantImp.h"
+
+using namespace std;
+
+CServer g_app;
+
+/////////////////////////////////////////////////////////////////
+void CServer::initialize()
+{
+    //initialize application here:
+    //... 
+
+    addServant<CServantImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".CServantObj");
+}
+/////////////////////////////////////////////////////////////////
+void CServer::destroyApp()
+{
+    //destroy application here:
+    //...
+}
+
+/////////////////////////////////////////////////////////////////
+int main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+/////////////////////////////////////////////////////////////////

+ 53 - 0
examples/PromiseDemo/CServer/CServer.h

@@ -0,0 +1,53 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#ifndef _BServer_H_
+#define _BServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+
+using namespace tars;
+
+/**
+ *  *
+ *   **/
+class CServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~CServer() {};
+
+    /**
+     *
+     **/
+    virtual void initialize();
+
+    /**
+     *
+     **/
+    virtual void destroyApp();
+protected:
+    bool cmdprofile(const string& command, const string& params, string& result);
+};
+
+extern CServer g_app;
+
+////////////////////////////////////////////
+#endif
+

+ 11 - 0
examples/PromiseDemo/CServer/makefile

@@ -0,0 +1,11 @@
+#-----------------------------------------------------------------------
+APP       := Test
+TARGET    := CServer
+CONFIG    := 
+STRIP_FLAG:= N 
+
+INCLUDE   +=
+
+#-----------------------------------------------------------------------
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 138 - 0
examples/PromiseDemo/Client/main.cpp

@@ -0,0 +1,138 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "AServant.h"
+#include "servant/Communicator.h"
+#include "util/tc_thread_pool.h"
+#include <iostream>
+
+using namespace std;
+using namespace Test;
+using namespace tars;
+
+class Test1
+{
+public:
+    Test1(const string &sStr);
+
+    ~Test1();
+
+    void  queryResult(int iFlag, int iExecuteNum);
+
+private:
+    Communicator    _comm;
+    AServantPrx        prx;
+};
+
+Test1::Test1(const string &sStr)
+{
+    _comm.setProperty("locator", "tars.tarsregistry.QueryObj@    tcp -h 10.208.139.242 -p 17890 -t 10000 ");
+    _comm.stringToProxy(sStr, prx);
+}
+
+Test1::~Test1()
+{
+    
+}
+
+void Test1::queryResult(int iFlag, int iExecuteNum)
+{
+    string sIn(10,'a');
+    string sOut("");
+
+    tars::Int32 count = 0;
+    unsigned long sum = 0;
+
+    time_t _iTime=TC_TimeProvider::getInstance()->getNowMs();
+
+    for(int i=0; i<iExecuteNum; i++) 
+    {
+        sOut = "";
+        try
+        {
+            int ret = -1;
+            if(iFlag == 0)
+            {
+                ret = prx->queryResultSerial(sIn, sOut);
+            }
+            else
+            {
+                ret = prx->queryResultParallel(sIn, sOut);
+            }
+
+            if(ret == 0)
+            {
+                ++sum;
+                ++count;
+                if(count == iExecuteNum)
+                {
+                    cout << "pthread id: " << pthread_self() << " | " << TC_TimeProvider::getInstance()->getNowMs() - _iTime << endl;
+                    _iTime=TC_TimeProvider::getInstance()->getNowMs();
+                    count = 0;
+                }
+            }
+        }
+        catch(TC_Exception &e)
+        {
+            cout << "pthread id: " << pthread_self() << "id: " << i << "exception: " << e.what() << endl;
+        }
+        catch(...)
+        {
+            cout << "pthread id: " << pthread_self() << "id: " << i << "unknown exception." << endl;
+        }
+    }
+    cout << "succ:" << sum << endl;
+    cout << "sOut:" << sOut << endl;
+}
+
+int main(int argc,char ** argv)
+{
+    if(argc != 5)
+    {
+        cout << "usage: " << argv[0] << " sObj ThreadNum CallTimes  CallMode" << endl;
+        return -1;
+    }
+
+    string s = string(argv[1]);
+
+    Test1 test1(s);
+    try
+    {
+        tars::Int32 threads = TC_Common::strto<tars::Int32>(string(argv[2]));
+        TC_ThreadPool tp;
+        tp.init(threads);
+        tp.start();
+        tars::Int32 times = TC_Common::strto<tars::Int32>(string(argv[3]));
+        tars::Int32 callMode = TC_Common::strto<tars::Int32>(string(argv[4]));
+        
+        for(int i = 0; i<threads; i++) 
+        {
+            auto fw = std::bind(&Test1::queryResult, &test1, callMode, times);
+            tp.exec(fw);
+            cout << "********************" <<endl;
+        }
+        tp.waitForAllDone(); 
+    }catch(exception &e)
+    {
+        cout<<e.what()<<endl;
+    }
+    catch(...)
+    {
+        
+    }
+    
+    return 0;
+}

+ 13 - 0
examples/PromiseDemo/Client/makefile

@@ -0,0 +1,13 @@
+
+#-----------------------------------------------------------------------
+APP       := Test
+TARGET    := myClientPromise
+CONFIG    := 
+STRIP_FLAG:= N
+
+INCLUDE   +=
+
+#-----------------------------------------------------------------------
+include /home/tarsproto/Test/AServer/AServer.mk
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 6 - 0
examples/PromiseDemo/README.md

@@ -0,0 +1,6 @@
+该工程是Tars promise编程示例的代码
+
+
+目录名称 |功能
+-----------------|----------------
+AServer   |   promise编程的示例程序,用promsie方式去并行和串行访问BServer和CServer

+ 13 - 0
examples/PushDemo/PushClient/Makefile

@@ -0,0 +1,13 @@
+APP          := Test
+TARGET       := TestPushClient
+MFLAGS       :=
+CONFIG       := 
+STRIP_FLAG   := N
+TARS2CPP_FLAG:= 
+
+INCLUDE      += 
+LIB          += 
+
+#-----------------------------------------------------------------------
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 162 - 0
examples/PushDemo/PushClient/TestRecvThread.cpp

@@ -0,0 +1,162 @@
+#include "TestRecvThread.h"
+#include <iostream>
+#include <arpa/inet.h>
+
+/*
+ 响应包解码函数,根据特定格式解码从服务端收到的数据,解析为ResponsePacket
+*/
+static size_t pushResponse(const char* recvBuffer, size_t length, list<ResponsePacket>& done)
+{
+	size_t pos = 0;
+    while (pos < length)
+    {
+        unsigned int len = length - pos;
+        if(len < sizeof(unsigned int))
+        {
+            break;
+        }
+
+        unsigned int iHeaderLen = ntohl(*(unsigned int*)(recvBuffer + pos));
+
+        //做一下保护,长度大于M
+        if (iHeaderLen > 100000 || iHeaderLen < sizeof(unsigned int))
+        {
+            throw TarsDecodeException("packet length too long or too short,len:" + TC_Common::tostr(iHeaderLen));
+        }
+
+        //包没有接收全
+        if (len < iHeaderLen)
+        {
+            break;
+        }
+        else
+        {
+            ResponsePacket rsp;
+			rsp.iRequestId = ntohl(*((unsigned int *)(recvBuffer + pos + sizeof(unsigned int))));
+			rsp.sBuffer.resize(iHeaderLen - 2*sizeof(unsigned int));
+		  ::memcpy(&rsp.sBuffer[0], recvBuffer + pos + 2*sizeof(unsigned int), iHeaderLen - 2*sizeof(unsigned int));
+
+			pos += iHeaderLen;
+
+            done.push_back(rsp);
+        }
+    }
+
+    return pos;
+}
+/*
+   请求包编码函数,本函数的打包格式为
+   整个包长度(字节)+iRequestId(字节)+包内容
+*/
+static void pushRequest(const RequestPacket& request, string& buff)
+{
+    unsigned int net_bufflength = htonl(request.sBuffer.size()+8);
+    unsigned char * bufflengthptr = (unsigned char*)(&net_bufflength);
+
+    buff = "";
+    for (int i = 0; i<4; ++i)
+    {
+        buff += *bufflengthptr++;
+    }
+
+    unsigned int netrequestId = htonl(request.iRequestId);
+    unsigned char * netrequestIdptr = (unsigned char*)(&netrequestId);
+
+    for (int i = 0; i<4; ++i)
+    {
+        buff += *netrequestIdptr++;
+    }
+
+    string tmp;
+    tmp.assign((const char*)(&request.sBuffer[0]), request.sBuffer.size());
+    buff+=tmp;
+}
+
+static void printResult(int iRequestId, const string &sResponseStr)
+{
+	cout << "request id: " << iRequestId << endl;
+	cout << "response str: " << sResponseStr << endl;
+}
+static void printPushInfo(const string &sResponseStr)
+{
+	cout << "push message: " << sResponseStr << endl;
+}
+
+int TestPushCallBack::onDispatch(ReqMessagePtr msg)
+{
+	if(msg->request.sFuncName == "printResult")
+	{
+		string sRet;
+		cout << "sBuffer: " << msg->response.sBuffer.size() << endl;
+		sRet.assign(&(msg->response.sBuffer[0]), msg->response.sBuffer.size());
+		printResult(msg->request.iRequestId, sRet);
+		return 0;
+	}
+	else if(msg->response.iRequestId == 0)
+	{
+		string sRet;
+		sRet.assign(&(msg->response.sBuffer[0]), msg->response.sBuffer.size());
+		printPushInfo(sRet);
+		return 0;
+	}
+	else
+	{
+		cout << "no match func!" <<endl;
+	}
+	return -3;
+}
+
+RecvThread::RecvThread():_bTerminate(false)
+{
+	string sObjName = "Test.TestPushServer.TestPushServantObj";
+    string sObjHost = "tcp -h 10.120.129.226 -t 60000 -p 10099";
+
+    _prx = _comm.stringToProxy<ServantPrx>(sObjName+"@"+sObjHost);
+
+	ProxyProtocol prot;
+    prot.requestFunc = pushRequest;
+    prot.responseFunc = pushResponse;
+
+    _prx->tars_set_protocol(prot);
+}
+
+void RecvThread::terminate()
+{
+	_bTerminate = true;
+	{
+	    tars::TC_ThreadLock::Lock sync(*this);
+	    notifyAll();
+	}
+}
+
+void RecvThread::run(void)
+{
+	TestPushCallBackPtr cbPush = new TestPushCallBack();
+	_prx->tars_set_push_callback(cbPush);	
+
+	string buf("heartbeat");
+
+	while(!_bTerminate)
+	{
+		{
+			try
+			{
+				TestPushCallBackPtr cb = new TestPushCallBack();
+				_prx->rpc_call_async(_prx->tars_gen_requestid(), "printResult", buf.c_str(), buf.length(), cb);
+			}
+			catch(TarsException& e)
+			{     
+				cout << "TarsException: " << e.what() << endl;
+			}
+			catch(...)
+			{
+				cout << "unknown exception" << endl;
+			}
+		}
+
+		{
+            TC_ThreadLock::Lock sync(*this);
+            timedWait(5000);
+		}
+	}
+}

+ 28 - 0
examples/PushDemo/PushClient/TestRecvThread.h

@@ -0,0 +1,28 @@
+#ifndef __TEST_RECV_THREAD_H
+#define __TEST_RECV_THREAD_H
+
+#include "servant/Application.h"
+
+class TestPushCallBack : public ServantProxyCallback
+{
+public:
+	virtual int onDispatch(ReqMessagePtr msg);
+};
+typedef tars::TC_AutoPtr<TestPushCallBack> TestPushCallBackPtr;
+
+class RecvThread : public TC_Thread, public TC_ThreadLock
+{
+public:
+	RecvThread();
+
+	virtual void run();
+
+	void terminate();
+private:
+	bool _bTerminate;
+
+	Communicator _comm;
+
+	ServantPrx  _prx;
+};
+#endif

+ 30 - 0
examples/PushDemo/PushClient/main.cpp

@@ -0,0 +1,30 @@
+#include "servant/Application.h"
+#include "TestRecvThread.h"
+#include <iostream>
+
+using namespace std;
+using namespace tars;
+
+int main(int argc,char**argv)
+{
+    try
+    {
+		RecvThread thread;
+		thread.start();
+
+		int c;
+		while((c = getchar()) != 'q');
+
+		thread.terminate();
+		thread.getThreadControl().join();
+    }
+    catch(std::exception&e)
+    {
+        cerr<<"std::exception:"<<e.what()<<endl;
+    }
+    catch(...)
+    {
+        cerr<<"unknown exception"<<endl;
+    }
+    return 0;
+}

+ 55 - 0
examples/PushDemo/PushServer/TestPushServantImp.cpp

@@ -0,0 +1,55 @@
+#include "TestPushServantImp.h"
+#include "servant/Application.h"
+#include "TestPushThread.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////
+void TestPushServantImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+
+//////////////////////////////////////////////////////
+void TestPushServantImp::destroy()
+{
+    //destroy servant here:
+    //...
+}
+
+
+int TestPushServantImp::doRequest(tars::TarsCurrentPtr current, vector<char>& response)
+{
+	//保存客户端的信息,以便对客户端进行push消息
+	(PushUser::mapMutex).lock();
+	map<string, TarsCurrentPtr>::iterator it = PushUser::pushUser.find(current->getIp());
+	if(it == PushUser::pushUser.end())
+	{
+		PushUser::pushUser.insert(map<string, TarsCurrentPtr>::value_type(current->getIp(), current));
+		LOG->debug() << "connect ip: " << current->getIp() << endl;
+	}
+	(PushUser::mapMutex).unlock();
+	//返回给客户端它自己请求的数据包,即原包返回
+	const vector<char>& request = current->getRequestBuffer();
+	response = request;
+
+	return 0;
+}
+//客户端关闭到服务端的连接,或者服务端发现客户端长时间未发送包过来,然后超过60s就关闭连接
+//调用的方法
+int TestPushServantImp::doClose(TarsCurrentPtr current)
+{
+	(PushUser::mapMutex).lock();
+	map<string, TarsCurrentPtr>::iterator it = PushUser::pushUser.find(current->getIp());
+	if(it != PushUser::pushUser.end())
+	{
+		PushUser::pushUser.erase(it);
+		LOG->debug() << "close ip: " << current->getIp() << endl;
+	}
+	(PushUser::mapMutex).unlock();
+
+	return 0;
+}
+
+

+ 43 - 0
examples/PushDemo/PushServer/TestPushServantImp.h

@@ -0,0 +1,43 @@
+#ifndef _TestPushServantImp_H_
+#define _TestPushServantImp_H_
+
+#include "servant/Application.h"
+//#include "TestPushServant.h"
+
+/**
+ *
+ *
+ */
+class TestPushServantImp : public  tars::Servant
+{
+public:
+    /**
+     *
+     */
+    virtual ~TestPushServantImp() {}
+
+    /**
+     *
+     */
+    virtual void initialize();
+
+    /**
+     *
+     */
+    virtual void destroy();
+
+    /**
+     *
+     */
+    virtual int test(tars::TarsCurrentPtr current) { return 0;};
+
+
+    //重载Servant的doRequest方法
+    int doRequest(tars::TarsCurrentPtr current, vector<char>& response);
+
+    //重载Servant的doClose方法
+    int doClose(tars::TarsCurrentPtr current);
+
+};
+/////////////////////////////////////////////////////
+#endif

+ 83 - 0
examples/PushDemo/PushServer/TestPushServer.cpp

@@ -0,0 +1,83 @@
+#include "TestPushServer.h"
+#include "TestPushServantImp.h"
+
+using namespace std;
+
+TestPushServer g_app;
+
+/////////////////////////////////////////////////////////////////
+
+static int parse(string &in, string &out)
+{
+    if(in.length() < sizeof(unsigned int))
+    {
+        return TC_EpollServer::PACKET_LESS;
+    }
+
+    unsigned int iHeaderLen;
+
+    memcpy(&iHeaderLen, in.c_str(), sizeof(unsigned int));
+
+    iHeaderLen = ntohl(iHeaderLen);
+
+    if(iHeaderLen < (unsigned int)(sizeof(unsigned int))|| iHeaderLen > 1000000)
+    {
+        return TC_EpollServer::PACKET_ERR;
+    }
+
+    if((unsigned int)in.length() < iHeaderLen)
+    {
+        return TC_EpollServer::PACKET_LESS;
+    }
+
+    out = in.substr(0, iHeaderLen);
+
+    in  = in.substr(iHeaderLen);
+
+    return TC_EpollServer::PACKET_FULL;
+}
+
+
+void
+TestPushServer::initialize()
+{
+    //initialize application here:
+    //...
+
+    addServant<TestPushServantImp>(ServerConfig::Application + "." + ServerConfig::ServerName + ".TestPushServantObj");
+
+    addServantProtocol("Test.TestPushServer.TestPushServantObj", parse);
+
+    pushThread.start();
+
+}
+/////////////////////////////////////////////////////////////////
+void
+TestPushServer::destroyApp()
+{
+    //destroy application here:
+    //...
+    pushThread.terminate();
+    pushThread.getThreadControl().join();
+
+}
+/////////////////////////////////////////////////////////////////
+int
+main(int argc, char* argv[])
+{
+    try
+    {
+        g_app.main(argc, argv);
+        g_app.waitForShutdown();
+    }
+    catch (std::exception& e)
+    {
+        cerr << "std::exception:" << e.what() << std::endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << std::endl;
+    }
+    return -1;
+}
+/////////////////////////////////////////////////////////////////

+ 41 - 0
examples/PushDemo/PushServer/TestPushServer.h

@@ -0,0 +1,41 @@
+#ifndef _TestPushServer_H_
+#define _TestPushServer_H_
+
+#include <iostream>
+#include "servant/Application.h"
+#include "TestPushThread.h"
+
+
+using namespace tars;
+
+/**
+ *
+ **/
+class TestPushServer : public Application
+{
+public:
+    /**
+     *
+     **/
+    virtual ~TestPushServer() {};
+
+    /**
+     *
+     **/
+    virtual void initialize();
+
+    /**
+     *
+     **/
+    virtual void destroyApp();
+
+    private:
+    //用于push消息的线程
+    PushInfoThread  pushThread;
+
+};
+
+extern TestPushServer g_app;
+
+////////////////////////////////////////////
+#endif

+ 67 - 0
examples/PushDemo/PushServer/TestPushThread.cpp

@@ -0,0 +1,67 @@
+#include "TestPushThread.h"
+#include <arpa/inet.h>
+
+map<string, TarsCurrentPtr> PushUser::pushUser;
+TC_ThreadMutex PushUser::mapMutex;
+
+
+void PushInfoThread::terminate(void)
+{
+	_bTerminate = true;
+	{
+	    tars::TC_ThreadLock::Lock sync(*this);
+	    notifyAll();
+	}
+}
+
+void PushInfoThread::setPushInfo(const string &sInfo)
+{
+    unsigned int iBuffLength = htonl(sInfo.size()+8);
+    unsigned char * pBuff = (unsigned char*)(&iBuffLength);
+
+    _sPushInfo = "";
+    for (int i = 0; i<4; ++i)
+    {
+        _sPushInfo += *pBuff++;
+    }
+
+    unsigned int iRequestId = htonl(_iId);
+    unsigned char * pRequestId = (unsigned char*)(&iRequestId);
+
+    for (int i = 0; i<4; ++i)
+    {
+        _sPushInfo += *pRequestId++;
+    }
+
+    _sPushInfo += sInfo;
+}
+//定期向客户push消息
+void PushInfoThread::run(void)
+{
+	time_t iNow;
+
+	setPushInfo("hello world");
+
+	while (!_bTerminate)
+	{
+		iNow =  TC_TimeProvider::getInstance()->getNow();
+
+		if(iNow - _tLastPushTime > _tInterval)
+		{
+			_tLastPushTime = iNow;
+
+			(PushUser::mapMutex).lock();
+			for(map<string, TarsCurrentPtr>::iterator it = (PushUser::pushUser).begin(); it != (PushUser::pushUser).end(); ++it)
+			{
+				(it->second)->sendResponse(_sPushInfo.c_str(), _sPushInfo.size());
+				LOG->debug() << "sendResponse: " << _sPushInfo.size() <<endl;
+			}
+			(PushUser::mapMutex).unlock();
+		}
+
+		{
+            TC_ThreadLock::Lock sync(*this);
+            timedWait(1000);
+		}
+	}
+}

+ 31 - 0
examples/PushDemo/PushServer/TestPushThread.h

@@ -0,0 +1,31 @@
+#ifndef __TEST_PUSH_THREAD_H
+#define __TEST_PUSH_THREAD_H
+
+#include "servant/Application.h"
+
+class PushUser
+{
+public:
+	static map<string, TarsCurrentPtr> pushUser;
+	static TC_ThreadMutex mapMutex;
+};
+
+class PushInfoThread : public TC_Thread, public TC_ThreadLock
+{
+public:
+	PushInfoThread():_bTerminate(false),_tLastPushTime(0),_tInterval(10),_iId(0){}
+
+	virtual void run();
+
+	void terminate();
+
+	void setPushInfo(const string &sInfo);
+
+private:
+	bool _bTerminate;
+	time_t _tLastPushTime;
+	time_t _tInterval;
+	unsigned int _iId;
+	string _sPushInfo;
+};
+#endif

+ 17 - 0
examples/PushDemo/PushServer/makefile

@@ -0,0 +1,17 @@
+
+#-----------------------------------------------------------------------
+
+APP          := Test
+TARGET       := TestPushServer
+CONFIG       := 
+STRIP_FLAG   := N
+TARS2CPP_FLAG:= 
+
+INCLUDE      += 
+LIB          += 
+
+#-----------------------------------------------------------------------
+
+include /usr/local/tars/cpp/makefile/makefile.tars
+
+#-----------------------------------------------------------------------

+ 7 - 0
examples/PushDemo/README.md

@@ -0,0 +1,7 @@
+该工程是Tars快速入门示例的代码
+
+
+目录名称 |功能
+-----------------|----------------
+HelloServer      |   开发快速入门的示例
+ProxyServer      |   中转代理服务示例,作为HelloServer的代理服务

+ 80 - 0
examples/QuickStartDemo/HelloServer/AsyncClient/main.cpp

@@ -0,0 +1,80 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include <iostream>
+#include "servant/Communicator.h"
+#include "Hello.h"
+
+using namespace std;
+using namespace TestApp;
+using namespace tars;
+
+class HelloCallBack : public HelloPrxCallback
+{
+public:
+    HelloCallBack(){}
+
+    virtual ~HelloCallBack(){}
+
+    virtual void callback_testHello(tars::Int32 ret,  const std::string& sRsp)
+    {
+        cout<<"callback_testHello ret:"<< ret << "|sRsp:" << sRsp <<endl; 
+    }
+
+    virtual void callback_testHello_exception(tars::Int32 ret)
+    {
+        cout<<"callback_testHello_exception ret:"<< ret <<endl;
+    }
+};
+
+int main(int argc,char ** argv)
+{
+    Communicator comm;
+
+    try
+    {
+        HelloPrx prx;
+        comm.stringToProxy("TestApp.HelloServer.HelloObj@tcp -h 10.120.129.226 -p 20001" , prx);
+
+        try
+        {
+            string sReq("hello world");
+            HelloPrxCallbackPtr cb = new HelloCallBack();
+            prx->async_testHello(cb, sReq);
+            cout<<" sReq:"<<sReq<<endl;
+        }
+        catch(exception &ex)
+        {
+            cerr<<"ex:"<<ex.what() <<endl;
+        }
+        catch(...)
+        {
+            cerr<<"unknown exception."<<endl;
+        }
+    }
+    catch(exception& e)
+    {
+        cerr<<"exception:"<<e.what() <<endl;
+    }
+    catch (...)
+    {
+        cerr<<"unknown exception."<<endl;
+    }
+
+    getchar();
+
+    return 0;
+}

+ 16 - 0
examples/QuickStartDemo/HelloServer/AsyncClient/makefile

@@ -0,0 +1,16 @@
+
+#-----------------------------------------------------------------------
+
+APP       := TestApp
+TARGET    := TestHelloServer
+CONFIG    := 
+STRIP_FLAG:= N
+
+INCLUDE   += 
+LIB       += 
+
+#-----------------------------------------------------------------------
+
+include /home/tarsproto/TestApp/HelloServer/HelloServer.mk
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 62 - 0
examples/QuickStartDemo/HelloServer/Client/main.cpp

@@ -0,0 +1,62 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include <iostream>
+#include "servant/Communicator.h"
+#include "Hello.h"
+
+using namespace std;
+using namespace TestApp;
+using namespace tars;
+
+int main(int argc,char ** argv)
+{
+    Communicator comm;
+
+    try
+    {
+        HelloPrx prx;
+        comm.stringToProxy("TestApp.HelloServer.HelloObj@tcp -h 10.120.129.226 -p 20001" , prx);
+
+        try
+        {
+            string sReq("hello");
+            string sRsp("");
+
+            int iRet = prx->testHello(sReq, sRsp);
+            cout<<"iRet:"<<iRet<<" sReq:"<<sReq<<" sRsp:"<<sRsp<<endl;
+
+        }
+        catch(exception &ex)
+        {
+            cerr << "ex:" << ex.what() << endl;
+        }
+        catch(...)
+        {
+            cerr << "unknown exception." << endl;
+        }
+    }
+    catch(exception& e)
+    {
+        cerr << "exception:" << e.what() << endl;
+    }
+    catch (...)
+    {
+        cerr << "unknown exception." << endl;
+    }
+
+    return 0;
+}

+ 16 - 0
examples/QuickStartDemo/HelloServer/Client/makefile

@@ -0,0 +1,16 @@
+
+#-----------------------------------------------------------------------
+
+APP       := TestApp
+TARGET    := TestHelloServer
+CONFIG    := 
+STRIP_FLAG:= N
+
+INCLUDE   += 
+LIB       += 
+
+#-----------------------------------------------------------------------
+
+include /home/tarsproto/TestApp/HelloServer/HelloServer.mk
+include /usr/local/tars/cpp/makefile/makefile.tars
+#-----------------------------------------------------------------------

+ 26 - 0
examples/QuickStartDemo/HelloServer/Hello.tars

@@ -0,0 +1,26 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+module TestApp
+{
+
+interface Hello
+{
+    int test();
+    int testHello(string sReq, out string sRsp);
+};
+
+}; 

+ 42 - 0
examples/QuickStartDemo/HelloServer/HelloImp.cpp

@@ -0,0 +1,42 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except 
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ */
+
+#include "HelloImp.h"
+#include "servant/Application.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////
+void HelloImp::initialize()
+{
+    //initialize servant here:
+    //...
+}
+
+//////////////////////////////////////////////////////
+void HelloImp::destroy()
+{
+    //destroy servant here:
+    //...
+}
+
+int HelloImp::testHello(const std::string &sReq, std::string &sRsp, tars::TarsCurrentPtr current)
+{
+    TLOGDEBUG("HelloImp::testHellosReq:"<<sReq<<endl);
+    sRsp = sReq;
+    return 0;
+}
+

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio