今天展示一下如何使用这里描写的库实现一个简单的聊天工具。Callback Interface是昨晚才加的,但是还有一些features没实现,等做完了再做一个Demo,然后提供源代码。
使用这个库开发网络程序的步骤如下:
1:将需要提供给客户端调用的功能封装成类,实现在服务器端,然后注册需要的类、类成员变量和类成员函数。
2:服务器创建VL_ObjectServer,并将注册的类提供给它,然后运行。
3:打开http://localhost:PORT/SERVER/index.htm下载服务器端需要的CallbackProxy类。当类需要客户端提供Callback的时候,就可以用CallbackProxy来调用它。这里CallbackProxy是自动生成的。
4:创建客户端工程,在上面那个网址下载生成的服务器端的类的Proxy。这个Proxy负责连接服务器并把所需要的数据序列化之后发送过去。服务器端的VL_ObjectServer负责解读序列化的内容,然后调用客户端实现的那些服务类。
5:写一个UI调用下载的服务类的Proxy。
6:运行它们。
实际上就是把他们当成同一个程序来写,然后这个库提供了很多方便的功能让客户端可以直接调用服务器端写的类,中间的链接和传输不需要自己处理,完全是自动的。
首先我们定义这个聊天工具的接口。聊天工具登录的时候服务器会自动分配一个名称,用户可以随后更改。然后剩下的只有两个操作:发送信息和退出登录。我们默认程序关闭的时候退出登录。于是可以先做一个User类,然后做一个Service类,Service调用Callback来告诉其他用户某人发送了信息:
1 class RoaTalkUser : public VL_Base
2 {
3 public:
4 typedef VL_AutoPtr<RoaTalkUser> Ptr;
5 typedef VL_List<Ptr , false , RoaTalkUser*> List;
6 typedef VL_ListedMap<VUnicodeString , Ptr> StringMap;
7
8 VUnicodeString Name;
9 RoaTalkService* Owner;
10 };
11
12 class RoaTalkCallback : public VL_ObjectCallback
13 {
14 public:
15 virtual void Say(RoaTalkUser::Ptr User , VUnicodeString Message);
16 virtual void Login(RoaTalkUser::Ptr User);
17 virtual void Logout(RoaTalkUser::Ptr User);
18 virtual void Rename(VUnicodeString OldName , RoaTalkUser::Ptr User);
19 };
20
21 class RoaTalkService : public VL_ObjectService
22 {
23 protected:
24 VUnicodeString FName;
25 RoaTalkCallback* FCallback;
26
27 void Initialize();
28 public:
29 typedef VL_List<RoaTalkService* , true> List;
30
31 RoaTalkService();
32 ~RoaTalkService();
33
34 RoaTalkCallback* GetCallback();
35
36 VUnicodeString GetCurrentName();
37 VBool SetCurrentName(VUnicodeString Name);
38 void Say(VUnicodeString Message);
39 VL_AutoPtr<RoaTalkUser::List> GetUsers();
40 };
这只是给客户端调用的外壳。因为每一个客户端连接的时候,系统就会创建一个RoaTalkService类,所以还需要一个全局变量来记录所有的Service类(未来可能会提供Feature来避免这种全局变量的产生)。这个全局的服务类是需要锁的:
1 class RoaTalkServer : public VL_Base
2 {
3 protected:
4 RoaTalkUser::StringMap FUsers;
5 VL_SynCriticalSection FServerLock;
6 public:
7 RoaTalkServer();
8 ~RoaTalkServer();
9
10 VBool CreateUser(VUnicodeString Name , RoaTalkService* Service);
11 VBool DestroyUser(VUnicodeString Name);
12 VBool RenameUser(VUnicodeString OldName , VUnicodeString NewName);
13 VL_AutoPtr<RoaTalkUser::List> GetUsers();
14 VBool Say(VUnicodeString Name , VUnicodeString Message);
15 };
16
17 extern void CreateRoaTalkServer();
18 extern void DestroyRoaTalkServer();
19 extern RoaTalkServer* GetRoaTalkServer();
实现他们是很容易的。Service通过调用CreateUser、DestroyUser、RenameUser和Say来完成SetCurrentName和Say两个操作。Server(注意不是Service)在被调用的时候,通过向其他Service->GetCallback()来通知其他客户端某个人做了什么事情。注意虽然代码是在服务器端,但是RoaTalkCallback的实现是在客户端。下面会告诉大家如何把两边连接起来的的。现在的事情就是要先把他们实现好,我们注意到Service有一个Initialize函数,这个函数通过创建一个生成的RoaTalkCallbackProxy类然后赋值给FCallback变量,从而达到让Server获得那么多Callback的目的。但是现在服务器还没启动,因此先留空。FCallback设置成NULL。等到代码写完了之后(见下文),我们需要注册它:
下面的VL_METHOD_PARAMETER并不是必需的,只是不写的话,生成的客户端的代码里面类的参数会变成_0,_1这样子的东西,不好看。
1 /*********************************************************************************************************
2 注册
3 *********************************************************************************************************/
4
5 VL_BEGIN_INSPECTOR_DECLARATION
6
7 VL_BEGIN_BASE_CLASS(RoaTalkUser)
8 VL_ADD_CLASS_MEMBER(Name)
9 VL_END_CLASS(RoaTalkUser)
10
11 VL_BEGIN_CALLBACK(RoaTalkCallback)
12 VL_ADD_CLASS_METHOD(Say)
13 VL_METHOD_PARAMETER(User)
14 VL_METHOD_PARAMETER(Message)
15
16 VL_ADD_CLASS_METHOD(Login)
17 VL_METHOD_PARAMETER(User)
18
19 VL_ADD_CLASS_METHOD(Logout)
20 VL_METHOD_PARAMETER(User)
21
22 VL_ADD_CLASS_METHOD(Rename)
23 VL_METHOD_PARAMETER(OldName)
24 VL_METHOD_PARAMETER(User)
25 VL_END_CLASS(RoaTalkCallback)
26
27 VL_BEGIN_DUAL_SERVICE(RoaTalkService,RoaTalkCallback)
28 VL_ADD_CLASS_METHOD(GetCurrentName)
29
30 VL_ADD_CLASS_METHOD(SetCurrentName)
31 VL_METHOD_PARAMETER(Name)
32
33 VL_ADD_CLASS_METHOD(Say)
34 VL_METHOD_PARAMETER(Message)
35
36 VL_ADD_CLASS_METHOD(GetUsers)
37 VL_END_CLASS(RoaTalkService)
38
39 VL_EXTERN_INSPECTOR_MANAGER(RoaTalk)
40
41 VL_END_INSPECTOR_DECLARATION
至此服务器就完成了。我们通过main函数来启动这个服务器:
1 #include "..\..\..\..\VL++\Library\Platform\VL_Console.h"
2 #include "RoaTalk.h"
3
4 using namespace vl;
5 using namespace vl::platform;
6
7 void PrintNotify(VUnicodeString Message)
8 {
9 GetConsole()->WriteLine(L"NOTIFY> "+Message);
10 }
11
12 void vlmain()
13 {
14 GetConsole()->SetTitle(L"Vczh RoaTalk Server v1.0");
15 GetConsole()->SetTestMemoryLeaks(true);
16 GetConsole()->SetPauseOnExit(false);
17
18 GetConsole()->WriteLine(L"Welcome to Vczh RoaTalk Server v1.0.");
19 CreateRoaTalkServer();
20 VL_ObjectServer Server(VL_GET_INSPECTOR_MANAGER(RoaTalk),8080,8081,L"RoaTalk");
21 Server.Start();
22 PrintNotify(L"Server started.");
23 GetConsole()->WaitForEnter();
24 Server.Stop();
25 DestroyRoaTalkServer();
26 }
接下来要生成代码了。我们看到main函数提供的HTTP端口是8080,而TCP端口是8081,服务名是RoaTalk。所以首先运行这个程序,然后打开IE并输入
http://localhost:8080/RoaTalk/index.htm,然后就可以看到下面的东西了:
首先下载“服务器端回调代理.h/.cpp”到服务器工程,然后创建一个客户端并下载“客户端.h/cpp”。现在我们先看看服务器端需要做些什么事情。
首先下载下来的RoaTalk_Callback.h需要手动添加一行#include "RoaTalk.h"。这个RoaTalk.h文件就是上文展示的那些声明所在的文件。然后就可以在RoaTalkService::Initialize()函数里面添加下面的内容了:
1 void RoaTalkService::Initialize()
2 {
3 FCallback=CreateCallbackObject<RoaTalkCallbackProxy>();
4 }
到此为止,服务器端就做好了。现在客户端有了客户端.h/cpp(生成的文件名是RoaTalk.h/cpp,跟服务名相同,并不是一定要跟服务器那个文件的名字一致)之后,就可以写一个Win32程序来调用它了。我们可以在客户端调用RoaTalkService类,但是需要实现RoaTalkCallback才能成功创建Service:
1 #include "..\..\..\..\VL++\Library\Windows\VL_WinGUI.h"
2 #include "RoaTalk.h"
3
4 using namespace vl;
5 using namespace vl::windows;
6 using namespace vl::windows::placement;
7
8 class RoaForm : public VL_WinForm , protected RoaTalkCallbackInterface
9 {
10 protected:
11 class PrintMessageCommand : public VL_Base , public IVL_WinCommand
12 {
13 protected:
14 RoaForm* FForm;
15 VUnicodeString FMessage;
16 public:
17 PrintMessageCommand(RoaForm* Form , VUnicodeString Message)
18 {
19 FForm=Form;
20 FMessage=Message;
21 }
22
23 void Execute()
24 {
25 FForm->FEditTalking->SetText(FForm->FEditTalking->GetText()+FMessage+L"\r\n");
26 FForm->FEditTalking->Select(FForm->FEditTalking->GetText().Length(),0);
27 FForm->FEditTalking->ScrollToCaret();
28 }
29 };
30 protected:
31 VL_WinEdit* FEditName;
32 VL_WinButton* FButtonLogin;
33 VL_WinEdit* FEditTalking;
34 VL_WinEdit* FEditMessage;
35 VL_WinButton* FButtonSend;
36
37 VL_AutoPtr<RoaTalkService> FRoaTalkService;
38
39 void UpdateStatus()
40 {
41 if(FRoaTalkService)
42 {
43 FEditName->SetEnabled(true);
44 FButtonLogin->SetText(L"Rename");
45 FEditMessage->SetEnabled(true);
46 FButtonSend->SetEnabled(true);
47 }
48 else
49 {
50 FEditName->SetEnabled(false);
51 FButtonLogin->SetText(L"Log In");
52 FEditMessage->SetEnabled(true);
53 FButtonSend->SetEnabled(false);
54 }
55 }
56
57 void CreateService()
58 {
59 if(!FRoaTalkService)
60 {
61 try
62 {
63 FRoaTalkService=new RoaTalkService(this);
64 FEditName->SetText(FRoaTalkService->GetCurrentName());
65 PrintMessage(L"==========CURRENT USERS==========");
66 VL_AutoPtr<VL_List<VL_AutoPtr<RoaTalkUser> , false , RoaTalkUser*>> Users=FRoaTalkService->GetUsers();
67 for(VInt i=0;i<Users->GetCount();i++)
68 {
69 PrintMessage(VUnicodeString(i+1)+L" : "+(*Users.Object())[i]->Name);
70 }
71 PrintMessage(L"=================================");
72 }
73 catch(const VL_ObjectError& e)
74 {
75 ShowMessage(this,e.Message,GetText());
76 }
77 }
78 UpdateStatus();
79 }
80
81 void DestroyService()
82 {
83 try
84 {
85 FRoaTalkService=0;
86 }
87 catch(const VL_ObjectError&)
88 {
89 }
90 UpdateStatus();
91 }
92
93 void PrintMessage(VUnicodeString Message)
94 {
95 GetApplication()->PerformCommandLater(new PrintMessageCommand(this,Message));
96 }
97
98 void FButtonLoginClick(VL_Base* Sender)
99 {
100 if(FRoaTalkService)
101 {
102 try
103 {
104 if(!FRoaTalkService->SetCurrentName(FEditName->GetText()))
105 {
106 FEditName->SetText(FRoaTalkService->GetCurrentName());
107 }
108 }
109 catch(const VL_ObjectError& e)
110 {
111 ShowMessage(this,e.Message,GetText());
112 DestroyService();
113 }
114 }
115 else
116 {
117 CreateService();
118 }
119 }
120
121 void FButtonSendClick(VL_Base* Sender)
122 {
123 if(FRoaTalkService)
124 {
125 try
126 {
127 FRoaTalkService->Say(FEditMessage->GetText());
128 PrintMessage(FRoaTalkService->GetCurrentName()+L"> "+FEditMessage->GetText());
129 FEditMessage->SetText(L"");
130 }
131 catch(const VL_ObjectError& e)
132 {
133 ShowMessage(this,e.Message,GetText());
134 DestroyService();
135 }
136 }
137 }
138
139 void FEditMessageChar(VL_Base* Sender , VWChar& Char)
140 {
141 if(Char==L'\r')
142 {
143 FButtonSendClick(FButtonSend);
144 Char=0;
145 }
146 }
147
148 void FormClose(VL_Base* Sender)
149 {
150 DestroyService();
151 }
152
153 void Login(VL_AutoPtr<RoaTalkUser> User)
154 {
155 PrintMessage(L"*"+User->Name+L" logged in*");
156 }
157
158 void Logout(VL_AutoPtr<RoaTalkUser> User)
159 {
160 PrintMessage(L"*"+User->Name+L" logged out*");
161 }
162
163 void Rename(VUnicodeString OldName , VL_AutoPtr<RoaTalkUser> User)
164 {
165 PrintMessage(L"*"+OldName+L" renamed to "+User->Name+L"*");
166 }
167
168 void Say(VL_AutoPtr<RoaTalkUser> User , VUnicodeString Message)
169 {
170 PrintMessage(User->Name+L"> "+Message);
171 }
172 public:
173 RoaForm():VL_WinForm(true)
174 {
175 FEditName=new VL_WinEdit(this,false);
176 FButtonLogin=new VL_WinButton(this);
177 FButtonLogin->SetText(L"Log In");
178 FButtonLogin->OnClick.Bind(this,&RoaForm::FButtonLoginClick);
179 FEditTalking=new VL_WinEdit(this,true);
180 FEditTalking->SetVScroll(true);
181 FEditTalking->SetHScroll(true);
182 FEditTalking->SetReadonly(true);
183 FEditMessage=new VL_WinEdit(this,false);
184 FEditMessage->OnChar.Bind(this,&RoaForm::FEditMessageChar);
185 FButtonSend=new VL_WinButton(this);
186 FButtonSend->SetText(L"Send");
187 FButtonSend->OnClick.Bind(this,&RoaForm::FButtonSendClick);
188
189 OnClose.Bind(this,&RoaForm::FormClose);
190
191 ApplyPlacement(
192 pHorzFix2(10,10,
193 pHorzFix1(0,10,
194 pVertFix2(0,10,
195 pControl(FEditName),
196 pControl(FButtonLogin,80,25)
197 ),
198 pControl(FEditTalking,280,310)
199 ),
200 pVertFix2(0,10,
201 pControl(FEditMessage),
202 pControl(FButtonSend,80,25)
203 )
204 )
205 );
206
207 SetClientWidth(300);
208 SetClientHeight(400);
209 SetText(L"Vczh RoaTalk Client v1.0");
210 UpdateStatus();
211 }
212 };
213
214 void main()
215 {
216 RoaForm* Form=new RoaForm;
217 Form->MoveCenter();
218 Form->Show();
219 GetApplication()->Run();
220 }
至此客户端就完成了。下面是服务器端所有代码,最后附上截图。这个截图是我的电脑上运行服务器和一个客户端,然后叫了另一个人在其他地方打开我的客户端,链接我的服务器,最后我这边显示的内容:
服务器端RoaTalk.h是服务的声明:
1 #ifndef VCZH_ROATALK_SERVICE_PROVIDER
2 #define VCZH_ROATALK_SERVICE_PROVIDER
3
4 #include "..\..\..\..\VL++\Library\Data\Inspector\VL_ObjectServer.h"
5
6 using namespace vl;
7 using namespace vl::inspector;
8
9 class RoaTalkUser;
10 class RoaTalkCallback;
11 class RoaTalkService;
12
13 /*********************************************************************************************************
14 服务
15 *********************************************************************************************************/
16
17 class RoaTalkUser : public VL_Base
18 {
19 public:
20 typedef VL_AutoPtr<RoaTalkUser> Ptr;
21 typedef VL_List<Ptr , false , RoaTalkUser*> List;
22 typedef VL_ListedMap<VUnicodeString , Ptr> StringMap;
23
24 VUnicodeString Name;
25 RoaTalkService* Owner;
26 };
27
28 class RoaTalkCallback : public VL_ObjectCallback
29 {
30 public:
31 virtual void Say(RoaTalkUser::Ptr User , VUnicodeString Message);
32 virtual void Login(RoaTalkUser::Ptr User);
33 virtual void Logout(RoaTalkUser::Ptr User);
34 virtual void Rename(VUnicodeString OldName , RoaTalkUser::Ptr User);
35 };
36
37 class RoaTalkService : public VL_ObjectService
38 {
39 protected:
40 VUnicodeString FName;
41 RoaTalkCallback* FCallback;
42
43 void Initialize();
44 public:
45 typedef VL_List<RoaTalkService* , true> List;
46
47 RoaTalkService();
48 ~RoaTalkService();
49
50 RoaTalkCallback* GetCallback();
51
52 VUnicodeString GetCurrentName();
53 VBool SetCurrentName(VUnicodeString Name);
54 void Say(VUnicodeString Message);
55 VL_AutoPtr<RoaTalkUser::List> GetUsers();
56 };
57
58 class RoaTalkServer : public VL_Base
59 {
60 protected:
61 RoaTalkUser::StringMap FUsers;
62 VL_SynCriticalSection FServerLock;
63 public:
64 RoaTalkServer();
65 ~RoaTalkServer();
66
67 VBool CreateUser(VUnicodeString Name , RoaTalkService* Service);
68 VBool DestroyUser(VUnicodeString Name);
69 VBool RenameUser(VUnicodeString OldName , VUnicodeString NewName);
70 VL_AutoPtr<RoaTalkUser::List> GetUsers();
71 VBool Say(VUnicodeString Name , VUnicodeString Message);
72 };
73
74 extern void CreateRoaTalkServer();
75 extern void DestroyRoaTalkServer();
76 extern RoaTalkServer* GetRoaTalkServer();
77
78 /*********************************************************************************************************
79 注册
80 *********************************************************************************************************/
81
82 VL_BEGIN_INSPECTOR_DECLARATION
83
84 VL_BEGIN_BASE_CLASS(RoaTalkUser)
85 VL_ADD_CLASS_MEMBER(Name)
86 VL_END_CLASS(RoaTalkUser)
87
88 VL_BEGIN_CALLBACK(RoaTalkCallback)
89 VL_ADD_CLASS_METHOD(Say)
90 VL_METHOD_PARAMETER(User)
91 VL_METHOD_PARAMETER(Message)
92
93 VL_ADD_CLASS_METHOD(Login)
94 VL_METHOD_PARAMETER(User)
95
96 VL_ADD_CLASS_METHOD(Logout)
97 VL_METHOD_PARAMETER(User)
98
99 VL_ADD_CLASS_METHOD(Rename)
100 VL_METHOD_PARAMETER(OldName)
101 VL_METHOD_PARAMETER(User)
102 VL_END_CLASS(RoaTalkCallback)
103
104 VL_BEGIN_DUAL_SERVICE(RoaTalkService,RoaTalkCallback)
105 VL_ADD_CLASS_METHOD(GetCurrentName)
106
107 VL_ADD_CLASS_METHOD(SetCurrentName)
108 VL_METHOD_PARAMETER(Name)
109
110 VL_ADD_CLASS_METHOD(Say)
111 VL_METHOD_PARAMETER(Message)
112
113 VL_ADD_CLASS_METHOD(GetUsers)
114 VL_END_CLASS(RoaTalkService)
115
116 VL_EXTERN_INSPECTOR_MANAGER(RoaTalk)
117
118 VL_END_INSPECTOR_DECLARATION
119
120 #endif
然后是它的实现:
1 #include "RoaTalk.h"
2 #include "RoaTalk_Callback.h"
3
4 extern void PrintNotify(VUnicodeString Message);
5
6 /*********************************************************************************************************
7 RoaTalkCallback
8 *********************************************************************************************************/
9
10 void RoaTalkCallback::Say(RoaTalkUser::Ptr User , VUnicodeString Message)
11 {
12 }
13
14 void RoaTalkCallback::Login(RoaTalkUser::Ptr User)
15 {
16 }
17
18 void RoaTalkCallback::Logout(RoaTalkUser::Ptr User)
19 {
20 }
21
22 void RoaTalkCallback::Rename(VUnicodeString OldName , RoaTalkUser::Ptr User)
23 {
24 }
25
26 /*********************************************************************************************************
27 RoaTalkService
28 *********************************************************************************************************/
29
30 void RoaTalkService::Initialize()
31 {
32 FCallback=CreateCallbackObject<RoaTalkCallbackProxy>();
33 }
34
35 RoaTalkService::RoaTalkService()
36 {
37 FCallback=0;
38 VInt i=1;
39 while(true)
40 {
41 VUnicodeString Name=L"Guest "+VUnicodeString(i++);
42 if(GetRoaTalkServer()->CreateUser(Name,this))
43 {
44 FName=Name;
45 break;
46 }
47 }
48 }
49
50 RoaTalkService::~RoaTalkService()
51 {
52 GetRoaTalkServer()->DestroyUser(FName);
53 delete FCallback;
54 }
55
56 RoaTalkCallback* RoaTalkService::GetCallback()
57 {
58 return FCallback;
59 }
60
61 VUnicodeString RoaTalkService::GetCurrentName()
62 {
63 return FName;
64 }
65
66 VBool RoaTalkService::SetCurrentName(VUnicodeString Name)
67 {
68 if(GetRoaTalkServer()->RenameUser(FName,Name))
69 {
70 FName=Name;
71 return true;
72 }
73 else
74 {
75 return false;
76 }
77 }
78
79 void RoaTalkService::Say(VUnicodeString Message)
80 {
81 GetRoaTalkServer()->Say(FName,Message);
82 }
83
84 VL_AutoPtr<RoaTalkUser::List> RoaTalkService::GetUsers()
85 {
86 return GetRoaTalkServer()->GetUsers();
87 }
88
89 /*********************************************************************************************************
90 RoaTalkServer
91 *********************************************************************************************************/
92
93 RoaTalkServer::RoaTalkServer()
94 {
95 }
96
97 RoaTalkServer::~RoaTalkServer()
98 {
99 }
100
101 VBool RoaTalkServer::CreateUser(VUnicodeString Name , RoaTalkService* Service)
102 {
103 VBool Result=false;
104 FServerLock.Enter();
105 if(!FUsers.Exists(Name))
106 {
107 VL_AutoPtr<RoaTalkUser> Talker=new RoaTalkUser;
108 Talker->Name=Name;
109 Talker->Owner=Service;
110 FUsers.Add(Name,Talker);
111 Result=true;
112
113 for(VInt i=0;i<FUsers.KeyCount();i++)
114 {
115 if(FUsers.KeyOfIndex(i)!=Name)
116 {
117 try
118 {
119 FUsers.ValueOfIndex(i)->Owner->GetCallback()->Login(Talker);
120 }
121 catch()
122 {
123 }
124 }
125 }
126
127 PrintNotify(Name+L" logged in.");
128 }
129 FServerLock.Leave();
130 return Result;
131 }
132
133 VBool RoaTalkServer::DestroyUser(VUnicodeString Name)
134 {
135 VBool Result=false;
136 FServerLock.Enter();
137 if(FUsers.Exists(Name))
138 {
139 RoaTalkUser::Ptr Talker=FUsers[Name];
140 FUsers.Delete(Name);
141 Result=true;
142
143 for(VInt i=0;i<FUsers.KeyCount();i++)
144 {
145 try
146 {
147 FUsers.ValueOfIndex(i)->Owner->GetCallback()->Logout(Talker);
148 }
149 catch()
150 {
151 }
152 }
153
154 PrintNotify(Name+L" logged out.");
155 }
156 FServerLock.Leave();
157 return Result;
158 }
159
160 VBool RoaTalkServer::RenameUser(VUnicodeString OldName , VUnicodeString NewName)
161 {
162 VBool Result=false;
163 FServerLock.Enter();
164 if(FUsers.Exists(OldName) && !FUsers.Exists(NewName))
165 {
166 RoaTalkUser::Ptr Talker=FUsers[OldName];
167 FUsers.Delete(OldName);
168 Talker->Name=NewName;
169 FUsers.Add(NewName,Talker);
170 Result=true;
171
172 for(VInt i=0;i<FUsers.KeyCount();i++)
173 {
174 if(FUsers.KeyOfIndex(i)!=NewName)
175 {
176 try
177 {
178 FUsers.ValueOfIndex(i)->Owner->GetCallback()->Rename(OldName,Talker);
179 }
180 catch()
181 {
182 }
183 }
184 }
185
186 PrintNotify(OldName+L" renamed to "+NewName+L".");
187 }
188 FServerLock.Leave();
189 return Result;
190 }
191
192 VL_AutoPtr<RoaTalkUser::List> RoaTalkServer::GetUsers()
193 {
194 RoaTalkUser::List* Result=new RoaTalkUser::List();
195 FServerLock.Enter();
196 for(VInt i=0;i<FUsers.KeyCount();i++)
197 {
198 Result->Add(FUsers.ValueOfIndex(i));
199 }
200 FServerLock.Leave();
201 return Result;
202 }
203
204 VBool RoaTalkServer::Say(VUnicodeString Name , VUnicodeString Message)
205 {
206 VBool Result=false;
207 FServerLock.Enter();
208 if(FUsers.Exists(Name))
209 {
210 RoaTalkUser::Ptr Talker=FUsers[Name];
211 Result=true;
212
213 for(VInt i=0;i<FUsers.KeyCount();i++)
214 {
215 if(FUsers.KeyOfIndex(i)!=Name)
216 {
217 try
218 {
219 FUsers.ValueOfIndex(i)->Owner->GetCallback()->Say(Talker,Message);
220 }
221 catch()
222 {
223 }
224 }
225 }
226
227 PrintNotify(Name+L" says \""+Message+L"\".");
228 }
229 FServerLock.Leave();
230 return Result;
231 }
232
233 /*********************************************************************************************************
234 工具函数
235 *********************************************************************************************************/
236
237 RoaTalkServer* GlobalServer=0;
238
239 void CreateRoaTalkServer()
240 {
241 GlobalServer=new RoaTalkServer;
242 }
243
244 void DestroyRoaTalkServer()
245 {
246 delete GlobalServer;
247 GlobalServer=0;
248 }
249
250 RoaTalkServer* GetRoaTalkServer()
251 {
252 return GlobalServer;
253 }
254
255 /*********************************************************************************************************
256 注册
257 *********************************************************************************************************/
258
259 VL_BEGIN_INSPECTOR_DECLARATION
260
261 VL_BEGIN_INSPECTOR_MANAGER(RoaTalk)
262 VL_REGISTER_SERVICE_CLASSES
263
264 VL_BIND_INSPECTOR(RoaTalkUser)
265 VL_BIND_INSPECTOR(RoaTalkCallback)
266 VL_BIND_INSPECTOR(RoaTalkService)
267 VL_END_INSPECTOR_MANAGER
268
269 VL_END_INSPECTOR_DECLARATION
接下来就剩下花边Feature了。使用这个东西可以开发一些C/S模式的程序,然后只需要将服务器和客户端看成同一个程序,将客户端认为是很多个线程就行了。服务器端提供一些类给客户端创建并使用,当这些服务类要求回调的时候,客户端只需要按照回调的接口实现回调,然后将指针提供给服务类就行了。剩下来的链接啊调度啊网络传输的问题就全部不用管了,非常方便。
posted on 2009-07-17 18:20
陈梓瀚(vczh) 阅读(3623)
评论(10) 编辑 收藏 引用 所属分类:
C++