MFC NETWORK COMMUNICATION; WEB BROWSING



NETWORK COMMUNICATION BETWEEN COMPUTERS WITH TCP/IP



Server App: Waits for other apps on other computers to open a connection
Client App: Attempts to open a connection
When connection is established, data can be exchanged

Sockets:

   Basic object used to perform network communication
   Used to read/write messages travelling between applications
   (Like a file pointer in file I/O)
   A communication "endpoint"
   Windows support for sockets in the Winsock API
   MFC encapsulates this in the CAsyncSocket base class
      Provides complete, event-driven socket communications

Making a socket connection to another app:

   Specify IP address of computer other app is running on
   and the port it's listening on
      Like telephone communication:
         (Dial number and extension)

CAsyncSocket class support:

   Can define our own derived m_sock class
   Objects constructed from this class will have socket functionality
   Assume objects: m_sock (listening socket) & m_dsock (data socket) 

Creating a Socket:

   Server:  m_sock.Create(listen port #);
   Client:  m_dsock.Create();

Making a Connection:

   Server:  (Step 1)  m_sock.Listen();
            (Step 2)  m_sock.Accept(m_dsock);
   Client:  m_dsock.Connect("IPnameOrAddress", port #)

   Server is listening
   Connection attempt--> "request connection messsage" event to server
      Event triggers call to Server's overridable m_sock.OnAccept()
      ==>It should call its Accept(m_dsock) method
          ==>data socket is created automatically & connected to client
      Result: "connection accepted msg" event to client (he can now send)
          Event triggers call to Client's overridable m_dsock.OnConnect()

Sending/receiving text data:
   Sender invokes m_d.Send(lpszDataSring,length)
   When data is received, receiver gets "data received msg" event
       Event triggers call to receiver's overridable m_dsock.OnReceive() method
       ==> Receiver should invoke m_dsock.Receive(lpszBuf,length)
               Fills the buffer with the received data

Closing a connection:
   Either party can invoke m_dsock.Close()
   ==>other party gets "close connection msg" event
             Event triggers call to overridable to m_dsock.OnClose()
             ==>Should call m_dsock.Close()
                    Sends a "close connection msg" event to other party...
                    who should do the same thing


ClientSock and ServeSock Applications <Show programs in action>
   MFC AppWizard Dialog-based applications










After network connection is made, either can send or receive strings

Need to define CMySock class derived from CAsyncSocket
   m_sock object from this class will be receiving msgs over the network
   In response it must call functions defined in its parent dialog box
   So need member variable that points to the parent window:
      CDialog  m_pWnd
   Need member function that will provide the parent window pointer:

      void CMySock::SetParent(CDialog  *pWnd)
      {
          m_pWnd = pWnd;
      }  

Must override the following base class virtual member functions
(Want corresponding functions to be called in parent dialog box)
   OnConnect()   <Client only>
   OnAccept()    <Server only>
   OnReceive()
   OnSend()
   OnClose()






Preparing the ServeSock Server App (details)

MFC AppWizard Dialog-based application
Be sure to include "Support for Windows Sockets" (Step 2)

Controls:

Static Control:  "ListenPort"
Single-line Edit box:  IDC_ESERVPORT
Button:  "Connect", IDC_BCONNECT
Button:  "Send", IDC_BSEND
Button:  "Close", IDC_BCLOSE
Static Control:  "Message:"
Single-line Edit box:  IDC_EMSG
Static Control:  "Sent:"
List box:  IDC_LSENT
Static Control:  "Received:"
List box:  IDC_LRECVD

Use ClassWizard to add variables to the controls:

IDC_EMSG:  m_sMsg, Value, CString
IDC_ESERVPORT:  m_iPort, Value, int
IDC_LRECVD:  m_cRecvd, Control, CListBox
IDC_LSENT:  m_cSent, Control, CListBox

Use ClassWizard to add Message Map handler functions for
BN_CLICK messages for each new button:
   IDC_BCONNECT --> OnBconnect()
   IDC_BSEND --> OnBsend()
   IDC_BCLOSE --> OnBclose()

Create the Socket Class:  CMySock
   Right Click on Parent folder (ServeSock Classes) in Classview
   Select: New Class, Name: CMySock, Base Class: CAsyncSocket

Add private member variable to CMySock:
   name: m_pWnd
   type: CDialog*

Add public member function to CMySock:
   void SetParent(CDialog* pWnd) 

Edit SetParent() by adding the line:
   m_pWnd = pWnd;

Add protected void member functions to override virtual functions in CMySock for:
   OnAccept(int nErrorCode)
   OnReceive(int nErrorCode)
   OnClose(int nErrorCode)
      For each, parameter in declaration should be:  int nErrorCode
      Make sure "virtual" check box is checked

Edit each of these new functions following pattern of OnAccept() given here:
   void CMySock::OnAccept(int nErrorCode)
   {
        if(nErrorCode==0)
                 //Call parent dialog's OnAccept() function
                ((CServeSockDlg*)m_pWnd)->OnAccept();
   }

Include the header file for the dialog box in new CMySock class:
    #include "ServeSockDlg.h"  in MySock.cpp

Add two private CMySock variables to CServeSockDlg class:
   m_listensock
   m_datasock

Add the following public void member functions to CServeSockDlg class:
   OnAccept()
   OnReceive()
   OnClose()

Add initialization code to CServeSockDlg's OnInitDialog() function:
        // TODO: Add extra initialization here
        m_iPort=3000;  //unused port number
        UpdateData(FALSE);  //send data to controls
        m_datasock.SetParent(this);   //the 2 MySocket objects
        m_listensock.SetParent(this);

Edit CServeSockDlg's OnBConnect() handler function:
        // TODO: Add your control notification handler code here
        UpdateData(TRUE);  //get string from control
        m_listensock.Create(m_iPort);  //create socket
        m_listensock.Listen();         //listen on socket

Edit CServeSockDlg's OnAccept():
        m_listensock.Accept(m_datasock);  //accept connection, create data socket

Edit CServeSockDlg's OnBSend():
        // TODO: Add your control notification handler code here
        int iLen;
        int iSent;
        UpdateData(TRUE);  //get string from control
        if (m_sMsg!="")
        {                                //send it out the socket
                iLen=m_sMsg.GetLength();
                iSent=m_datasock.Send(LPCTSTR(m_sMsg),iLen);
                if (iSent==SOCKET_ERROR)
                {MessageBox("Server send error");}
                else
                {              //add string to Sent box
                        m_cSent.AddString(m_sMsg);
                        UpdateData(FALSE);  //send data to control
                }
        }

Edit CServeSockDlg's OnReceive():
        char *pBuf = new char[1025];
        int iBufSize=1024;
        int iRecvd;
        CString sRecvd;
        iRecvd=m_datasock.Receive(pBuf,iBufSize); //get string from socket
        if(iRecvd==SOCKET_ERROR)
        {}
        else
        {              //add string to Received box
                pBuf[iRecvd]=0;  //terminating NULL
                sRecvd=pBuf;
                m_cRecvd.AddString(sRecvd);
                UpdateData(FALSE);  //send data to control
        }

Edit CServeSockDlg's OnClose():
        m_datasock.Close();  //close the data socket

Edit CServeSockDlg's OnBclose():
        OnClose();   //call function that closes the data socket

Build the application
Enhancing the ServeSock App--
    Disable and disable the "Connect", "Send", & "Close" buttons...
    and the "Message" and "Listen Port" Edit controls...
    at the appropriate times--
        Add Control variables:
            m_cConnect to IDC_BCONNECT button
            m_cSend to IDC_BSEND button
            m_cClose to IDC_BCLOSE button
            m_cMsg to IDC_EMSG edit control
            m_cPort to IDC_ESERVPORT edit control
        and invoke their EnableWindow (TRUE/FALSE) functions at correct times.
Preparing the ClientSock Client Application

Most of project same as ServerSock

Some Differences:

   Dialog box needs "Server Name" Edit Control:
   (So user can specify DNS name or IP address & enable/disable it)

   Only need one CMySock object: m_datasock

   OnInitDialog() should be changed--extra initialization

   Need an OnConnect() function instead of OnAccept()
   
   OnBConnect() will be changed
      
   OnClose() will be changed
      
Running the ServeSock and ClientSock:

Applications will only work if computer(s) have TCP/IP installed and configured correctly

Be sure the Server connects before a client tries to connect

Test first with both applications on the same machine
   Servername = "loopback" (default as programmed)
Then try with server on one machine and client on another
   Client must enter:
       correct "name" or "IP address" of computer server is running on
       Port number Server is listening on
One problem: The server application can handle only one connection at  time.
A second application trying to connect to connected server will cause server to crash.
One soution: A third socket object could be used to send a rejection message to other 
clients attempting to connect if another client is still connected.


HyperText Markup Language (HTML) and Web Browsing in Windows

MFC Support for Web Browsing
New in VC++ 6

HTML--
   Scripting Language to create Web Pages

VC++ Support for HTML--
   WebBrowser Control
      ActiveX component provides access to Inernet Explorer browsing    components  
   MFC CHtmlView class
      Wraps WebBrowser control into package that fits into Doc/View arch.
      Provides easy access to Internet Explorers functions
      Views derived from CHtmlView are basic Web browser windows
      Requires Microsoft Internet Explorer 4.0 (or later) installed

Some CHtmlView member functions:
   Navigate ("URL")
   GoBack()
   GoHome()
   GoSearch()
   Stop()
   Refresh()
   LoadFromResource()
   CString GetLocationURL()
   BOOL GetBusy()

Adding DHTML Documents to Windows Programs:
   1. As a resource
      Insert / Resource / HTML / New / Enter HTML Script
      Load using LoadFromResource()
   2. Load from a file
      Navigate("file_name")
   3. Download from a remote site
      Navigate("URL")

HtmlSample Application <Show program in action>



MFC AppWizard, SDI Application
Step 6 (checkered flag):
   Select View Class (HtmlSampleView)
   Select CHtmlView from Base Class combo box
   Click Finish & OK

Add Pop-up Menu Item "Browse" with items:
   "URL":      IDM_URL   (-->Dialog box w/ edit control to enter URL)
   "File":     IDM_FILE  (--> Common file dialog box to get file name)
   "Home":     IDM_HOME  (--> Go to browser's home page)
   "Resource": IDM_RES   (--> Load html page from pgm's resources)

Insert Simple HTML page resource:
   Insert / Resource / HTML / New

   Add something like the following text to the editor window that appears:
   <html>
   <body>
   <h3> This page was stored as a resource for this program</h3>
   <h2> My favorite Web page is:</h2>
   <A HREF="http://www.binghamton.edu">
        Binghamton University Home Page</>
   </body>
   </html>

   This will generate resource IDR_HTML1 in a file called html1.htm

Insert a "URL" Dialog Box Resource (IDD_URL_DLG):

   Static Control:  "Enter URL"
   Edit Box:  "IDC_EURL

Use ClassWizard to add a new Dialog box class:
   CUrlDlg based on CDialog

Use ClassWizard to add a CString member variable to CUrlDlg:
   IDC_EURL:  variable name = m_EURL

Use ClassWizard to add menu command message map handler functions in CHtmlSampleView:
   IDM_URL:   OnUrl()
   IDM_FILE:  OnFile()
   IDM_HOME:  OnHome()
   IDM_RES:   OnRes()

Edit each of the handler functions:

OnUrl():
        // TODO: Add your command handler code here
        CUrlDlg dlg;
        if (dlg.DoModal()==IDOK)  //Invoke URL dialog box
                Navigate(dlg.m_eURL);

OnFile():
        // TODO: Add your command handler code here
        CFileDialog fdlg(TRUE);
        CString sFileName;
        if (fdlg.DoModal()==IDOK)   //Invoke common file dlg box
      {
                sFileName=fdlg.GetPathName();  //Get file name
                Navigate(sFileName);
      }

OnHome():
        // TODO: Add your command handler code here
        GoHome();

OnRes():
        // TODO: Add your command handler code here
        LoadFromResource(IDR_HTML1);    

Edit the code in OnInitialUpdate()
(The hardcoded Microsoft VC++ initial URL has moved!)
Change the line:
        Navigate2(_T("http://www.microsoft.com/visualc/"),NULL,NULL);
to:
        Navigate("http://www.SomeValidURL");       
Here SomeValidURL would be some web address you know is OK

Add #include "UrlDlg.h" near top of htmlSampleView.cpp

Build and run the application--
Make sure you're connected to the Internet
Computer must have Microsoft Internet Explorer installed