From f85d901fcb784f74cc95b0ec6913ae99f32e926d Mon Sep 17 00:00:00 2001 From: Guillermo Rodriguez Garcia Date: Thu, 30 Sep 1999 23:56:10 +0000 Subject: [PATCH] new sample git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3773 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- samples/wxsocket/client.cpp | 670 ++++++++++++++++++++---------------- samples/wxsocket/server.cpp | 444 +++++++++++++++++------- 2 files changed, 679 insertions(+), 435 deletions(-) diff --git a/samples/wxsocket/client.cpp b/samples/wxsocket/client.cpp index 4d14e9cb94..0ffb78c522 100644 --- a/samples/wxsocket/client.cpp +++ b/samples/wxsocket/client.cpp @@ -1,387 +1,445 @@ -/* - * File: client.cpp - * Purpose: wxSocket: client demo - * Author: LAVAUX Guilhem - * Created: June 1997 - * CVS ID: $Id$ - * Copyright: (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" +# include "wx/socket.h" +# include "wx/url.h" +# include "wx/protocol/http.h" +# include "wx/progdlg.h" #endif -#include "wx/wfstream.h" -#include "wx/socket.h" -#include "wx/url.h" -#include "wx/protocol/http.h" -#include "wx/thread.h" -#include "wx/progdlg.h" +// -------------------------------------------------------------------------- +// resources +// -------------------------------------------------------------------------- -#if defined(__WXMOTIF__) || defined(__WXGTK__) -#include "mondrian.xpm" +// the application icon +#if defined(__WXGTK__) || defined(__WXMOTIF__) +# include "mondrian.xpm" #endif -// Define a new application type -class MyApp: public wxApp -{ public: - virtual bool OnInit(void); -}; - -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; - int m_good; - - 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 OnSocketEvent(wxSocketEvent& evt); - void UpdateStatus(); - - void Download(wxInputStream *input); - - 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(GSocketEventFlags 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; -const int SKDEMO_SCK = 108; +// -------------------------------------------------------------------------- +// constants +// -------------------------------------------------------------------------- -IMPLEMENT_APP(MyApp) - -/* - * `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)) { - sock = new MyClient(); - sock->SetFlags((wxSocketBase::wxSockFlags) (wxSocketBase::WAITALL | wxSocketBase::SPEED)); - sock->frame = this; - sock->SetNotify(wxSOCKET_LOST_FLAG); + // 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->Connect(addr, FALSE); - sock->WaitOnConnect(10); - sock->SetFlags(wxSocketBase::NONE); - 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)) { - 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) - EVT_SOCKET(SKDEMO_SCK, MyFrame::OnSocketEvent) -END_EVENT_TABLE() + delete[] buf2; + m_busy = FALSE; + UpdateStatusBar(); +} -class MyFrameSocketTimer: public wxTimer { - public: - void Notify() { - *m_var = 0; +void MyFrame::OnTest2(wxCommandEvent& WXUNUSED(event)) +{ + 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")); - int *m_var; -}; + m_text->AppendText(_T("=== Test 2 ends ===\n")); -void MyFrame::OnSocketEvent(wxSocketEvent& evt) -{ - m_good = 1; + free(msg2); + m_busy = FALSE; + UpdateStatusBar(); } -void MyFrame::OnCloseTest(wxCommandEvent& evt) +void MyFrame::OnTest3(wxCommandEvent& WXUNUSED(event)) { - wxButton *button = (wxButton *)evt.GetEventObject(); - wxDialog *dlg = (wxDialog *)button->GetParent(); - - dlg->EndModal(0); + 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::UpdateStatus() +void MyFrame::OnCloseConnection(wxCommandEvent& WXUNUSED(event)) { - if (!sock->IsConnected()) { - SetStatusText("Not connected", 0); - SetStatusText("", 1); - } else { - wxIPV4address addr; - wxChar s[100]; - - sock->GetPeer(addr); - wxSprintf(s, _T("Connected to %s"), WXSTRINGCAST addr.Hostname()); - SetStatusText(s, 0); - wxSprintf(s, _T("Service: %d"), addr.Service()); - SetStatusText(s, 1); - } + m_sock->Close(); + UpdateStatusBar(); } -void MyFrame::OnExecTest1(wxCommandEvent& WXUNUSED(evt)) +void MyFrame::OnSocketEvent(wxSocketEvent& event) { - if (!sock->IsConnected()) - return; - - wxDialog *dlgbox = new wxDialog(this, -1, "Test 1", wxDefaultPosition, wxSize(414, 280)); - 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)); - wxChar *buf, *buf2; - - dlgbox->Layout(); - dlgbox->Show(TRUE); - - text_win->WriteText("Initializing test 1 ...\n"); - - wxYield(); - - /* Init */ - buf = copystring(_T("Hi ! Hi ! Hi !\n")); - buf2 = new wxChar[wxStrlen(buf)+1]; - char c = 0xbe; - sock->Write(&c, 1); - - /* No 1 */ - text_win->WriteText("Sending some byte to the server ..."); - wxYield(); - sock->Write((char *)buf, wxStrlen(buf)+1); - text_win->WriteText("done\n"); - wxYield(); - text_win->WriteText("Receiving some byte from the server ..."); - wxYield(); - sock->Read((char *)buf2, wxStrlen(buf)+1); - text_win->WriteText("done\n"); - wxYield(); - - text_win->WriteText("Comparing the two buffers ..."); - if (memcmp(buf, buf2, wxStrlen(buf)+1) != 0) { - text_win->WriteText("Fail\n"); - sock->Close(); - UpdateStatus(); - } else - text_win->WriteText("done\nTest 1A passed !\n"); - - /* No 2 */ - sock->SetEventHandler(*this, SKDEMO_SCK); - sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); - sock->Notify(TRUE); - text_win->WriteText("Test 1B: sending bytes to the server\n"); - if (!sock->IsData()) - text_win->WriteText("No data to read yet (this is OK)\n"); - - wxYield(); - sock->Write((char *)buf, wxStrlen(buf)+1); - text_win->WriteText("Waiting for incoming bytes (timeout = 2 sec) ..."); - wxYield(); - - m_good = 2; - - MyFrameSocketTimer timer; - - timer.m_var = &m_good; - timer.Start(2000, TRUE); - - while (m_good == 2) - wxYield(); - - if (!m_good) { - text_win->WriteText("timeout ! Failed.\n"); - sock->Close(); - UpdateStatus(); - } else - text_win->WriteText("event ! (no timeout).\n"); - - if (sock->IsData()) - text_win->WriteText("Data is available, as expected...\n"); - - sock->Read((char *)buf2, wxStrlen(buf)+1); - - text_win->WriteText("Success!\n"); - - dlgbox->Layout(); - dlgbox->ShowModal(); + 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; + } - delete [] buf; - delete [] buf2; - delete text_win; - delete dlgbox; + m_text->AppendText(s); + UpdateStatusBar(); } +// convenience functions -void MyFrame::Download(wxInputStream *input) +void MyFrame::UpdateStatusBar() { - wxProgressDialog progress("Downloading ...", "0% downloaded"); - wxFileOutputStream f_out("test.url"); - size_t downloaded; - int BUFSIZE, bytes_read; - size_t file_size; - wxString message; - int percents; - - char *buf; - - if (input->GetSize() == (size_t)-1) { - file_size = (size_t)-1; - bytes_read = BUFSIZE = 10240; - } else { - file_size = input->GetSize(); - if (file_size > 10240) - bytes_read = BUFSIZE = file_size / 1024; - else - bytes_read = BUFSIZE = 1024; - } - buf = new char[BUFSIZE]; + wxString s; - downloaded = 0; - bytes_read = BUFSIZE; - while (downloaded < file_size && bytes_read != 0) { - bytes_read = input->Read(buf, BUFSIZE).LastRead(); - f_out.Write(buf, bytes_read); - downloaded += bytes_read; - - percents = downloaded * 100 / file_size; - - message = _T(""); - message << percents << _T("% downloaded"); - progress.Update(percents, message); + if (!m_sock->IsConnected()) + { + s.Printf(_T("Not connected")); } + else + { + wxIPV4address addr; - delete[] buf; -} - -void MyFrame::OnExecUrlTest(wxCommandEvent& WXUNUSED(evt)) -{ - wxString urlname = wxGetTextFromUser("Enter an URL to get", - "URL:", "http://localhost"); - - wxURL url(urlname); - wxInputStream *datas = url.GetInputStream(); + m_sock->GetPeer(addr); + s.Printf(_T("%s : %d"), (addr.Hostname()).c_str(), addr.Service()); + } - if (!datas) { - wxString error; - error.Printf(_T("Error in getting data from the URL. (error = %d)"), url.GetError()); - wxMessageBox(error, "Alert !"); - } else { - Download(datas); + SetStatusText(s, 1); - delete datas; - } + 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()); } diff --git a/samples/wxsocket/server.cpp b/samples/wxsocket/server.cpp index 1e750a6ffa..087b58ccfb 100644 --- a/samples/wxsocket/server.cpp +++ b/samples/wxsocket/server.cpp @@ -1,194 +1,380 @@ -/* - * File: server.cpp - * Purpose: wxSocket: server demo - * Author: LAVAUX Guilhem - * Created: June 1997 - * CVS Id: $Id$ - * Copyright: (C) 1997, LAVAUX Guilhem - */ +///////////////////////////////////////////////////////////////////////////// +// Name: server.cpp +// Purpose: Server 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 "server.cpp" +# pragma interface "server.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" +# include "wx/socket.h" #endif -#include "wx/socket.h" +// -------------------------------------------------------------------------- +// resources +// -------------------------------------------------------------------------- -#if defined(__WXMOTIF__) || defined(__WXGTK__) -#include "mondrian.xpm" +// the application icon +#if defined(__WXGTK__) || defined(__WXMOTIF__) +# include "mondrian.xpm" #endif +// -------------------------------------------------------------------------- +// classes +// -------------------------------------------------------------------------- + // Define a new application type -class MyApp: public wxApp -{ public: - bool OnInit(void); +class MyApp : public wxApp +{ +public: + virtual bool OnInit(); }; -class MyServer; - -// Define a new frame type -class MyFrame: public wxFrame -{ - DECLARE_EVENT_TABLE() +// Define a new frame type: this is going to be our main frame +class MyFrame : public wxFrame +{ public: - wxSocketServer *sock; - int nb_clients; - - MyFrame(wxFrame *frame); - virtual ~MyFrame(); - void Menu_Exit(wxCommandEvent& evt); - void OnSockRequest(wxSocketEvent& evt); - void OnSockRequestServer(wxSocketEvent& evt); - void ExecTest1(wxSocketBase *sock_o); - void UpdateStatus(int incr); + MyFrame(); + ~MyFrame(); + + // event handlers (these functions should _not_ be virtual) + 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; + wxPanel *m_panel; + wxTextCtrl *m_text; + wxMenu *m_menuFile; + wxMenuBar *m_menuBar; + bool m_busy; + int m_numClients; + + // any class wishing to process wxWindows events must use this macro + DECLARE_EVENT_TABLE() +}; + +// -------------------------------------------------------------------------- +// constants +// -------------------------------------------------------------------------- + +// IDs for the controls and the menu commands +enum +{ + // menu items + SERVER_QUIT = 1000, + SERVER_ABOUT, + + // id for sockets + SERVER_ID, + SOCKET_ID }; -#define SKDEMO_QUIT 101 -#define SKDEMO_SOCKET_SERV 102 -#define SKDEMO_SOCKET 103 +// -------------------------------------------------------------------------- +// event tables and other macros for wxWindows +// -------------------------------------------------------------------------- BEGIN_EVENT_TABLE(MyFrame, wxFrame) - EVT_MENU(SKDEMO_QUIT, MyFrame::Menu_Exit) - EVT_SOCKET(SKDEMO_SOCKET_SERV, MyFrame::OnSockRequestServer) - EVT_SOCKET(SKDEMO_SOCKET, MyFrame::OnSockRequest) + EVT_MENU(SERVER_QUIT, MyFrame::OnQuit) + EVT_MENU(SERVER_ABOUT, MyFrame::OnAbout) + EVT_SOCKET(SERVER_ID, MyFrame::OnServerEvent) + EVT_SOCKET(SOCKET_ID, MyFrame::OnSocketEvent) END_EVENT_TABLE() IMPLEMENT_APP(MyApp) -// `Main program' equivalent, creating windows and returning main app frame -bool MyApp::OnInit(void) -{ - // Create the main frame window - MyFrame *frame = new MyFrame(NULL); - // Give it an icon - frame->SetIcon(wxICON(mondrian)); +// To append sockets for delayed deletion +extern wxList wxPendingDelete; + - // Make a menubar - wxMenu *file_menu = new wxMenu; +// ========================================================================== +// implementation +// ========================================================================== - file_menu->Append(SKDEMO_QUIT, "E&xit"); - wxMenuBar *menu_bar = new wxMenuBar; - menu_bar->Append(file_menu, "File"); - 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); + SetTopWindow(frame); - // Return the main frame window + // success return TRUE; } -extern wxList wxPendingDelete; +// -------------------------------------------------------------------------- +// main frame +// -------------------------------------------------------------------------- -void MyFrame::OnSockRequest(wxSocketEvent& evt) +// frame constructor +MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, -1, + _T("wxSocket demo: Server"), + wxDefaultPosition, wxSize(300, 200)) { - wxSocketBase *sock = evt.Socket(); - - wxPrintf(_T("OnSockRequest OK\n")); - wxPrintf(_T("OnSockRequest (event = %d)\n"),evt.SocketEvent()); - switch (evt.SocketEvent()) { - case wxSOCKET_INPUT: - unsigned char c; - - sock->Read((char *)&c, 1); - if (c == 0xbe) - ExecTest1(sock); - - break; - case wxSOCKET_LOST: - wxPrintf(_T("Destroying socket\n")); - wxPendingDelete.Append(sock); - UpdateStatus(-1); - return; - break; - default: - wxPrintf(_T("Invalid event !\n")); - } - wxPrintf(_T("OnSockRequest Exiting\n")); + // Give the frame an icon + SetIcon(wxICON(mondrian)); + + // Make menus + m_menuFile = new wxMenu(); + m_menuFile->Append(SERVER_ABOUT, _T("&About...\tCtrl-A"), _T("Show about dialog")); + m_menuFile->AppendSeparator(); + m_menuFile->Append(SERVER_QUIT, _T("E&xit\tAlt-X"), _T("Quit server")); + + // Append menus to the menubar + m_menuBar = new wxMenuBar(); + m_menuBar->Append(m_menuFile, _T("&File")); + SetMenuBar(m_menuBar); + + // Status bar + CreateStatusBar(2); + + // 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: Server\n"), + wxPoint(0, 0), m_panel->GetClientSize(), + wxTE_MULTILINE | wxTE_READONLY); + + // Create the socket + wxIPV4address addr; + addr.Service(3000); + + m_server = new wxSocketServer(addr); + m_server->SetEventHandler(*this, SERVER_ID); + m_server->SetNotify(wxSOCKET_CONNECTION_FLAG); + m_server->Notify(TRUE); + + // We use Ok() here to see if the server is really listening + if (m_server->Ok()) + m_text->AppendText(_T("Server listening.\n\n")); + else + m_text->AppendText(_T("Could not listen at the specified port !\n\n")); + + m_busy = FALSE; + m_numClients = 0; + UpdateStatusBar(); } -void MyFrame::OnSockRequestServer(wxSocketEvent& evt) +MyFrame::~MyFrame() { - wxSocketBase *sock2; - wxSocketServer *server = (wxSocketServer *) evt.Socket(); + delete m_server; +} - wxPrintf(_T("OnSockRequestServer OK\n")); - wxPrintf(_T("OnSockRequest (event = %d)\n"), evt.SocketEvent()); +// event handlers - sock2 = server->Accept(FALSE); - if (sock2 == NULL) - return; +void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + // TRUE is to force the frame to close + Close(TRUE); +} - UpdateStatus(1); - sock2->SetFlags(wxSocketBase::NONE); - sock2->Notify(TRUE); - sock2->SetEventHandler(*this, SKDEMO_SOCKET); - sock2->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); +void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + wxMessageBox(_T("wxSocket demo: Server\n") + _T("(c) 1999 Guillermo Rodriguez Garcia\n"), + _T("About Server"), + wxOK | wxICON_INFORMATION, this); } -// My frame Constructor -MyFrame::MyFrame(wxFrame *frame): - wxFrame(frame, -1, "wxSocket sample (server)", wxDefaultPosition, - wxSize(300, 200)) +void MyFrame::Test1(wxSocketBase *sock) { - wxIPV4address addr; - addr.Service(3000); + unsigned char len; + char *buf; - // Init all + m_text->AppendText(_T("Test 1 begins\n")); - sock = new wxSocketServer(addr); - sock->SetNotify(wxSOCKET_CONNECTION_FLAG); - sock->SetEventHandler(*this, SKDEMO_SOCKET_SERV); - sock->SetFlags(wxSocketBase::SPEED); - sock->Notify(TRUE); - nb_clients = 0; - CreateStatusBar(1); - UpdateStatus(0); + // 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 WAITALL flag. Also, we disabled + // input events so we won't have unwanted reentrance. This + // way we can avoid the infamous BLOCK (formerly SPEED) flag. + // + sock->SetFlags(wxSOCKET_WAITALL); + + sock->Read((char *)&len, 1); + + buf = (char *)malloc(len); + sock->Read(buf, len); + sock->Write(buf, len); + free(buf); + + m_text->AppendText(_T("Test 1 ends\n")); } -MyFrame::~MyFrame() +void MyFrame::Test2(wxSocketBase *sock) { - delete sock; +#define MAX_MSG_SIZE 10000 + + wxString s; + char *buf = (char *)malloc(MAX_MSG_SIZE); + wxUint32 len; + + m_text->AppendText(_T("Test 2 begins\n")); + + // We don't need to set flags because ReadMsg and WriteMsg + // are not affected by them anyway. + // + len = sock->ReadMsg(buf, MAX_MSG_SIZE).LastCount(); + + s.Printf(_T("Client says: %s\n"), buf); + m_text->AppendText(s); + + sock->WriteMsg(buf, len); + free(buf); + + m_text->AppendText(_T("Test 2 ends\n")); + +#undef MAX_MSG_SIZE } -// Intercept menu commands -void MyFrame::Menu_Exit(wxCommandEvent& WXUNUSED(event)) +void MyFrame::Test3(wxSocketBase *sock) { - Close(TRUE); + m_text->AppendText(_T("Test 3 begins\n")); + m_text->AppendText(_T("(not implemented)\n")); + m_text->AppendText(_T("Test 3 ends\n")); } -void MyFrame::ExecTest1(wxSocketBase *sock_o) +void MyFrame::OnServerEvent(wxSocketEvent& event) { - char *buf = new char[50]; - size_t l; + wxString s = _T("OnServerEvent: "); + wxSocketBase *sock; + + switch(event.SocketEvent()) + { + case wxSOCKET_CONNECTION : s.Append(_T("wxSOCKET_CONNECTION\n")); break; + default : s.Append(_T("Unexpected event !\n")); break; + } - l = sock_o->Read(buf, 50).LastCount(); - sock_o->Write(buf, l); - l = sock_o->Read(buf, 50).LastCount(); - sock_o->Write(buf, l); + m_text->AppendText(s); - delete[] buf; + // 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) + { + m_text->AppendText(_T("New client connection accepted\n")); + } + else + { + m_text->AppendText(_T("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::UpdateStatus(int incr) +void MyFrame::OnSocketEvent(wxSocketEvent& event) +{ + wxSocketBase *sock = event.Socket(); + wxString s = _T("OnSocketEvent: "); + + // We first print a msg + switch(event.SocketEvent()) + { + case wxSOCKET_INPUT: s.Append(_T("wxSOCKET_INPUT\n")); break; + case wxSOCKET_LOST: s.Append(_T("wxSOCKET_LOST\n")); break; + default: s.Append(_T("unexpected event !\n")); + } + + m_text->AppendText(s); + + // Now we process the event + switch(event.SocketEvent()) + { + 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((char *)&c ,1); + + switch (c) + { + case 0xBE: Test1(sock); break; + case 0xCE: Test2(sock); break; + case 0xDE: Test3(sock); break; + default: s.Append(_T("Unknown test id received from client\n")); + } + + // Enable input events again. + sock->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG); + break; + } + case wxSOCKET_LOST: + { + m_numClients--; + + // We cannot delete the socket right now because we can + // be in the middle of a test or something. So we append + // it to the list of objects to be deleted. + m_text->AppendText(_T("Deleting socket.\n")); + wxPendingDelete.Append(sock); + break; + } + default: ; + } + + UpdateStatusBar(); +} + +// convenience functions + +void MyFrame::UpdateStatusBar() { - wxChar s[30]; - nb_clients += incr; - wxSprintf(s, _T("%d clients connected"), nb_clients); - SetStatusText(s); + wxString s; + s.Printf(_T("%d clients connected"), m_numClients); + SetStatusText(s, 1); } -- 2.45.2