这次展示如何将一个服务器端的C++类让客户端调用。使用早上刚刚开发完的工具,用户可以不用处理任何传输过程中的连接和编码解码等操作。这次实现一个四则运算的语法分析器,客户端发送表达式,服务器端传回语法树(继承树那个模型),客户端将语法树传回去,服务器端传回运算结果。
首先在服务器端定义语法树:
1 class Expression : public VL_Base
2 {
3 public:
4 typedef VL_AutoPtr<Expression> Ptr;
5
6 virtual VDouble Evaluate()
7 {
8 return 0;
9 }
10 };
11
12 class NumberExpression : public Expression
13 {
14 public:
15 VDouble Number;
16
17 NumberExpression()
18 {
19 Number=0;
20 }
21
22 NumberExpression(VDouble aNumber)
23 {
24 Number=aNumber;
25 }
26
27 VDouble Evaluate()
28 {
29 return Number;
30 }
31 };
32
33 enum BinaryType
34 {
35 btAdd,
36 btSub,
37 btMul,
38 btDiv
39 };
40
41 class BinaryExpression : public Expression
42 {
43 public:
44 Expression::Ptr Left;
45 Expression::Ptr Right;
46 BinaryType Type;
47
48 BinaryExpression()
49 {
50 Type=btAdd;
51 }
52
53 BinaryExpression(Expression::Ptr aLeft , Expression::Ptr aRight , BinaryType aType)
54 {
55 Left=aLeft;
56 Right=aRight;
57 Type=aType;
58 }
59
60 VDouble Evaluate()
61 {
62 switch(Type)
63 {
64 case btAdd:
65 return Left->Evaluate()+Right->Evaluate();
66 case btSub:
67 return Left->Evaluate()-Right->Evaluate();
68 case btMul:
69 return Left->Evaluate()*Right->Evaluate();
70 case btDiv:
71 return Left->Evaluate()/Right->Evaluate();
72 default:
73 return 0;
74 }
75 }
76 };
其次使用
Combinator写一个语法分析器:
1 enum TokenType
2 {
3 ttNumber,
4 ttAdd,
5 ttSub,
6 ttMul,
7 ttDiv,
8 ttLeft,
9 ttRight
10 };
11
12 Expression::Ptr CreateNumber(const VL_CpToken& Token)
13 {
14 return new NumberExpression(VUnicodeString(Token.Start,Token.Length).ToDouble());
15 }
16
17 Expression::Ptr CreateBinary(const VL_CpPair<Expression::Ptr , VL_CpList<VL_CpPair<VL_CpToken , Expression::Ptr>>>& Input)
18 {
19 Expression::Ptr Result=Input.First;
20 VL_CpList<VL_CpPair<VL_CpToken , Expression::Ptr>>::Node::Ptr Current=Input.Second.Head;
21 while(Current)
22 {
23 switch(Current->Data.First.ID)
24 {
25 case ttAdd:
26 Result=new BinaryExpression(Result,Current->Data.Second,btAdd);
27 break;
28 case ttSub:
29 Result=new BinaryExpression(Result,Current->Data.Second,btSub);
30 break;
31 case ttMul:
32 Result=new BinaryExpression(Result,Current->Data.Second,btMul);
33 break;
34 case ttDiv:
35 Result=new BinaryExpression(Result,Current->Data.Second,btDiv);
36 break;
37 }
38 Current=Current->Next;
39 }
40 return Result;
41 }
42
43 class ExpressionParser
44 {
45 public:
46 Expression::Ptr Parse(VUnicodeString Input)
47 {
48 VL_CpLexer Lexer;
49 Lexer
50 <<Token(false,_UnsignedFloat,ttNumber)
51 <<Token(false,L"+",ttAdd)
52 <<Token(false,L"-",ttSub)
53 <<Token(false,L"*",ttMul)
54 <<Token(false,L"/",ttDiv)
55 <<Token(false,L"(",ttLeft)
56 <<Token(false,L")",ttRight)
57 ;
58
59 typedef VL_CpLexedTypes<Expression::Ptr> Types;
60 Types::Rule Factor,Term,Expr;
61
62 Factor=(CreateNumber<<=Token(ttNumber))||(Token(ttLeft)>Expr<Token(ttRight));
63 Term=CreateBinary<<=(Factor+**((Token(ttMul)||Token(ttDiv))+Factor));
64 Expr=CreateBinary<<=(Term+**((Token(ttAdd)||Token(ttSub))+Term));
65 Types::Parser Parser=Expr;
66
67 VL_CpLexer::_Result LexerResult=Lexer.Parse(Input.Buffer());
68 if(LexerResult.First.Head && !LexerResult.Second.First)
69 {
70 Types::Parser::_FullResult ParserResult=Parser.Parse(LexerResult.First.Head,true);
71 if(ParserResult.Head)
72 {
73 return ParserResult.Head->Data.First;
74 }
75 }
76 return 0;
77 }
78
79 VDouble Evaluate(Expression::Ptr Expr)
80 {
81 return Expr->Evaluate();
82 }
83 };
最后将这4个类注册进服务器:
1 /*********************************************************************************************************
2 反射
3 *********************************************************************************************************/
4
5 VL_BEGIN_INSPECTOR_DECLARATION
6
7 VL_BEGIN_BASE_CLASS(Expression)
8 VL_END_CLASS(Expression)
9
10 VL_BEGIN_SUB_CLASS(NumberExpression,Expression)
11 VL_ADD_CLASS_MEMBER(Number)
12 VL_END_CLASS(NumberExpression)
13
14 VL_BEGIN_ENUM(BinaryType,false)
15 VL_ADD_ENUM_MEMBER(btAdd)
16 VL_ADD_ENUM_MEMBER(btSub)
17 VL_ADD_ENUM_MEMBER(btMul)
18 VL_ADD_ENUM_MEMBER(btDiv)
19 VL_END_ENUM(BinaryType)
20
21 VL_BEGIN_SUB_CLASS(BinaryExpression,Expression)
22 VL_ADD_CLASS_MEMBER(Left)
23 VL_ADD_CLASS_MEMBER(Right)
24 VL_ADD_CLASS_MEMBER(Type)
25 VL_END_CLASS(BinaryExpression)
26
27 VL_BEGIN_BASE_CLASS(ExpressionParser)
28 VL_ADD_CLASS_METHOD(Parse)
29 VL_ADD_CLASS_METHOD(Evaluate)
30 VL_END_CLASS(ExpressionParser)
31
32 VL_BEGIN_INSPECTOR_MANAGER(ExpressionManager)
33 VL_BIND_INSPECTOR(Expression)
34 VL_BIND_INSPECTOR(NumberExpression)
35 VL_BIND_INSPECTOR(BinaryExpression)
36 VL_BIND_INSPECTOR(ExpressionParser)
37 VL_END_INSPECTOR_MANAGER
38
39 VL_END_INSPECTOR_DECLARATION
40
41 /*********************************************************************************************************
42 主程序
43 *********************************************************************************************************/
44
45 void vlmain()
46 {
47 GetConsole()->SetTitle(L"Vczh HTTP Server");
48 GetConsole()->SetTestMemoryLeaks(true);
49 GetConsole()->SetPauseOnExit(false);
50 GetConsole()->WriteLine(L"主机名称:"+GetHostName());
51 GetConsole()->WriteLine(L"主机地址:"+GetIpv4Address());
52
53 VL_ObjectServer Server(VL_GET_INSPECTOR_MANAGER(ExpressionManager),8080,8081,L"expression");
54 Server.Start();
55 GetConsole()->WriteLine(L"按回车结束服务程序:");
56 GetConsole()->WaitForEnter();
57 }
注意代码配置的HTTP端口是8080,Service端口是8081。首先是服务器端的截图:
然后就可以使用上面的地址(或者写成localhost,如果是本地调试的话)和端口打开一个服务器自动产生的网站,在上面可以下载已经生成的客户端的代码:
建立一个客户端工程,
将这个远程调用的库的源代码包含进去之后,将.h和.cpp下载了加进工程,然后修改#include的地址,就可以编译了:
于是我们就可以立刻调用这个类了。
注意算法的实现仍然在服务器端,生成的expression.h/.cpp只负责在网络上传输你的参数和服务器的结果。
1 #include "..\..\..\..\VL++\Library\Platform\VL_Console.h"
2 #include "expression.h"
3
4 using namespace vl;
5 using namespace vl::platform;
6
7 void vlmain()
8 {
9 GetConsole()->SetTitle(L"Vczh HTTP Client");
10 GetConsole()->SetTestMemoryLeaks(true);
11 GetConsole()->SetPauseOnExit(true);
12
13 try
14 {
15 ExpressionParser Parser;
16 VUnicodeString Input;
17 GetConsole()->WriteLine(L"请输入四则运算表达式,若直接回车则视为结束。");
18 while(true)
19 {
20 GetConsole()->Write(L":");
21 GetConsole()->Read(Input);
22 if(Input==L"")
23 {
24 break;
25 }
26 VL_AutoPtr<Expression> Expr=Parser.Parse(Input);
27 if(Expr)
28 {
29 GetConsole()->WriteLine(L"结果:"+VUnicodeString(Parser.Evaluate(Expr)));
30 }
31 else
32 {
33 GetConsole()->WriteLine(L"出现语法错误。");
34 }
35 }
36 }
37 catch(const VL_ObjectClientError& e)
38 {
39 GetConsole()->WriteLine(L"发生错误:"+e.Message);
40 }
41 GetConsole()->WriteLine(L"结束运行。");
42 }
然后我们看看运行结果:
成功了!只需要在服务器端注册一个类,客户端就可以这么调用了。而且无论数据结构有什么继承还有各种各样的容器都不成问题,还可以在不修改已有代码的情况下,扩展成支持STL或者其他各种容器的系统。
最后附上服务器
生成的客户端头文件和代码文件。首先是头文件:
1 /*******************************************************************************
2 Vczh Library++ 2.0
3 C++远程对象客户端::expression
4 开发者:陈梓瀚
5
6 *******************************************************************************/
7 #ifndef VCZH_LIBRARY_PLUS_PLUS_2_0_C_PLUS_PLUS_REMOTE_OBJECT_CLIENT_EXPRESSION
8 #define VCZH_LIBRARY_PLUS_PLUS_2_0_C_PLUS_PLUS_REMOTE_OBJECT_CLIENT_EXPRESSION
9
10 #include "Library\Data\Inspector\VL_ObjectClient.h"
11
12 using namespace vl;
13 using namespace vl::collection;
14 using namespace vl::inspector;
15
16 enum BinaryType
17 {
18 btAdd,
19 btDiv,
20 btMul,
21 btSub,
22 };
23
24 class Expression : public VL_Base
25 {
26 public:
27 };
28
29 class BinaryExpression : public Expression
30 {
31 public:
32 VL_AutoPtr<Expression> Left;
33 VL_AutoPtr<Expression> Right;
34 BinaryType Type;
35 };
36
37 class ExpressionParser : public VL_ObjectClient
38 {
39 protected:
40 VL_InspectorManager::Ptr FManager;
41
42 VL_InspectorManager::Ptr GetInspectorManager();
43 public:
44 ExpressionParser();
45
46 VDouble Evaluate(VL_AutoPtr<Expression> _0);
47 VL_AutoPtr<Expression> Parse(VUnicodeString _0);
48 };
49
50 class NumberExpression : public Expression
51 {
52 public:
53 VDouble Number;
54 };
55
56 #endif
然后是代码文件:
1 #include "expression.h"
2
3 VL_BEGIN_INSPECTOR_DECLARATION
4
5 VL_BEGIN_ENUM(BinaryType,false)
6 VL_ADD_ENUM_MEMBER(btAdd)
7 VL_ADD_ENUM_MEMBER(btDiv)
8 VL_ADD_ENUM_MEMBER(btMul)
9 VL_ADD_ENUM_MEMBER(btSub)
10 VL_END_ENUM(BinaryType)
11
12 VL_BEGIN_BASE_CLASS(Expression)
13 VL_END_CLASS(Expression)
14
15 VL_BEGIN_SUB_CLASS(BinaryExpression,Expression)
16 VL_ADD_CLASS_MEMBER(Left)
17 VL_ADD_CLASS_MEMBER(Right)
18 VL_ADD_CLASS_MEMBER(Type)
19 VL_END_CLASS(BinaryExpression)
20
21 VL_BEGIN_BASE_CLASS(ExpressionParser)
22 VL_ADD_CLASS_METHOD(Evaluate)
23 VL_ADD_CLASS_METHOD(Parse)
24 VL_END_CLASS(ExpressionParser)
25
26 VL_BEGIN_SUB_CLASS(NumberExpression,Expression)
27 VL_ADD_CLASS_MEMBER(Number)
28 VL_END_CLASS(NumberExpression)
29
30 VL_BEGIN_INSPECTOR_MANAGER(expressionManager)
31 VL_BIND_INSPECTOR(BinaryType)
32 VL_BIND_INSPECTOR(Expression)
33 VL_BIND_INSPECTOR(BinaryExpression)
34 VL_BIND_INSPECTOR(ExpressionParser)
35 VL_BIND_INSPECTOR(NumberExpression)
36 VL_END_INSPECTOR_MANAGER
37
38 VL_END_INSPECTOR_DECLARATION
39
40 /*********************************************************************************************************
41 ExpressionParser
42 *********************************************************************************************************/
43
44 VL_InspectorManager::Ptr ExpressionParser::GetInspectorManager()
45 {
46 return FManager;
47 }
48
49 ExpressionParser::ExpressionParser():VL_ObjectClient(L"192.168.11.13:8081",L"ExpressionParser")
50 {
51 FManager=VL_GET_INSPECTOR_MANAGER(expressionManager);
52 SetMethodResult(L"Evaluate",FManager->GetInspector(L"VDouble"));
53 AddMethodParameter(L"Evaluate",FManager->GetInspector(L"Expression"));
54 SetMethodResult(L"Parse",FManager->GetInspector(L"Expression"));
55 AddMethodParameter(L"Parse",FManager->GetInspector(L"VUnicodeString"));
56 }
57
58 VDouble ExpressionParser::Evaluate(VL_AutoPtr<Expression> _0)
59 {
60 VL_ObjectInspector::Ptr ResultInspector;
61 VDouble ResultVariable;
62 VPointer ResultData=&ResultVariable;
63 VPointer Parameters[1];
64 Parameters[0]=_0.Object();
65 Invoke(L"Evaluate",Parameters,ResultInspector,ResultData);
66 return ResultVariable;
67 }
68
69 VL_AutoPtr<Expression> ExpressionParser::Parse(VUnicodeString _0)
70 {
71 VL_ObjectInspector::Ptr ResultInspector;
72 VPointer ResultData=0;
73 VPointer Parameters[1];
74 Parameters[0]=&_0;
75 Invoke(L"Parse",Parameters,ResultInspector,ResultData);
76 return (Expression*)ResultData;
77 }
78
现在只完成了单向操作,服务器端还不能调用客户端提供的服务。等这个完成之后,就写一个完整的Demo,然后把代码放出来供下载。
posted on 2009-07-03 18:07
陈梓瀚(vczh) 阅读(4092)
评论(14) 编辑 收藏 引用 所属分类:
C++