add tarscpp files
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "servant/protocol"]
|
||||
path = servant/protocol
|
||||
url = https://github.com/TarsCloud/TarsProtocol.git
|
32
CMakeLists.txt
Normal file
@ -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
README.md
Normal file
@ -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
README.zh.md
Normal file
@ -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
docs-en/tars_cpp_develop_specification.md
Normal file
@ -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
docs-en/tars_cpp_faq.md
Normal file
@ -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
docs-en/tars_cpp_future_promise.md
Normal file
@ -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.
|
||||
|
||||
|
||||
|
||||
## **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**
|
||||
|
||||
|
||||
|
||||
## **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->B->C,C->B->A is the same result), so the idea of using Future/Promise is most suitable.
|
||||
|
||||
|
||||
|
||||
## **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
docs-en/tars_cpp_http_demo.md
Normal file
@ -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
docs-en/tars_cpp_quickstart.md
Normal file
@ -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
docs-en/tars_cpp_server_thread.md
Normal file
@ -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
docs-en/tars_cpp_user_guide.md
Normal file
47
docs-en/tars_protobuf_cpp.md
Normal file
@ -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
docs-en/tars_push.md
Normal file
@ -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
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
docs/images/tars_cpp_quickstart_bushu2.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
docs/images/tars_cpp_quickstart_patch.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
docs/images/tars_cpp_quickstart_patchresult.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
docs/images/tars_cpp_quickstart_upload.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
docs/images/tars_cpp_third_protocol.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
docs/images/tars_web_index.png
Normal file
After Width: | Height: | Size: 24 KiB |
178
docs/tars_cpp_develop_specification.md
Normal file
@ -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
docs/tars_cpp_faq.md
Normal file
@ -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
docs/tars_cpp_future_promise.md
Normal file
@ -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不完全相同。
|
||||
|
||||
|
||||
|
||||
## **Future/Promise是什么?**
|
||||
|
||||
Future与Promise其实是二个完全不同的东西:
|
||||
|
||||
> Future:用来表示一个尚未有结果的对象,而产生这个结果的行为是异步操作;
|
||||
>
|
||||
> Promise:Future对象可以使用Promise对象来创建(getFuture),创建后,Promise对象保存的值可以被Future对象读取,同时将二个对象共享状态关联起来。可以认Promise为Future结果同步提供了一种手段;
|
||||
|
||||
简而言之就是:**他们提供了一套非阻塞并行操作的处理方案,当然,你也可以阻塞操作来等待Future的结果返回。**
|
||||
|
||||
|
||||
|
||||
## **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->B->C,C->B->A的结果一样),所使用Future/Promise的思想最适合。
|
||||
|
||||
|
||||
|
||||
## **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
docs/tars_cpp_http_demo.md
Normal file
@ -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
docs/tars_cpp_quickstart.md
Normal file
@ -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
docs/tars_cpp_server_thread.md
Normal file
@ -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
docs/tars_cpp_user_guide.md
Normal file
44
docs/tars_protobuf_cpp.md
Normal file
@ -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
docs/tars_push.md
Normal file
@ -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
examples/CoroutineDemo/AServer/AServant.tars
Normal file
@ -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
examples/CoroutineDemo/AServer/AServantImp.cpp
Normal file
@ -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
examples/CoroutineDemo/AServer/AServantImp.h
Normal file
@ -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
examples/CoroutineDemo/AServer/AServer.cpp
Normal file
@ -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
examples/CoroutineDemo/AServer/AServer.h
Normal file
@ -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
examples/CoroutineDemo/AServer/makefile
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
APP := Test
|
||||
TARGET := AServer
|
||||
CONFIG :=
|
||||
STRIP_FLAG:= N
|
||||
|
||||
INCLUDE +=
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
include /usr/local/tars/cpp/makefile/makefile.tars
|
||||
#-----------------------------------------------------------------------
|
14
examples/CoroutineDemo/BServer/AServant.tars
Normal file
@ -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
examples/CoroutineDemo/BServer/BServant.tars
Normal file
@ -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
examples/CoroutineDemo/BServer/BServantImp.cpp
Normal file
@ -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
examples/CoroutineDemo/BServer/BServantImp.h
Normal file
@ -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
examples/CoroutineDemo/BServer/BServer.cpp
Normal file
@ -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
examples/CoroutineDemo/BServer/BServer.h
Normal file
@ -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
examples/CoroutineDemo/BServer/makefile
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
APP := Test
|
||||
TARGET := BServer
|
||||
CONFIG :=
|
||||
STRIP_FLAG:= N
|
||||
|
||||
INCLUDE +=
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
include /usr/local/tars/cpp/makefile/makefile.tars
|
||||
#-----------------------------------------------------------------------
|
7
examples/CoroutineDemo/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
该工程是Tars 协程编程示例的代码
|
||||
|
||||
|
||||
目录名称 |功能
|
||||
-----------------|----------------
|
||||
client/BServer/AServer | 协程编程的示例程序,client访问BServer,BServer用协程方式去并行和串行访问AServer
|
||||
testCoro/testParallelCoro | 协程编程的示例程序,自定义或者继承框架的协程类
|
15
examples/CoroutineDemo/client/BServant.tars
Normal file
@ -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
examples/CoroutineDemo/client/main.cpp
Normal file
@ -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
examples/CoroutineDemo/client/makefile
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
APP := Test
|
||||
TARGET := client
|
||||
CONFIG :=
|
||||
STRIP_FLAG:= N
|
||||
|
||||
INCLUDE +=
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
include /usr/local/tars/cpp/makefile/makefile.tars
|
||||
#-----------------------------------------------------------------------
|
15
examples/CoroutineDemo/testCoro/BServant.tars
Normal file
@ -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
examples/CoroutineDemo/testCoro/main.cpp
Normal file
@ -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
examples/CoroutineDemo/testCoro/makefile
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
APP := Test
|
||||
TARGET := testCoro
|
||||
CONFIG :=
|
||||
STRIP_FLAG:= N
|
||||
|
||||
INCLUDE +=
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
include /usr/local/tars/cpp/makefile/makefile.tars
|
||||
#-----------------------------------------------------------------------
|
15
examples/CoroutineDemo/testParallelCoro/BServant.tars
Normal file
@ -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
examples/CoroutineDemo/testParallelCoro/main.cpp
Normal file
@ -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
examples/CoroutineDemo/testParallelCoro/makefile
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
APP := Test
|
||||
TARGET := testCoro
|
||||
CONFIG :=
|
||||
STRIP_FLAG:= N
|
||||
|
||||
INCLUDE +=
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
include /usr/local/tars/cpp/makefile/makefile.tars
|
||||
#-----------------------------------------------------------------------
|
175
examples/HttpDemo/HttpClient/main.cpp
Normal file
@ -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
examples/HttpDemo/HttpClient/makefile
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
APP := Test
|
||||
TARGET := HttpClient
|
||||
CONFIG :=
|
||||
STRIP_FLAG:= N
|
||||
|
||||
INCLUDE +=
|
||||
LIB +=
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
include /usr/local/tars/cpp/makefile/makefile.tars
|
||||
#-----------------------------------------------------------------------
|
49
examples/HttpDemo/HttpServer/HttpImp.cpp
Normal file
@ -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
examples/HttpDemo/HttpServer/HttpImp.h
Normal file
@ -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
examples/HttpDemo/HttpServer/HttpServer.cpp
Normal file
@ -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
examples/HttpDemo/HttpServer/HttpServer.h
Normal file
@ -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
examples/HttpDemo/HttpServer/makefile
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
APP := TestApp
|
||||
TARGET := HttpServer
|
||||
CONFIG :=
|
||||
STRIP_FLAG:= N
|
||||
|
||||
INCLUDE +=
|
||||
LIB +=
|
||||
|
||||
#-----------------------------------------------------------------------i
|
||||
|
||||
include /usr/local/tars/cpp/makefile/makefile.tars
|
27
examples/PromiseDemo/AServer/AServant.tars
Normal file
@ -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
examples/PromiseDemo/AServer/AServantImp.cpp
Normal file
@ -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 ¤t)
|
||||
: _current(current)
|
||||
{}
|
||||
|
||||
BServantCallback(TarsCurrentPtr ¤t, 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 ¤t)
|
||||
: _current(current)
|
||||
{}
|
||||
|
||||
CServantCallback(TarsCurrentPtr ¤t, 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
examples/PromiseDemo/AServer/AServantImp.h
Normal file
@ -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
examples/PromiseDemo/AServer/AServer.cpp
Normal file
@ -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
examples/PromiseDemo/AServer/AServer.h
Normal file
@ -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
examples/PromiseDemo/AServer/BServant.tars
Normal file
@ -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
examples/PromiseDemo/AServer/CServant.tars
Normal file
@ -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
examples/PromiseDemo/AServer/makefile
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
APP := Test
|
||||
TARGET := AServer
|
||||
CONFIG :=
|
||||
STRIP_FLAG:= N
|
||||
|
||||
INCLUDE +=
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
include /usr/local/tars/cpp/makefile/makefile.tars
|
||||
#-----------------------------------------------------------------------
|
25
examples/PromiseDemo/BServer/BServant.tars
Normal file
@ -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
examples/PromiseDemo/BServer/BServantImp.cpp
Normal file
@ -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
examples/PromiseDemo/BServer/BServantImp.h
Normal file
@ -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
examples/PromiseDemo/BServer/BServer.cpp
Normal file
@ -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
examples/PromiseDemo/BServer/BServer.h
Normal file
@ -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
examples/PromiseDemo/BServer/makefile
Normal file
@ -0,0 +1,11 @@
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
APP := Test
|
||||
TARGET := BServer
|
||||
CONFIG :=
|
||||
STRIP_FLAG:= N
|
||||
INCLUDE +=
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
include /usr/local/tars/cpp/makefile/makefile.tars
|
||||
#-----------------------------------------------------------------------
|
25
examples/PromiseDemo/CServer/CServant.tars
Normal file
@ -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
examples/PromiseDemo/CServer/CServantImp.cpp
Normal file
@ -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
examples/PromiseDemo/CServer/CServantImp.h
Normal file
@ -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
examples/PromiseDemo/CServer/CServer.cpp
Normal file
@ -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
examples/PromiseDemo/CServer/CServer.h
Normal file
@ -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
examples/PromiseDemo/CServer/makefile
Normal file
@ -0,0 +1,11 @@
|
||||
#-----------------------------------------------------------------------
|
||||
APP := Test
|
||||
TARGET := CServer
|
||||
CONFIG :=
|
||||
STRIP_FLAG:= N
|
||||
|
||||
INCLUDE +=
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
include /usr/local/tars/cpp/makefile/makefile.tars
|
||||
#-----------------------------------------------------------------------
|
138
examples/PromiseDemo/Client/main.cpp
Normal file
@ -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
examples/PromiseDemo/Client/makefile
Normal file
@ -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
examples/PromiseDemo/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
该工程是Tars promise编程示例的代码
|
||||
|
||||
|
||||
目录名称 |功能
|
||||
-----------------|----------------
|
||||
AServer | promise编程的示例程序,用promsie方式去并行和串行访问BServer和CServer
|
13
examples/PushDemo/PushClient/Makefile
Normal file
@ -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
examples/PushDemo/PushClient/TestRecvThread.cpp
Normal file
@ -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
examples/PushDemo/PushClient/TestRecvThread.h
Normal file
@ -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
examples/PushDemo/PushClient/main.cpp
Normal file
@ -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
examples/PushDemo/PushServer/TestPushServantImp.cpp
Normal file
@ -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
examples/PushDemo/PushServer/TestPushServantImp.h
Normal file
@ -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
examples/PushDemo/PushServer/TestPushServer.cpp
Normal file
@ -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
examples/PushDemo/PushServer/TestPushServer.h
Normal file
@ -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
examples/PushDemo/PushServer/TestPushThread.cpp
Normal file
@ -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
examples/PushDemo/PushServer/TestPushThread.h
Normal file
@ -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
examples/PushDemo/PushServer/makefile
Normal file
@ -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
examples/PushDemo/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
该工程是Tars快速入门示例的代码
|
||||
|
||||
|
||||
目录名称 |功能
|
||||
-----------------|----------------
|
||||
HelloServer | 开发快速入门的示例
|
||||
ProxyServer | 中转代理服务示例,作为HelloServer的代理服务
|
80
examples/QuickStartDemo/HelloServer/AsyncClient/main.cpp
Normal file
@ -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
examples/QuickStartDemo/HelloServer/AsyncClient/makefile
Normal file
@ -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
examples/QuickStartDemo/HelloServer/Client/main.cpp
Normal file
@ -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
examples/QuickStartDemo/HelloServer/Client/makefile
Normal file
@ -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
examples/QuickStartDemo/HelloServer/Hello.tars
Normal file
@ -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
examples/QuickStartDemo/HelloServer/HelloImp.cpp
Normal file
@ -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;
|
||||
}
|
||||
|