-/*
- * File: client.cpp
- * Purpose: wxSocket: client demo
- * Author: LAVAUX Guilhem
- * Created: June 1997
- * Updated:
- * Copyright: (c) 1997, LAVAUX Guilhem
- */
+/////////////////////////////////////////////////////////////////////////////
+// Name: client.cpp
+// Purpose: Client for wxSocket demo
+// Author: Guillermo Rodriguez Garcia <guille@iies.es>
+// Modified by:
+// Created: 1999/09/19
+// RCS-ID: $Id$
+// Copyright: (c) 1999 Guillermo Rodriguez Garcia
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// ==========================================================================
+// declarations
+// ==========================================================================
+
+// --------------------------------------------------------------------------
+// headers
+// --------------------------------------------------------------------------
#ifdef __GNUG__
-#pragma implementation
-#pragma interface
+# pragma implementation "client.cpp"
+# pragma interface "client.cpp"
#endif
-// For compilers that support precompilation, includes "wx.h".
+// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
-#pragma hdrstop
+# pragma hdrstop
#endif
+// for all others, include the necessary headers
#ifndef WX_PRECOMP
-#include "wx/wx.h"
+# include "wx/wx.h"
#endif
-#include "wx/socket.h"
-#include "wx/url.h"
-#include "wx/protocol/http.h"
+# include "wx/socket.h"
+# include "wx/url.h"
+# include "wx/protocol/http.h"
+# include "wx/progdlg.h"
-#if defined(__WXMOTIF__) || defined(__WXGTK__)
-#include "mondrian.xpm"
-#endif
+// --------------------------------------------------------------------------
+// resources
+// --------------------------------------------------------------------------
-// Define a new application type
-class MyApp: public wxApp
-{ public:
- virtual bool OnInit(void);
-};
+// the application icon
+#if defined(__WXGTK__) || defined(__WXMOTIF__)
+# include "mondrian.xpm"
+#endif
-class MyClient;
+// --------------------------------------------------------------------------
+// classes
+// --------------------------------------------------------------------------
-// Define a new frame type
-class MyFrame: public wxFrame
-{
- DECLARE_CLASS(MyFrame)
+// Define a new application type
+class MyApp : public wxApp
+{
public:
- MyClient *sock;
-
- MyFrame(void);
- virtual ~MyFrame();
- void OnCloseTest(wxCommandEvent& evt);
- void OnExecTest1(wxCommandEvent& evt);
- void OnExecUrlTest(wxCommandEvent& evt);
- void OnQuitApp(wxCommandEvent& evt);
- void OnExecOpenConnection(wxCommandEvent& evt);
- void OnExecCloseConnection(wxCommandEvent& evt);
- void UpdateStatus();
-
- DECLARE_EVENT_TABLE()
+ virtual bool OnInit();
};
-
-IMPLEMENT_CLASS(MyFrame, wxFrame)
-
-/*
- * Define a new derived SocketClient
- */
-class MyClient: public wxSocketClient
+// Define a new frame type: this is going to be our main frame
+class MyFrame : public wxFrame
{
public:
- MyFrame *frame;
-
- void OnNotify(wxRequestNotify WXUNUSED(flags)) { frame->UpdateStatus(); }
+ MyFrame();
+ ~MyFrame();
+
+ // event handlers (these functions should _not_ be virtual)
+ void OnQuit(wxCommandEvent& event);
+ void OnAbout(wxCommandEvent& event);
+ void OnOpenConnection(wxCommandEvent& event);
+ void OnTest1(wxCommandEvent& event);
+ void OnTest2(wxCommandEvent& event);
+ void OnTest3(wxCommandEvent& event);
+ void OnCloseConnection(wxCommandEvent& event);
+ void OnSocketEvent(wxSocketEvent& event);
+
+ // convenience functions
+ void UpdateStatusBar();
+
+private:
+ wxSocketClient *m_sock;
+ wxPanel *m_panel;
+ wxTextCtrl *m_text;
+ wxMenu *m_menuFile;
+ wxMenu *m_menuSocket;
+ wxMenuBar *m_menuBar;
+ bool m_busy;
+
+ // any class wishing to process wxWindows events must use this macro
+ DECLARE_EVENT_TABLE()
};
-// ID for the menu quit command
-const int SKDEMO_QUIT = 101;
-const int SKDEMO_CONNECT = 102;
-const int SKDEMO_TEST1 = 103;
-const int SKDEMO_TEST2 = 104;
-const int SKDEMO_CLOSE = 105;
-const int SKDEMO_TEST3 = 106;
-const int ID_TEST_CLOSE = 107;
-
-IMPLEMENT_APP(MyApp)
+// --------------------------------------------------------------------------
+// constants
+// --------------------------------------------------------------------------
-/*
- * `Main program' equivalent, creating windows and returning main app frame
- */
-bool MyApp::OnInit(void)
+// IDs for the controls and the menu commands
+enum
{
- // Create the main frame window
- MyFrame *frame = new MyFrame();
-
- // Give it an icon
- frame->SetIcon(wxICON(mondrian));
+ // menu items
+ CLIENT_QUIT = 1000,
+ CLIENT_ABOUT,
+ CLIENT_OPEN,
+ CLIENT_TEST1,
+ CLIENT_TEST2,
+ CLIENT_TEST3,
+ CLIENT_CLOSE,
+
+ // id for socket
+ SOCKET_ID
+};
- // Make a menubar
- wxMenu *file_menu = new wxMenu();
+// --------------------------------------------------------------------------
+// event tables and other macros for wxWindows
+// --------------------------------------------------------------------------
- file_menu->Append(SKDEMO_QUIT, "Exit");
- wxMenuBar *menu_bar = new wxMenuBar;
- menu_bar->Append(file_menu, "File");
+BEGIN_EVENT_TABLE(MyFrame, wxFrame)
+ EVT_MENU(CLIENT_QUIT, MyFrame::OnQuit)
+ EVT_MENU(CLIENT_ABOUT, MyFrame::OnAbout)
+ EVT_MENU(CLIENT_OPEN, MyFrame::OnOpenConnection)
+ EVT_MENU(CLIENT_TEST1, MyFrame::OnTest1)
+ EVT_MENU(CLIENT_TEST2, MyFrame::OnTest2)
+ EVT_MENU(CLIENT_TEST3, MyFrame::OnTest3)
+ EVT_MENU(CLIENT_CLOSE, MyFrame::OnCloseConnection)
+ EVT_SOCKET(SOCKET_ID, MyFrame::OnSocketEvent)
+END_EVENT_TABLE()
- wxMenu *socket_menu = new wxMenu();
- socket_menu->Append(SKDEMO_CONNECT, "Open session");
- socket_menu->AppendSeparator();
- socket_menu->Append(SKDEMO_TEST1, "Start test 1");
- socket_menu->AppendSeparator();
- socket_menu->Append(SKDEMO_CLOSE, "Close session");
- socket_menu->AppendSeparator();
- socket_menu->Append(SKDEMO_TEST3, "Start URL test");
+IMPLEMENT_APP(MyApp)
- menu_bar->Append(socket_menu, "Socket");
+// ==========================================================================
+// implementation
+// ==========================================================================
- frame->SetMenuBar(menu_bar);
+// --------------------------------------------------------------------------
+// the application class
+// --------------------------------------------------------------------------
- // Make a panel with a message
- (void)new wxPanel(frame, -1, wxPoint(0, 0), wxSize(300, 100));
+bool MyApp::OnInit()
+{
+ // Create the main application window
+ MyFrame *frame = new MyFrame();
- // Show the frame
+ // Show it and tell the application that it's our main window
frame->Show(TRUE);
-
- // Return the main frame window
+ SetTopWindow(frame);
+
+ // success
return TRUE;
}
-/*
- * MyFrame Constructor
- */
-MyFrame::MyFrame():
- wxFrame(NULL, -1, "wxSocket client demo",
- wxDefaultPosition, wxSize(300, 200), wxDEFAULT_FRAME_STYLE)
+// --------------------------------------------------------------------------
+// main frame
+// --------------------------------------------------------------------------
+
+// frame constructor
+MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, -1,
+ _T("wxSocket demo: Client"),
+ wxDefaultPosition, wxSize(300, 200))
{
- // Init all
- wxSocketHandler::Master();
-
- sock = new MyClient();
- sock->SetFlags(wxSocketBase::WAITALL);
- wxSocketHandler::Master().Register(sock);
- sock->frame = this;
- sock->SetNotify(wxSocketBase::REQ_LOST);
+ // Give the frame an icon
+ SetIcon(wxICON(mondrian));
+
+ // Make menus
+ m_menuFile = new wxMenu();
+ m_menuFile->Append(CLIENT_ABOUT, _T("&About...\tCtrl-A"), _T("Show about dialog"));
+ m_menuFile->AppendSeparator();
+ m_menuFile->Append(CLIENT_QUIT, _T("E&xit\tAlt-X"), _T("Quit client"));
+
+ m_menuSocket = new wxMenu();
+ m_menuSocket->Append(CLIENT_OPEN, _T("&Open session"), _T("Connect to server"));
+ m_menuSocket->AppendSeparator();
+ m_menuSocket->Append(CLIENT_TEST1, _T("Test &1"), _T("Test basic functionality"));
+ m_menuSocket->Append(CLIENT_TEST2, _T("Test &2"), _T("Test ReadMsg and WriteMsg"));
+ m_menuSocket->Append(CLIENT_TEST3, _T("Test &3"), _T("Test large data transfer"));
+ m_menuSocket->AppendSeparator();
+ m_menuSocket->Append(CLIENT_CLOSE, _T("&Close session"), _T("Close connection"));
+
+ // Append menus to the menubar
+ m_menuBar = new wxMenuBar();
+ m_menuBar->Append(m_menuFile, _T("&File"));
+ m_menuBar->Append(m_menuSocket, _T("&Socket"));
+ SetMenuBar(m_menuBar);
+
+ // Status bar
CreateStatusBar(2);
- UpdateStatus();
+
+ // Make a panel with a textctrl in it
+ m_panel = new wxPanel(this, -1, wxPoint(0, 0), GetClientSize());
+ m_text = new wxTextCtrl(m_panel, -1,
+ _T("Welcome to wxSocket demo: Client\n")
+ _T("Client ready\n\n"),
+ wxPoint(0, 0), m_panel->GetClientSize(),
+ wxTE_MULTILINE | wxTE_READONLY);
+
+ // Create the socket
+ m_sock = new wxSocketClient();
+ m_sock->SetEventHandler(*this, SOCKET_ID);
+ m_sock->SetNotify(wxSOCKET_CONNECTION_FLAG |
+ wxSOCKET_INPUT_FLAG |
+ wxSOCKET_LOST_FLAG);
+ m_sock->Notify(TRUE);
+
+ m_busy = FALSE;
+ UpdateStatusBar();
}
MyFrame::~MyFrame()
{
- delete sock;
+ delete m_sock;
}
-void MyFrame::OnQuitApp(wxCommandEvent& WXUNUSED(evt))
+// event handlers
+
+void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
+ // TRUE is to force the frame to close
Close(TRUE);
}
-void MyFrame::OnExecOpenConnection(wxCommandEvent& WXUNUSED(evt))
+void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
+{
+ wxMessageBox(_T("wxSocket demo: Client\n")
+ _T("(c) 1999 Guillermo Rodriguez Garcia\n"),
+ _T("About Client"),
+ wxOK | wxICON_INFORMATION, this);
+}
+
+void MyFrame::OnOpenConnection(wxCommandEvent& WXUNUSED(event))
{
wxIPV4address addr;
-
- if (sock->IsConnected())
- sock->Close();
- wxString hname = wxGetTextFromUser("Enter the address of the wxSocket Sample Server",
- "Connect ...", "localhost");
- addr.Hostname(hname);
+ m_menuSocket->Enable(CLIENT_OPEN, FALSE);
+ m_menuSocket->Enable(CLIENT_CLOSE, FALSE);
+
+ // Ask server address
+ wxString hostname = wxGetTextFromUser(
+ _T("Enter the address of the wxSocket demo server:"),
+ _T("Connect ..."),
+ _T("localhost"));
+
+ addr.Hostname(hostname);
addr.Service(3000);
- sock->SetNotify(0);
- sock->Connect(addr, TRUE);
- if (!sock->IsConnected())
- wxMessageBox("Can't connect to the specified host", "Alert !");
- UpdateStatus();
+ // Non-blocking connect
+ m_text->AppendText(_T("Trying to connect (timeout = 10 sec) ...\n"));
+ m_sock->Connect(addr, FALSE);
+ m_sock->WaitOnConnect(10);
+
+ if (m_sock->IsConnected())
+ m_text->AppendText(_T("Succeeded ! Connection established\n"));
+ else
+ {
+ m_sock->Close();
+ m_text->AppendText(_T("Failed ! Unable to connect\n"));
+ wxMessageBox(_T("Can't connect to the specified host"), _T("Alert !"));
+ }
+
+ UpdateStatusBar();
}
-void MyFrame::OnExecCloseConnection(wxCommandEvent& WXUNUSED(evt))
+void MyFrame::OnTest1(wxCommandEvent& WXUNUSED(event))
{
- if (sock)
- sock->Close();
- UpdateStatus();
-}
+ char *buf1, *buf2;
+ char len;
+
+ // Disable socket menu entries (exception: Close Session)
+ m_busy = TRUE;
+ UpdateStatusBar();
+
+ m_text->AppendText(_T("\n=== Test 1 begins ===\n"));
+
+ // Tell the server which test we are running
+ char c = 0xBE;
+ m_sock->Write(&c, 1);
+
+ // Send some data and read it back. We know the size of the
+ // buffer, so we can specify the exact number of bytes to be
+ // sent or received and use the WAITALL flag. Also, we have
+ // disabled menu entries which could interfere with the test,
+ // so we can safely avoid the BLOCK (formerly SPEED) flag.
+ //
+ // First we send a byte with the length of the string, then
+ // we send the string itself (do NOT try to send any integral
+ // value larger than a byte "as is" acrosss the network, or
+ // you might be in trouble! Ever heard about big and little
+ // endian computers?)
+ //
+ m_sock->SetFlags(wxSOCKET_WAITALL);
+
+ buf1 = _T("Test string (less than 127 chars!)");
+ len = wxStrlen(buf1) + 1;
+ buf2 = new char[len];
+
+ m_text->AppendText(_T("Sending a test buffer to the server ..."));
+ m_sock->Write(&len, 1);
+ m_sock->Write(buf1, len);
+ m_text->AppendText(m_sock->Error() ? _T("failed !\n") : _T("done\n"));
+
+ m_text->AppendText(_T("Receiving the buffer back from server ..."));
+ m_sock->Read(buf2, len);
+ m_text->AppendText(m_sock->Error() ? _T("failed !\n") : _T("done\n"));
+
+ m_text->AppendText(_T("Comparing the two buffers ..."));
+ if (memcmp(buf1, buf2, len) != 0)
+ {
+ m_text->AppendText(_T("failed!\n"));
+ m_text->AppendText(_T("Test 1 failed !\n"));
+ }
+ else
+ {
+ m_text->AppendText(_T("done\n"));
+ m_text->AppendText(_T("Test 1 passed !\n"));
+ }
+ m_text->AppendText(_T("=== Test 1 ends ===\n"));
-BEGIN_EVENT_TABLE(MyFrame, wxFrame)
- EVT_BUTTON(ID_TEST_CLOSE, MyFrame::OnCloseTest)
- EVT_MENU(SKDEMO_TEST1, MyFrame::OnExecTest1)
- EVT_MENU(SKDEMO_TEST3, MyFrame::OnExecUrlTest)
- EVT_MENU(SKDEMO_QUIT, MyFrame::OnQuitApp)
- EVT_MENU(SKDEMO_CONNECT, MyFrame::OnExecOpenConnection)
- EVT_MENU(SKDEMO_CLOSE, MyFrame::OnExecCloseConnection)
-END_EVENT_TABLE()
+ delete[] buf2;
+ m_busy = FALSE;
+ UpdateStatusBar();
+}
-void MyFrame::OnCloseTest(wxCommandEvent& evt)
+void MyFrame::OnTest2(wxCommandEvent& WXUNUSED(event))
{
- wxButton *button = (wxButton *)evt.GetEventObject();
- wxDialog *dlg = (wxDialog *)button->GetParent();
+ char *msg1;
+ char *msg2;
+ size_t len;
+
+ // Disable socket menu entries (exception: Close Session)
+ m_busy = TRUE;
+ UpdateStatusBar();
+
+ m_text->AppendText(_T("\n=== Test 2 begins ===\n"));
+
+ // Tell the server which test we are running
+ char c = 0xCE;
+ m_sock->Write(&c, 1);
+
+ // Here we use ReadMsg and WriteMsg to send messages with
+ // a header with size information. Also, the reception is
+ // event triggered, so we test input events as well.
+ //
+ // We need to set no flags here (ReadMsg and WriteMsg are
+ // not affected by flags)
+ //
+ m_sock->SetFlags(wxSOCKET_WAITALL);
+
+ wxString s = wxGetTextFromUser(
+ _T("Enter an arbitrary string to send to the server:"),
+ _T("Test 2 ..."),
+ _T("Yes I like wxWindows!"));
+
+ msg1 = (char *)s.c_str();
+ len = wxStrlen(msg1) + 1;
+ msg2 = (char *)malloc(len);
+
+ m_text->AppendText(_T("Sending the string with WriteMsg ..."));
+ m_sock->WriteMsg(msg1, len);
+ m_text->AppendText(m_sock->Error() ? _T("failed !\n") : _T("done\n"));
+ m_text->AppendText(_T("Waiting for an event (timeout = 2 sec)\n"));
+
+ // Wait until data available (will also return if the connection is lost)
+ m_sock->WaitForRead(2);
+
+ if (m_sock->IsData())
+ {
+ m_text->AppendText(_T("Reading the string back with ReadMsg ..."));
+ m_sock->ReadMsg(msg2, len);
+ m_text->AppendText(m_sock->Error() ? _T("failed !\n") : _T("done\n"));
+ m_text->AppendText(_T("Comparing the two buffers ..."));
+ if (memcmp(msg1, msg2, len) != 0)
+ {
+ m_text->AppendText(_T("failed!\n"));
+ m_text->AppendText(_T("Test 2 failed !\n"));
+ }
+ else
+ {
+ m_text->AppendText(_T("done\n"));
+ m_text->AppendText(_T("Test 2 passed !\n"));
+ }
+ }
+ else
+ m_text->AppendText(_T("Timeout ! Test 2 failed.\n"));
+
+ m_text->AppendText(_T("=== Test 2 ends ===\n"));
- dlg->EndModal(0);
+ free(msg2);
+ m_busy = FALSE;
+ UpdateStatusBar();
}
-void MyFrame::UpdateStatus()
+void MyFrame::OnTest3(wxCommandEvent& WXUNUSED(event))
{
- if (!sock->IsConnected()) {
- SetStatusText("Not connected", 0);
- SetStatusText("", 1);
- } else {
- wxIPV4address addr;
- char s[100];
-
- sock->GetPeer(addr);
- sprintf(s, "Connected to %s", (const char *)addr.Hostname());
- SetStatusText(s, 0);
- sprintf(s, "Service: %d", addr.Service());
- SetStatusText(s, 1);
- }
+ m_text->AppendText(_T("\n=== Test 3 begins ===\n"));
+ m_text->AppendText(_T("Test 3 not implemented\n"));
+ m_text->AppendText(_T("=== Test 3 ends ===\n"));
}
-void MyFrame::OnExecTest1(wxCommandEvent& WXUNUSED(evt))
+void MyFrame::OnCloseConnection(wxCommandEvent& WXUNUSED(event))
{
- if (!sock->IsConnected())
- return;
-
- wxDialog *dlgbox = new wxDialog(this, -1, "Test 1", wxDefaultPosition, wxSize(414, 250));
- wxTextCtrl *text_win = new wxTextCtrl(dlgbox, -1, "",
- wxPoint(0, 0), wxSize(400, 200),
- wxTE_MULTILINE);
- (void)new wxButton(dlgbox, ID_TEST_CLOSE, "Close",
- wxPoint(100, 210), wxSize(100, -1));
- char *buf, *buf2;
+ m_sock->Close();
+ UpdateStatusBar();
+}
- dlgbox->Layout();
- dlgbox->Show(TRUE);
+void MyFrame::OnSocketEvent(wxSocketEvent& event)
+{
+ wxString s = _T("OnSocketEvent: ");
+
+ switch(event.SocketEvent())
+ {
+ case wxSOCKET_INPUT : s.Append(_T("wxSOCKET_INPUT\n")); break;
+ case wxSOCKET_LOST : s.Append(_T("wxSOCKET_LOST\n")); break;
+ case wxSOCKET_CONNECTION : s.Append(_T("wxSOCKET_CONNECTION\n")); break;
+ default : s.Append(_T("Unexpected event !\n")); break;
+ }
- text_win->WriteText("Initializing test 1 ...\n");
-
- wxYield();
-
- /* Init */
- buf = copystring("Salut ! Salut ! Salut ! Salut Toto\n");
- buf2 = new char[strlen(buf)+1];
- char c = 0xbe;
- sock->WriteMsg(&c, 1);
-
- /* No 1 */
- text_win->WriteText("Sending some byte to the server ...");
- sock->Write(buf, strlen(buf)+1);
- text_win->WriteText("done\n");
- text_win->WriteText("Receiving some byte from the server ...");
- sock->Read(buf2, strlen(buf)+1);
- text_win->WriteText("done\n");
-
- text_win->WriteText("Comparing the two buffers ...");
- if (memcmp(buf, buf2, strlen(buf)+1) != 0) {
- text_win->WriteText("Fail\n");
- sock->Close();
- UpdateStatus();
- } else
- text_win->WriteText("done\nTest 1 passed !\n");
-
- dlgbox->Layout();
- dlgbox->ShowModal();
-
- delete [] buf;
- delete [] buf2;
- delete text_win;
- delete dlgbox;
+ m_text->AppendText(s);
+ UpdateStatusBar();
}
-void MyFrame::OnExecUrlTest(wxCommandEvent& WXUNUSED(evt))
+// convenience functions
+
+void MyFrame::UpdateStatusBar()
{
- wxString urlname = wxGetTextFromUser("Enter an URL to get",
- "URL:", "http://localhost");
+ wxString s;
- wxURL url(urlname);
- wxInputStream *datas = url.GetInputStream();
+ if (!m_sock->IsConnected())
+ {
+ s.Printf(_T("Not connected"));
+ }
+ else
+ {
+ wxIPV4address addr;
- if (!datas)
- wxMessageBox("Error in getting data from the URL.", "Alert !");
- else {
- wxMessageBox("Success !! Click on OK to see the text.", "OK");
- delete datas;
+ m_sock->GetPeer(addr);
+ s.Printf(_T("%s : %d"), (addr.Hostname()).c_str(), addr.Service());
}
+
+ SetStatusText(s, 1);
+
+ m_menuSocket->Enable(CLIENT_OPEN, !m_sock->IsConnected() && !m_busy);
+ m_menuSocket->Enable(CLIENT_TEST1, m_sock->IsConnected() && !m_busy);
+ m_menuSocket->Enable(CLIENT_TEST2, m_sock->IsConnected() && !m_busy);
+ m_menuSocket->Enable(CLIENT_TEST3, m_sock->IsConnected() && !m_busy);
+ m_menuSocket->Enable(CLIENT_CLOSE, m_sock->IsConnected());
}