home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / samples / sockets / server.cpp < prev    next >
C/C++ Source or Header  |  2002-09-01  |  12KB  |  419 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        server.cpp
  3. // Purpose:     Server for wxSocket demo
  4. // Author:      Guillermo Rodriguez Garcia <guille@iies.es>
  5. // Modified by:
  6. // Created:     1999/09/19
  7. // RCS-ID:      $Id: server.cpp,v 1.15 2002/08/31 22:30:58 GD Exp $
  8. // Copyright:   (c) 1999 Guillermo Rodriguez Garcia
  9. // Licence:     wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ==========================================================================
  13. // declarations
  14. // ==========================================================================
  15.  
  16. // --------------------------------------------------------------------------
  17. // headers
  18. // --------------------------------------------------------------------------
  19.  
  20. #if defined(__GNUG__) && !defined(__APPLE__)
  21. #  pragma implementation "server.cpp"
  22. #  pragma interface "server.cpp"
  23. #endif
  24.  
  25. // For compilers that support precompilation, includes "wx/wx.h".
  26. #include "wx/wxprec.h"
  27.  
  28. #ifdef __BORLANDC__
  29. #  pragma hdrstop
  30. #endif
  31.  
  32. // for all others, include the necessary headers
  33. #ifndef WX_PRECOMP
  34. #  include "wx/wx.h"
  35. #endif
  36.  
  37. #include "wx/socket.h"
  38.  
  39. // --------------------------------------------------------------------------
  40. // resources
  41. // --------------------------------------------------------------------------
  42.  
  43. // the application icon
  44. #if defined(__WXGTK__) || defined(__WXX11__) || defined(__WXMOTIF__) || defined(__WXMAC__)
  45. #  include "mondrian.xpm"
  46. #endif
  47.  
  48. // --------------------------------------------------------------------------
  49. // classes
  50. // --------------------------------------------------------------------------
  51.  
  52. // Define a new application type
  53. class MyApp : public wxApp
  54. {
  55. public:
  56.   virtual bool OnInit();
  57. };
  58.  
  59. // Define a new frame type: this is going to be our main frame
  60. class MyFrame : public wxFrame
  61. {
  62. public:
  63.   MyFrame();
  64.   ~MyFrame();
  65.  
  66.   // event handlers (these functions should _not_ be virtual)
  67.   void OnQuit(wxCommandEvent& event);
  68.   void OnAbout(wxCommandEvent& event);
  69.   void OnServerEvent(wxSocketEvent& event);
  70.   void OnSocketEvent(wxSocketEvent& event);
  71.  
  72.   void Test1(wxSocketBase *sock);
  73.   void Test2(wxSocketBase *sock);
  74.   void Test3(wxSocketBase *sock);
  75.  
  76.   // convenience functions
  77.   void UpdateStatusBar();
  78.  
  79. private:
  80.   wxSocketServer *m_server;
  81.   wxTextCtrl     *m_text;
  82.   wxMenu         *m_menuFile;
  83.   wxMenuBar      *m_menuBar;
  84.   bool            m_busy;
  85.   int             m_numClients;
  86.  
  87.   // any class wishing to process wxWindows events must use this macro
  88.   DECLARE_EVENT_TABLE()
  89. };
  90.  
  91. // --------------------------------------------------------------------------
  92. // constants
  93. // --------------------------------------------------------------------------
  94.  
  95. // IDs for the controls and the menu commands
  96. enum
  97. {
  98.   // menu items
  99.   SERVER_QUIT = 1000,
  100.   SERVER_ABOUT,
  101.  
  102.   // id for sockets
  103.   SERVER_ID,
  104.   SOCKET_ID
  105. };
  106.  
  107. // --------------------------------------------------------------------------
  108. // event tables and other macros for wxWindows
  109. // --------------------------------------------------------------------------
  110.  
  111. BEGIN_EVENT_TABLE(MyFrame, wxFrame)
  112.   EVT_MENU(SERVER_QUIT,  MyFrame::OnQuit)
  113.   EVT_MENU(SERVER_ABOUT, MyFrame::OnAbout)
  114.   EVT_SOCKET(SERVER_ID,  MyFrame::OnServerEvent)
  115.   EVT_SOCKET(SOCKET_ID,  MyFrame::OnSocketEvent)
  116. END_EVENT_TABLE()
  117.  
  118. IMPLEMENT_APP(MyApp)
  119.  
  120.  
  121. // ==========================================================================
  122. // implementation
  123. // ==========================================================================
  124.  
  125. // --------------------------------------------------------------------------
  126. // the application class
  127. // --------------------------------------------------------------------------
  128.  
  129. bool MyApp::OnInit()
  130. {
  131.   // Create the main application window
  132.   MyFrame *frame = new MyFrame();
  133.  
  134.   // Show it and tell the application that it's our main window
  135.   frame->Show(TRUE);
  136.   SetTopWindow(frame);
  137.  
  138.   // Success
  139.   return TRUE;
  140. }
  141.  
  142. // --------------------------------------------------------------------------
  143. // main frame
  144. // --------------------------------------------------------------------------
  145.  
  146. // frame constructor
  147.  
  148. MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, -1,
  149.                              _("wxSocket demo: Server"),
  150.                              wxDefaultPosition, wxSize(300, 200))
  151. {
  152.   // Give the frame an icon
  153.   SetIcon(wxICON(mondrian));
  154.  
  155.   // Make menus
  156.   m_menuFile = new wxMenu();
  157.   m_menuFile->Append(SERVER_ABOUT, _("&About...\tCtrl-A"), _("Show about dialog"));
  158.   m_menuFile->AppendSeparator();
  159.   m_menuFile->Append(SERVER_QUIT, _("E&xit\tAlt-X"), _("Quit server"));
  160.  
  161.   // Append menus to the menubar
  162.   m_menuBar = new wxMenuBar();
  163.   m_menuBar->Append(m_menuFile, _("&File"));
  164.   SetMenuBar(m_menuBar);
  165.  
  166.   // Status bar
  167.   CreateStatusBar(2);
  168.  
  169.   // Make a textctrl for logging
  170.   m_text  = new wxTextCtrl(this, -1,
  171.                            _("Welcome to wxSocket demo: Server\n"),
  172.                            wxDefaultPosition, wxDefaultSize,
  173.                            wxTE_MULTILINE | wxTE_READONLY);
  174.  
  175.   // Create the address - defaults to localhost:0 initially
  176.   wxIPV4address addr;
  177.   addr.Service(3000);
  178.  
  179.   // Create the socket
  180.   m_server = new wxSocketServer(addr);
  181.  
  182.   // We use Ok() here to see if the server is really listening
  183.   if (! m_server->Ok())
  184.   {
  185.     m_text->AppendText(_("Could not listen at the specified port !\n\n"));
  186.     return;
  187.   }
  188.   else
  189.   {
  190.     m_text->AppendText(_("Server listening.\n\n"));
  191.   }
  192.  
  193.   // Setup the event handler and subscribe to connection events
  194.   m_server->SetEventHandler(*this, SERVER_ID);
  195.   m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
  196.   m_server->Notify(TRUE);
  197.  
  198.   m_busy = FALSE;
  199.   m_numClients = 0;
  200.   UpdateStatusBar();
  201. }
  202.  
  203. MyFrame::~MyFrame()
  204. {
  205.   // No delayed deletion here, as the frame is dying anyway
  206.   delete m_server;
  207. }
  208.  
  209. // event handlers
  210.  
  211. void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
  212. {
  213.   // TRUE is to force the frame to close
  214.   Close(TRUE);
  215. }
  216.  
  217. void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
  218. {
  219.   wxMessageBox(_("wxSocket demo: Server\n(c) 1999 Guillermo Rodriguez Garcia\n"),
  220.                _("About Server"),
  221.                wxOK | wxICON_INFORMATION, this);
  222. }
  223.  
  224. void MyFrame::Test1(wxSocketBase *sock)
  225. {
  226.   unsigned char len;
  227.   char *buf;
  228.  
  229.   m_text->AppendText(_("Test 1 begins\n"));
  230.  
  231.   // Receive data from socket and send it back. We will first
  232.   // get a byte with the buffer size, so we can specify the
  233.   // exact size and use the wxSOCKET_WAITALL flag. Also, we
  234.   // disabled input events so we won't have unwanted reentrance.
  235.   // This way we can avoid the infamous wxSOCKET_BLOCK flag.
  236.  
  237.   sock->SetFlags(wxSOCKET_WAITALL);
  238.  
  239.   // Read the size
  240.   sock->Read(&len, 1);
  241.   buf = new char[len];
  242.  
  243.   // Read the data
  244.   sock->Read(buf, len);
  245.   m_text->AppendText(_("Got the data, sending it back\n"));
  246.  
  247.   // Write it back
  248.   sock->Write(buf, len);
  249.   delete[] buf;
  250.  
  251.   m_text->AppendText(_("Test 1 ends\n\n"));
  252. }
  253.  
  254. void MyFrame::Test2(wxSocketBase *sock)
  255. {
  256. #define MAX_MSG_SIZE 10000
  257.  
  258.   wxString s;
  259.   wxChar *buf = new wxChar[MAX_MSG_SIZE];
  260.   wxUint32 len;
  261.  
  262.   m_text->AppendText(_("Test 2 begins\n"));
  263.  
  264.   // We don't need to set flags because ReadMsg and WriteMsg
  265.   // are not affected by them anyway.
  266.  
  267.   // Read the message
  268.   len = sock->ReadMsg(buf, MAX_MSG_SIZE * sizeof(wxChar)).LastCount();
  269.   s.Printf(_("Client says: %s\n"), buf);
  270.   m_text->AppendText(s);
  271.   m_text->AppendText(_("Sending the data back\n"));
  272.  
  273.   // Write it back
  274.   sock->WriteMsg(buf, len);
  275.   delete[] buf;
  276.  
  277.   m_text->AppendText(_("Test 2 ends\n\n"));
  278.  
  279. #undef MAX_MSG_SIZE
  280. }
  281.  
  282. void MyFrame::Test3(wxSocketBase *sock)
  283. {
  284.   unsigned char len;
  285.   char *buf;
  286.  
  287.   m_text->AppendText(_("Test 3 begins\n"));
  288.  
  289.   // This test is similar to the first one, but the len is
  290.   // expressed in kbytes - this tests large data transfers.
  291.  
  292.   sock->SetFlags(wxSOCKET_WAITALL);
  293.  
  294.   // Read the size
  295.   sock->Read(&len, 1);
  296.   buf = new char[len * 1024];
  297.  
  298.   // Read the data
  299.   sock->Read(buf, len * 1024);
  300.   m_text->AppendText(_("Got the data, sending it back\n"));
  301.  
  302.   // Write it back
  303.   sock->Write(buf, len * 1024);
  304.   delete[] buf;
  305.  
  306.   m_text->AppendText(_("Test 3 ends\n\n"));
  307. }
  308.  
  309. void MyFrame::OnServerEvent(wxSocketEvent& event)
  310. {
  311.   wxString s = _("OnServerEvent: ");
  312.   wxSocketBase *sock;
  313.  
  314.   switch(event.GetSocketEvent())
  315.   {
  316.     case wxSOCKET_CONNECTION : s.Append(_("wxSOCKET_CONNECTION\n")); break;
  317.     default                  : s.Append(_("Unexpected event !\n")); break;
  318.   }
  319.  
  320.   m_text->AppendText(s);
  321.  
  322.   // Accept new connection if there is one in the pending
  323.   // connections queue, else exit. We use Accept(FALSE) for
  324.   // non-blocking accept (although if we got here, there
  325.   // should ALWAYS be a pending connection).
  326.  
  327.   sock = m_server->Accept(FALSE);
  328.  
  329.   if (sock)
  330.   {
  331.     m_text->AppendText(_("New client connection accepted\n\n"));
  332.   }
  333.   else
  334.   {
  335.     m_text->AppendText(_("Error: couldn't accept a new connection\n\n"));
  336.     return;
  337.   }
  338.  
  339.   sock->SetEventHandler(*this, SOCKET_ID);
  340.   sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
  341.   sock->Notify(TRUE);
  342.  
  343.   m_numClients++;
  344.   UpdateStatusBar();
  345. }
  346.  
  347. void MyFrame::OnSocketEvent(wxSocketEvent& event)
  348. {
  349.   wxString s = _("OnSocketEvent: ");
  350.   wxSocketBase *sock = event.GetSocket();
  351.  
  352.   // First, print a message
  353.   switch(event.GetSocketEvent())
  354.   {
  355.     case wxSOCKET_INPUT : s.Append(_("wxSOCKET_INPUT\n")); break;
  356.     case wxSOCKET_LOST  : s.Append(_("wxSOCKET_LOST\n")); break;
  357.     default             : s.Append(_("Unexpected event !\n")); break;
  358.   }
  359.  
  360.   m_text->AppendText(s);
  361.  
  362.   // Now we process the event
  363.   switch(event.GetSocketEvent())
  364.   {
  365.     case wxSOCKET_INPUT:
  366.     {
  367.       // We disable input events, so that the test doesn't trigger
  368.       // wxSocketEvent again.
  369.       sock->SetNotify(wxSOCKET_LOST_FLAG);
  370.  
  371.       // Which test are we going to run?
  372.       unsigned char c;
  373.       sock->Read(&c, 1);
  374.  
  375.       switch (c)
  376.       {
  377.         case 0xBE: Test1(sock); break;
  378.         case 0xCE: Test2(sock); break;
  379.         case 0xDE: Test3(sock); break;
  380.         default:
  381.           m_text->AppendText(_("Unknown test id received from client\n\n"));
  382.       }
  383.  
  384.       // Enable input events again.
  385.       sock->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG);
  386.       break;
  387.     }
  388.     case wxSOCKET_LOST:
  389.     {
  390.       m_numClients--;
  391.  
  392.       // Destroy() should be used instead of delete wherever possible,
  393.       // due to the fact that wxSocket uses 'delayed events' (see the
  394.       // documentation for wxPostEvent) and we don't want an event to
  395.       // arrive to the event handler (the frame, here) after the socket
  396.       // has been deleted. Also, we might be doing some other thing with
  397.       // the socket at the same time; for example, we might be in the
  398.       // middle of a test or something. Destroy() takes care of all
  399.       // this for us.
  400.  
  401.       m_text->AppendText(_("Deleting socket.\n\n"));
  402.       sock->Destroy();
  403.       break;
  404.     }
  405.     default: ;
  406.   }
  407.  
  408.   UpdateStatusBar();
  409. }
  410.  
  411. // convenience functions
  412.  
  413. void MyFrame::UpdateStatusBar()
  414. {
  415.   wxString s;
  416.   s.Printf(_("%d clients connected"), m_numClients);
  417.   SetStatusText(s, 1);
  418. }
  419.