X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/db131261984ad9a406373bfa497e117c524ef0ed..78ee892753cbe21615f178b3efdf32b4419a903a:/samples/wxsocket/client.cpp diff --git a/samples/wxsocket/client.cpp b/samples/wxsocket/client.cpp index c1ac80ebe2..2dba5c91b3 100644 --- a/samples/wxsocket/client.cpp +++ b/samples/wxsocket/client.cpp @@ -1,282 +1,446 @@ -/* - * File: client.cpp - * Purpose: wxSocket: client demo - * Author: LAVAUX Guilhem (from minimal.cc) - * Created: June 1997 - * Updated: - * Copyright: (c) 1993, AIAI, University of Edinburgh - * (C) 1997, LAVAUX Guilhem - */ +///////////////////////////////////////////////////////////////////////////// +// Name: client.cpp +// Purpose: Client for wxSocket demo +// Author: Guillermo Rodriguez Garcia +// 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" - -// Define a new application type -class MyApp: public wxApp -{ public: - virtual bool OnInit(void); -}; -class MyClient; +# include "wx/socket.h" +# include "wx/url.h" +# include "wx/protocol/http.h" +# include "wx/progdlg.h" -// Define a new frame type -class MyFrame: public wxFrame -{ - DECLARE_CLASS(MyFrame) -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() -}; +// -------------------------------------------------------------------------- +// resources +// -------------------------------------------------------------------------- +// the application icon +#if defined(__WXGTK__) || defined(__WXMOTIF__) +# include "mondrian.xpm" +#endif -IMPLEMENT_CLASS(MyFrame, wxFrame) +// -------------------------------------------------------------------------- +// classes +// -------------------------------------------------------------------------- -/* - * Define a new derived SocketClient - */ -class MyClient: public wxSocketClient +// Define a new application type +class MyApp : public wxApp { public: - MyFrame *frame; - - void OnNotify(wxRequestNotify WXUNUSED(flags)) { frame->UpdateStatus(); } + virtual bool OnInit(); }; -// 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; +// 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 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() +}; -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 -#ifdef wx_msw - frame->SetIcon(new wxIcon("mondrian")); -#endif -#ifdef wx_x - frame->SetIcon(new wxIcon("mondrian.xbm")); -#endif + // 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, 0, 0, 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")); - dlg->EndModal(0); + m_text->AppendText(_T("=== Test 2 ends ===\n")); + + 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()); }