随笔-341  评论-2670  文章-0  trackbacks-0

    今天展示一下如何使用这里描写的库实现一个简单的聊天工具。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) 阅读(3596) 评论(10)  编辑 收藏 引用 所属分类: C++

评论:
# re: C++远程调用类操作支持Callback Interface 2009-07-17 19:01 | 99读书人
不错 来学习了  回复  更多评论
  
# re: C++远程调用类操作支持Callback Interface 2009-07-17 19:33 | 奋斗
无聊  回复  更多评论
  
# re: C++远程调用类操作支持Callback Interface 2009-07-17 23:10 | SOS
拍手  回复  更多评论
  
# re: C++远程调用类操作支持Callback Interface 2009-07-18 05:00 | 彭小虎(Tigerkin)
瓦哈哈哈哈哈哈  回复  更多评论
  
# re: C++远程调用类操作支持Callback Interface 2009-07-18 06:27 | 空明流转
很好,很强大,很幽默。  回复  更多评论
  
# re: C++远程调用类操作支持Callback Interface 2009-07-19 06:43 | Gohan
真的很强大  回复  更多评论
  
# re: C++远程调用类操作支持Callback Interface 2009-07-20 04:08 | 移动12530彩铃
阿斯顿~哈哈!  回复  更多评论
  
# re: C++远程调用类操作支持Callback Interface 2009-07-27 05:13 | shz
我发现微软的人都很爱说feature这个词……娃哈哈  回复  更多评论
  
# re: C++远程调用类操作支持Callback Interface 2010-07-01 00:48 |
说实话...我真的非常讨厌用宏来着...能不用尽量不用。
看到LZ用宏来定义消息和回调的地方时...有种瞬间给浇了一盆水的感觉。  回复  更多评论
  
# re: C++远程调用类操作支持Callback Interface 2010-07-01 01:04 | 陈梓瀚(vczh)
@酿
这是为了可以自动生成client的代码。就忍忍吧。我这做的是你写server的class,我的类库帮你写client。不这么干怎么干,除非你人写,或者用doxygen的那种办法。当然这玩意儿对我来说已经是过时的了,你不需要在意他。  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理