| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- /////////////////////////////////////////////////////////////////////////////
- // Name: server.cpp
- // Purpose: Server for wxSocket demo
- // Author: Guillermo Rodriguez Garcia <guille@iies.es>
- // Created: 1999/09/19
- // Copyright: (c) 1999 Guillermo Rodriguez Garcia
- // (c) 2009 Vadim Zeitlin
- // Licence: wxWindows licence
- /////////////////////////////////////////////////////////////////////////////
- // ==========================================================================
- // declarations
- // ==========================================================================
- // --------------------------------------------------------------------------
- // headers
- // --------------------------------------------------------------------------
- // For compilers that support precompilation, includes "wx/wx.h".
- #include "wx/wxprec.h"
- #ifdef __BORLANDC__
- # pragma hdrstop
- #endif
- // for all others, include the necessary headers
- #ifndef WX_PRECOMP
- # include "wx/wx.h"
- #endif
- #include "wx/busyinfo.h"
- #include "wx/socket.h"
- // this example is currently written to use only IP or only IPv6 sockets, it
- // should be extended to allow using either in the future
- #if wxUSE_IPV6
- typedef wxIPV6address IPaddress;
- #else
- typedef wxIPV4address IPaddress;
- #endif
- // --------------------------------------------------------------------------
- // resources
- // --------------------------------------------------------------------------
- // the application icon
- #ifndef wxHAS_IMAGES_IN_RESOURCES
- #include "../sample.xpm"
- #endif
- // --------------------------------------------------------------------------
- // classes
- // --------------------------------------------------------------------------
- // Define a new application type
- class MyApp : public wxApp
- {
- public:
- virtual bool OnInit();
- };
- // Define a new frame type: this is going to be our main frame
- class MyFrame : public wxFrame
- {
- public:
- MyFrame();
- ~MyFrame();
- // event handlers (these functions should _not_ be virtual)
- void OnUDPTest(wxCommandEvent& event);
- void OnWaitForAccept(wxCommandEvent& event);
- void OnQuit(wxCommandEvent& event);
- void OnAbout(wxCommandEvent& event);
- void OnServerEvent(wxSocketEvent& event);
- void OnSocketEvent(wxSocketEvent& event);
- void Test1(wxSocketBase *sock);
- void Test2(wxSocketBase *sock);
- void Test3(wxSocketBase *sock);
- // convenience functions
- void UpdateStatusBar();
- private:
- wxSocketServer *m_server;
- wxTextCtrl *m_text;
- wxMenu *m_menuFile;
- wxMenuBar *m_menuBar;
- bool m_busy;
- int m_numClients;
- // any class wishing to process wxWidgets events must use this macro
- wxDECLARE_EVENT_TABLE();
- };
- // simple helper class to log start and end of each test
- class TestLogger
- {
- public:
- TestLogger(const wxString& name) : m_name(name)
- {
- wxLogMessage("=== %s begins ===", m_name);
- }
- ~TestLogger()
- {
- wxLogMessage("=== %s ends ===", m_name);
- }
- private:
- const wxString m_name;
- };
- // --------------------------------------------------------------------------
- // constants
- // --------------------------------------------------------------------------
- // IDs for the controls and the menu commands
- enum
- {
- // menu items
- SERVER_UDPTEST = 10,
- SERVER_WAITFORACCEPT,
- SERVER_QUIT = wxID_EXIT,
- SERVER_ABOUT = wxID_ABOUT,
- // id for sockets
- SERVER_ID = 100,
- SOCKET_ID
- };
- // --------------------------------------------------------------------------
- // event tables and other macros for wxWidgets
- // --------------------------------------------------------------------------
- wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
- EVT_MENU(SERVER_QUIT, MyFrame::OnQuit)
- EVT_MENU(SERVER_ABOUT, MyFrame::OnAbout)
- EVT_MENU(SERVER_UDPTEST, MyFrame::OnUDPTest)
- EVT_MENU(SERVER_WAITFORACCEPT, MyFrame::OnWaitForAccept)
- EVT_SOCKET(SERVER_ID, MyFrame::OnServerEvent)
- EVT_SOCKET(SOCKET_ID, MyFrame::OnSocketEvent)
- wxEND_EVENT_TABLE()
- IMPLEMENT_APP(MyApp)
- // ==========================================================================
- // implementation
- // ==========================================================================
- // --------------------------------------------------------------------------
- // the application class
- // --------------------------------------------------------------------------
- bool MyApp::OnInit()
- {
- if ( !wxApp::OnInit() )
- return false;
- // Create the main application window
- MyFrame *frame = new MyFrame();
- // Show it
- frame->Show(true);
- // Success
- return true;
- }
- // --------------------------------------------------------------------------
- // main frame
- // --------------------------------------------------------------------------
- // frame constructor
- MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, wxID_ANY,
- _("wxSocket demo: Server"),
- wxDefaultPosition, wxSize(300, 200))
- {
- // Give the frame an icon
- SetIcon(wxICON(sample));
- // Make menus
- m_menuFile = new wxMenu();
- m_menuFile->Append(SERVER_WAITFORACCEPT, "&Wait for connection\tCtrl-W");
- m_menuFile->Append(SERVER_UDPTEST, "&UDP test\tCtrl-U");
- m_menuFile->AppendSeparator();
- m_menuFile->Append(SERVER_ABOUT, _("&About\tCtrl-A"), _("Show about dialog"));
- m_menuFile->AppendSeparator();
- m_menuFile->Append(SERVER_QUIT, _("E&xit\tAlt-X"), _("Quit server"));
- // Append menus to the menubar
- m_menuBar = new wxMenuBar();
- m_menuBar->Append(m_menuFile, _("&File"));
- SetMenuBar(m_menuBar);
- #if wxUSE_STATUSBAR
- // Status bar
- CreateStatusBar(2);
- #endif // wxUSE_STATUSBAR
- // Make a textctrl for logging
- m_text = new wxTextCtrl(this, wxID_ANY,
- _("Welcome to wxSocket demo: Server\n"),
- wxDefaultPosition, wxDefaultSize,
- wxTE_MULTILINE | wxTE_READONLY);
- delete wxLog::SetActiveTarget(new wxLogTextCtrl(m_text));
- // Create the address - defaults to localhost:0 initially
- IPaddress addr;
- addr.Service(3000);
- wxLogMessage("Creating server at %s:%u", addr.IPAddress(), addr.Service());
- // Create the socket
- m_server = new wxSocketServer(addr);
- // We use IsOk() here to see if the server is really listening
- if (! m_server->IsOk())
- {
- wxLogMessage("Could not listen at the specified port !");
- return;
- }
- IPaddress addrReal;
- if ( !m_server->GetLocal(addrReal) )
- {
- wxLogMessage("ERROR: couldn't get the address we bound to");
- }
- else
- {
- wxLogMessage("Server listening at %s:%u",
- addrReal.IPAddress(), addrReal.Service());
- }
- // Setup the event handler and subscribe to connection events
- m_server->SetEventHandler(*this, SERVER_ID);
- m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
- m_server->Notify(true);
- m_busy = false;
- m_numClients = 0;
- UpdateStatusBar();
- }
- MyFrame::~MyFrame()
- {
- // No delayed deletion here, as the frame is dying anyway
- delete m_server;
- }
- // event handlers
- void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
- {
- // true is to force the frame to close
- Close(true);
- }
- void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
- {
- wxMessageBox(_("wxSocket demo: Server\n(c) 1999 Guillermo Rodriguez Garcia\n"),
- _("About Server"),
- wxOK | wxICON_INFORMATION, this);
- }
- void MyFrame::OnUDPTest(wxCommandEvent& WXUNUSED(event))
- {
- TestLogger logtest("UDP test");
- IPaddress addr;
- addr.Service(3000);
- wxDatagramSocket sock(addr);
- char buf[1024];
- size_t n = sock.RecvFrom(addr, buf, sizeof(buf)).LastCount();
- if ( !n )
- {
- wxLogMessage("ERROR: failed to receive data");
- return;
- }
- wxLogMessage("Received \"%s\" from %s:%u.",
- wxString::From8BitData(buf, n),
- addr.IPAddress(), addr.Service());
- for ( size_t i = 0; i < n; i++ )
- {
- char& c = buf[i];
- if ( (c >= 'A' && c <= 'M') || (c >= 'a' && c <= 'm') )
- c += 13;
- else if ( (c >= 'N' && c <= 'Z') || (c >= 'n' && c <= 'z') )
- c -= 13;
- }
- if ( sock.SendTo(addr, buf, n).LastCount() != n )
- {
- wxLogMessage("ERROR: failed to send data");
- return;
- }
- }
- void MyFrame::OnWaitForAccept(wxCommandEvent& WXUNUSED(event))
- {
- TestLogger logtest("WaitForAccept() test");
- wxBusyInfo("Waiting for connection for 10 seconds...", this);
- if ( m_server->WaitForAccept(10) )
- wxLogMessage("Accepted client connection.");
- else
- wxLogMessage("Connection error or timeout expired.");
- }
- void MyFrame::Test1(wxSocketBase *sock)
- {
- TestLogger logtest("Test 1");
- // Receive data from socket and send it back. We will first
- // get a byte with the buffer size, so we can specify the
- // exact size and use the wxSOCKET_WAITALL flag. Also, we
- // disabled input events so we won't have unwanted reentrance.
- // This way we can avoid the infamous wxSOCKET_BLOCK flag.
- sock->SetFlags(wxSOCKET_WAITALL);
- // Read the size
- unsigned char len;
- sock->Read(&len, 1);
- wxCharBuffer buf(len);
- // Read the data
- sock->Read(buf.data(), len);
- wxLogMessage("Got the data, sending it back");
- // Write it back
- sock->Write(buf, len);
- }
- void MyFrame::Test2(wxSocketBase *sock)
- {
- char buf[4096];
- TestLogger logtest("Test 2");
- // We don't need to set flags because ReadMsg and WriteMsg
- // are not affected by them anyway.
- // Read the message
- wxUint32 len = sock->ReadMsg(buf, sizeof(buf)).LastCount();
- if ( !len )
- {
- wxLogError("Failed to read message.");
- return;
- }
- wxLogMessage("Got \"%s\" from client.", wxString::FromUTF8(buf, len));
- wxLogMessage("Sending the data back");
- // Write it back
- sock->WriteMsg(buf, len);
- }
- void MyFrame::Test3(wxSocketBase *sock)
- {
- TestLogger logtest("Test 3");
- // This test is similar to the first one, but the len is
- // expressed in kbytes - this tests large data transfers.
- sock->SetFlags(wxSOCKET_WAITALL);
- // Read the size
- unsigned char len;
- sock->Read(&len, 1);
- wxCharBuffer buf(len*1024);
- // Read the data
- sock->Read(buf.data(), len * 1024);
- wxLogMessage("Got the data, sending it back");
- // Write it back
- sock->Write(buf, len * 1024);
- }
- void MyFrame::OnServerEvent(wxSocketEvent& event)
- {
- wxString s = _("OnServerEvent: ");
- wxSocketBase *sock;
- switch(event.GetSocketEvent())
- {
- case wxSOCKET_CONNECTION : s.Append(_("wxSOCKET_CONNECTION\n")); break;
- default : s.Append(_("Unexpected event !\n")); break;
- }
- m_text->AppendText(s);
- // Accept new connection if there is one in the pending
- // connections queue, else exit. We use Accept(false) for
- // non-blocking accept (although if we got here, there
- // should ALWAYS be a pending connection).
- sock = m_server->Accept(false);
- if (sock)
- {
- IPaddress addr;
- if ( !sock->GetPeer(addr) )
- {
- wxLogMessage("New connection from unknown client accepted.");
- }
- else
- {
- wxLogMessage("New client connection from %s:%u accepted",
- addr.IPAddress(), addr.Service());
- }
- }
- else
- {
- wxLogMessage("Error: couldn't accept a new connection");
- return;
- }
- sock->SetEventHandler(*this, SOCKET_ID);
- sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
- sock->Notify(true);
- m_numClients++;
- UpdateStatusBar();
- }
- void MyFrame::OnSocketEvent(wxSocketEvent& event)
- {
- wxString s = _("OnSocketEvent: ");
- wxSocketBase *sock = event.GetSocket();
- // First, print a message
- switch(event.GetSocketEvent())
- {
- case wxSOCKET_INPUT : s.Append(_("wxSOCKET_INPUT\n")); break;
- case wxSOCKET_LOST : s.Append(_("wxSOCKET_LOST\n")); break;
- default : s.Append(_("Unexpected event !\n")); break;
- }
- m_text->AppendText(s);
- // Now we process the event
- switch(event.GetSocketEvent())
- {
- case wxSOCKET_INPUT:
- {
- // We disable input events, so that the test doesn't trigger
- // wxSocketEvent again.
- sock->SetNotify(wxSOCKET_LOST_FLAG);
- // Which test are we going to run?
- unsigned char c;
- sock->Read(&c, 1);
- switch (c)
- {
- case 0xBE: Test1(sock); break;
- case 0xCE: Test2(sock); break;
- case 0xDE: Test3(sock); break;
- default:
- wxLogMessage("Unknown test id received from client");
- }
- // Enable input events again.
- sock->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG);
- break;
- }
- case wxSOCKET_LOST:
- {
- m_numClients--;
- // Destroy() should be used instead of delete wherever possible,
- // due to the fact that wxSocket uses 'delayed events' (see the
- // documentation for wxPostEvent) and we don't want an event to
- // arrive to the event handler (the frame, here) after the socket
- // has been deleted. Also, we might be doing some other thing with
- // the socket at the same time; for example, we might be in the
- // middle of a test or something. Destroy() takes care of all
- // this for us.
- wxLogMessage("Deleting socket.");
- sock->Destroy();
- break;
- }
- default: ;
- }
- UpdateStatusBar();
- }
- // convenience functions
- void MyFrame::UpdateStatusBar()
- {
- #if wxUSE_STATUSBAR
- wxString s;
- s.Printf(_("%d clients connected"), m_numClients);
- SetStatusText(s, 1);
- #endif // wxUSE_STATUSBAR
- }
|