December 19, 2014
Hot Topics:

Developing Efficient Network and Distributed Applications with ACE, Part 2

  • November 10, 2004
  • By Mugdha Vairagade
  • Send Email »
  • More Articles »

Registering a new user

When the button for new user registration is clicked, the application GUI asks for new username and password entries. When appropriate input for the same is submitted, the application creates a Connector object of type CLogConnector.

Figure 4: New user registration Dialog

Then CLogConnector actively establishes a connection with CNewUserAcceptor on the server side. Both CLogConnector and CNewUserAcceptor create service handlers CNewUserLogHandler and CNewUserHandler, respectively.

Code: Source code from file NewUserDlg.cpp

typedef ACE_Connector<CNewUserLogHandler,ACE_SOCK_CONNECTOR>
        CLogConnector;
static  const char *const SERVER_HOST = ACE_DEFAULT_SERVER_HOST;
   ----
   ---
   ACE_INET_Addr addr(NEWUSER_PORT,SERVER_HOST);
   CNewUserLogHandler *pSrvHandler = new CNewUserLogHandler(this);
   CLogConnector logCon;
   logCon.open();
   if (logCon.connect(pSrvHandler,addr) == -1)
   {
      AfxMessageBox("Error: connection failed");
      return;
   }

Once the connection is established, the Service Handler objects on both sides start communicating with each other. The CNewUserLogHandler sends the username and password to CNewUserHandler.

Code: Source code from file BlogClient.h

#define USERNAME_LENGTH     255

Code: Source code from file NewUserDlg.h

#define NEWUSER_DATA_LENGTH 512

Code: Source code from file NewUserDlg.cpp

   char* pstrBuffer = NULL;
   pstrBuffer = new char[NEWUSER_DATA_LENGTH];
   strcpy(pstrBuffer,m_strUser.operator LPCTSTR());
   pstrBuffer+=USERNAME_LENGTH;
   strcpy(pstrBuffer,m_strPsw.operator LPCTSTR());
   pstrBuffer-=USERNAME_LENGTH;
   pSrvHandler->peer().send_n (pstrBuffer,NEWUSER_DATA_LENGTH);
   delete []pstrBuffer;

CNewUserHandler checks for the availability of the username and sends the status message back to CNewUserLogHandler and closes the communication by calling its close() function.

Code: Source code from file NewUserHandler.cpp

char strNewUserData[NEWUSER_DATA_LENGTH];
   char strStatus[STATUS_DATA_LENGTH];
   CLogin LogObj;

   peer().recv_n(strNewUserData,NEWUSER_DATA_LENGTH);
   if (LogObj.AddNewUser(strNewUserData))
   {
      strcpy(strStatus,STATUS_SUCCESS);
   }
   else
   {
      strcpy(strStatus,STATUS_FAIL);
   }
   this->peer().send_n(strStatus, STATUS_DATA_LENGTH);
   this->close();

The login process

To log in, the user supplies the username and password to a login dialog box, which appears when the client application is executed (refer to Figure 3: The blog client login GUI). When the user submits these entries and presses the login button, the blog client creates a connector object of type CServiceConnector. This connector object in turn creates a Service Handler object of type CSrvHandler.

Code: Source code from file UserLoginDlg.cpp

   ACE_INET_Addr addr(SERVICE_PORT,SERVER_HOST);
   CBlogClientDoc *pDoc = (CBlogClientDoc*)
                          ((CFrameWnd*)AfxGetApp()->GetMainWnd())
                          ->GetActiveDocument();
   if(!pDoc)
      return;

   pDoc->m_pSrvHandler= new CSrvHandler(pDoc);
   CServiceConnector svrCon;
   svrCon.open();
   if (svrCon.connect(pDoc->m_pSrvHandler,addr) == -1)
   {
      AfxMessageBox("Error: connection failed");
      pDoc->m_pSrvHandler = NULL;
      svrCon.close();
      return;
   }

On the server side, when CServiceAcceptor receives the connection request, it creates a Service Handler of the CServiceHandler class. Once the connection is established, this Service Handler object communicates with CSrvHandler, its remote peer on the client side. CSrvHandler sends the username and password along with a LogRequest command to CServiceHandler.

Code: Source code from file UserLoginDlg.cpp

