今天展示一下如何使用這里描寫的庫實現一個簡單的聊天工具。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) 閱讀(3652)
評論(10) 編輯 收藏 引用 所屬分類:
C++