MFC NETWORK COMMUNICATION + WEB BROWSING

NETWORK COMMUNICATION BETWEEN COMPUTERS WITH TCP/IP

Apps running on different computers can communicate with each other
Server App: Waits for other apps on other computers to open a communication connection
Client App: Attempts to open a connection
When connection is established, data can be exchanged
Either can close the communication

Connections:
    Two programs running on different computers form a connection
    Data is sent and received along the connection

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"
        There's a socket at each end of the connection
   Windows support for sockets: in the Winsock API
   MFC encapsulates this in the CAsyncSocket base class
        Provides complete, event-driven socket communications
        Lowest level support
        Higher level support from derived classes like CSocket

Making a socket connection to another app:
   Specify IP address of computer the other app is running on
       Identifies a machine
   Also specify the port the app listening on
       Identifies the program that should handle the communication
           E.g. port 80 for web document transfers
   Like telephone communication: (Dial number and extension)


CAsyncSocket class support:

 Provides for complete event-driven network communication
 Facilitates creation of sockets & establishing/closing connections
 Manages data transfer

 We can define our own m_sock class derived from CAsyncSocket
 Objects constructed from this class will have socket functionality
 Use 2 AsyncSocket objects: m_L (listening socket) & m_C (communication data socket) 

Creating a Socket:
   Server:  m_L.Create(listen port #);  // A Listening socket
   Client:  m_C.Create();                      // Client Connection socket for Data
   Server:  m_C                                     // Server Connecton socket for Data

Making a Connection:
   Server:  m_L.Listen();
   Client:  m_C.Connect("IPnameOrAddress", port #);
   Server:  m_L.Accept(m_C);  // Creates the server side m_C Connection socket for Data

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

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


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

<Show Powerpoint here>

Socket “Msg Handler” Virtual Functions:    Socket “Action” Functions:
Override--                                 Call at correct times--   
   Connection accepted --> OnConnect()        Create()   
   Request connection -->  OnAccept()         Listen()  -- server
   Data received -->  OnReceive()                     Connect() -- client
   Close connections --> OnClose()                    Accept()  -- server
                                                      Send()    
                                                      Receive()
                                                      Close()

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 messages over the network
   In response it must call functions defined in its parent dialog box class
   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()
   OnClose()


Preparing the ServeSock Server App (details)

MFC AppWizard Dialog-based application
Under "Advanced Features" check "Windows Sockets"

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

Attach 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

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
   In Classview, right click on top node (ServeSock Classes)
   Select: Add, Add Class; Select MFC, MFC 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;

In properties window of CMySock add event override functions:
   OnAccept(int nErrorCode)
   OnReceive(int nErrorCode)
   OnClose(int nErrorCode)
      For each, parameter in declaration should be:  int nErrorCode

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::OnInitDialog() function:
   // TODO: Add extra initialization here
   m_iPort=4000;  //unused port number
   UpdateData(FALSE);  //send data to controls
   m_datasock.SetParent(this);   //the 2 MySocket objects
   m_listensock.SetParent(this);

Edit  CServeSockDlg::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::OnAccept():
  m_listensock.Accept(m_datasock); //accept connection, create data socket

Edit  CServeSockDlg::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::OnReceive():
   char *pBuf = new char[1025];
   int iBufSize=1024;
   int iRecvd;
   CString sRecvd;

   iRecvd=m_datasock.Receive(pBuf,iBufSize); //get strng 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::OnClose():
   m_datasock.Close();  //close the data socket

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

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() function 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.


WINDOWS WEB BROWSING & HYPERTEXT MARKUP LANGUAGE (HTML) 

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()
   GoForward()
   GoHome()
   GoSearch()
   Stop()
   Refresh()
   LoadFromResource()
   CString GetLocationURL()
   BOOL GetBusy()

Adding DHTML Documents to Windows Programs:
   1. As a resource:
         Project / Add Resource / HTML / New / 
         Then right click to get to "View HTML Source"
         Then enter html script
         Finally in code, Load HTML resource using LoadFromResource()
   2. Or Load from a file:
         Navigate("file_name")
   3. Or Download from a remote site
         Navigate("URL")

HtmlSample Application <Show program in action>
Allows user to browse the web:
   Go to home page
   Navigate to a URL entered in a dialog box
   Load a web page from a file using the common file dialog box
   Load a web page whose html is defined in the program's resources



MFC AppWizard, SDI Application
In "User Features" select "Standard Docking" and "Browser Style" under Toolbars
In "Generated Classes" select CHtmlView as the base class for CHtmlSampleView

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

Insert Simple HTML page resource:
   Project / Add / Resource / HTML / New
   Right click and select "View HTML Source"

   Enter something like the following text in the editor window:
   <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:

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

Add a new Dialog box class:
   CUrlDlg based on CDialog

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:
   ID_BROWSE_URL:  OnBrowseUrl()
   ID_BROWSE_FILE:  OnBowseFile()
   ID_BROWSE_HOME:  OnBrowseHome()
   ID_BROWSE_RESOURCE:  OnBrowseResource()

Edit each of the handler functions:

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

OnBowseFile():
        // 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);
      }

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

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

Edit the code in OnInitialUpdate()
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, perhaps your home page

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