char *pStrCommand = new char[COMMAND_LENGTH];
ZeroMemory(pStrCommand,COMMAND_LENGTH);
strcpy(pStrCommand,LOG_REQUEST_COMMAND);
pStrCommand = pStrCommand + BLOGSIZE_COMMAND_LENGTH;
sprintf(pStrCommand,"%d",USERNAME_LENGTH + PASSWRD_LENGTH);
pStrCommand = pStrCommand - BLOGSIZE_COMMAND_LENGTH;
pDoc->m_pSrvHandler->peer().send_n(pStrCommand,COMMAND_LENGTH);
delete[] pStrCommand;
char *pStrLogInfoBuf = new char[USERNAME_LENGTH + PASSWRD_LENGTH];
strcpy(pStrLogInfoBuf,m_strLogId);
pStrLogInfoBuf = pStrLogInfoBuf + USERNAME_LENGTH;
strcpy(pStrLogInfoBuf,m_strPassword);
pStrLogInfoBuf = pStrLogInfoBuf -  USERNAME_LENGTH;
pDoc->m_pSrvHandler->peer().send_n(pStrLogInfoBuf,USERNAME_LENGTH +
                                   PASSWRD_LENGTH);
delete[] pStrLogInfoBuf;

When CServiceHandler receives LogRequest command, it checks whether such a user exists or not. If not, it sends a Terminate command back to CSrvHandler and closes the connection by calling its close() function.

Code: Source code from file ServiceHandler.cpp

if(strcmp(strCommand,LOG_REQUEST_COMMAND) == 0)
{
   char *pUserBuffer = new char[nDataLen];
   peer().recv_n(pUserBuffer,nDataLen);
   //pUserBuffer = pUserBuffer + COMMAND_LENGTH;
   CLogin userLogInfo;
   char *pBlogFileName = NULL;
   pBlogFileName       = userLogInfo.CheckUser(pUserBuffer);
   m_strBlogFileName   = pBlogFileName;
   if(pBlogFileName    == NULL)
   {
      char strCommand[COMMAND_LENGTH];
      strcpy(strCommand,TERMINATE_COMMAND);
      peer().send_n(strCommand,COMMAND_LENGTH);
      close();
      return 0;
   }
}

If such a user exists, the CServiceHandler sends the blog data to CSrvHandler.

Code: Source code from file ServiceHandler.cpp

char *pBlogBuffer = NULL;
char *pCmdBuffer = new char[COMMAND_LENGTH];
char strBolgCmd[BLOG_DATA_COMMAND_LENGTH];
char strBlogLen[BLOGSIZE_COMMAND_LENGTH];
CBlog blogObj;
int nBlogLen = blogObj.ReadBuffer(pBlogFileName,pBlogBuffer);
strcpy(strBolgCmd,BLOG_DATA);
sprintf(strBlogLen,"%d",nBlogLen);
strcpy(pCmdBuffer,strBolgCmd);
pCmdBuffer = pCmdBuffer + BLOG_DATA_COMMAND_LENGTH;
strcpy(pCmdBuffer,strBlogLen);
pCmdBuffer = pCmdBuffer - BLOG_DATA_COMMAND_LENGTH;
peer().send_n(pCmdBuffer,COMMAND_LENGTH);
peer().send_n(pBlogBuffer,nBlogLen);
delete[] pBlogBuffer; 
delete[] pCmdBuffer;

On receiving blog data, the client displays it in a blog window, in which the user can make new entries or edit/delete old entries. Once the desired operation is finished, the user can save the blog entries by clicking the Save button.

Figure 5: Blog window for existing logged-in user

After that, data exchange between peer service handler objects continues as long as the user remains logged in. The user can discard changes and log off at any time, simply by closing the window. This is followed by the shutting down the peer Service Handlers and resource release.

This is how ACE enables communication between the components of a distributed application.

Gains from ACE

Now that we've learned how to implement ACE, we are ready to answer the most important question: "Why should one implement ACE at all, when there are other ways, such as sockets and TLI, are available for the same purpose?" The answer is simple: Implementing ACE for developing communication software is more advantageous than other methods. Some of the advantages are listed here:

  • The biggest gains from implementing ACE are in terms of increased portability for the application. It's possible to port an application from one platform, with minimum efforts, resources, and time, thanks to ACE's support for various platforms.
  • Another important advantage is that communication software developers need not be aware of OS communication internals for different OS platforms (or any OS platform, to be precise). ACE can be easily ported to most widely used OS platforms available today and hides complexities of the communication handling mechanism of the underlying OS by providing a standard framework for developing communication software.
  • ACE internally implements the best practices, design patterns, and strategies to enhance communication software efficiency.
  • ACE helps increase the reusability and extensibility of implementing application because it clearly decouples the connection establishment from the subsequent service initialization. This approach also makes adding new services and providing new service implementations easy.

About the Author

Mugdha Chauhan is a senior IT consultant and author. An open source supporter, she frequently writes articles and tutorials on useful emerging open source projects. Major tech portals including developer.com, IBM developerWorks, CNET Networks, Slashdot, and many eZines regularly publish her work. Her other expertise and interests include Java, Linux, XML, and wireless application development.





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel