Please help with memory leak !!!
Petr Chládek
pchladek at retia.cz
Fri Aug 24 03:59:17 PDT 2007
Hi,
I'm using wxGTK-2.8.4 (Suse 9.3) and I probably noticed a memory leak. I saw increasing TCP server memory need with htop (column RES) during receiving data (top is insufficient because of it shows RES in MBytes). I adjusted examples/sockets/client.cpp and server.cpp for better demonstration (see below). TCP client is sending data (very fast - with 32 ms interval) and TCP server is receiving it without any logging.
When I'm using wxGTK-2.6.3 or wxMSW-2.8.4 there's no problem.
Thanks
Petr Chladek
Using example: Connect a client to server and run Test1. After 1 minute
you'll see growing memory allocation for server.
---------------------------- server.cpp -------------------------------------
/////////////////////////////////////////////////////////////////////////////
// Name: server.cpp
// Purpose: Server for wxSocket demo
// Author: Guillermo Rodriguez Garcia <guille at iies.es>
// Modified by:
// Created: 1999/09/19
// RCS-ID: $Id: server.cpp,v 1.21 2005/09/23 12:52:25 MR Exp $
// Copyright: (c) 1999 Guillermo Rodriguez Garcia
// 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/socket.h"
// --------------------------------------------------------------------------
// resources
// --------------------------------------------------------------------------
// the application icon
#if defined( WXGTK ) || defined( WXX11 ) || defined( WXMOTIF ) ||
defined( WXMAC )
# include "mondrian.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 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
DECLARE EVENT TABLE()
};
// --------------------------------------------------------------------------
// constants
// --------------------------------------------------------------------------
// IDs for the controls and the menu commands
enum
{
// menu items
SERVER QUIT = wxID EXIT,
SERVER ABOUT = wxID ABOUT,
// id for sockets
SERVER ID = 100,
SOCKET ID
};
// --------------------------------------------------------------------------
// event tables and other macros for wxWidgets
// --------------------------------------------------------------------------
BEGIN EVENT TABLE(MyFrame, wxFrame)
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)
// ==========================================================================
// implementation
// ==========================================================================
// --------------------------------------------------------------------------
// the application class
// --------------------------------------------------------------------------
bool MyApp::OnInit()
{
// Create the main application window
MyFrame *frame = new MyFrame();
// Show it and tell the application that it's our main window
frame->Show(true);
SetTopWindow(frame);
// 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(mondrian));
// Make menus
m menuFile = new wxMenu();
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);
// Create the address - defaults to localhost:0 initially
wxIPV4address addr;
addr.Service(3000);
// Create the socket
m server = new wxSocketServer(addr);
// We use Ok() here to see if the server is really listening
if (! m server->Ok())
{
m text->AppendText( ("Could not listen at the specified port !\n\n"));
return;
}
else
{
m text->AppendText( ("Server listening.\n\n"));
}
// 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::Test1(wxSocketBase *sock)
{
unsigned char len;
char *buf;
//m text->AppendText( ("Test 1 begins\n"));
// 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
sock->Read(&len, 1);
buf = new char[len];
// Read the data
sock->Read(buf, len);
//m text->AppendText( ("Got the data, sending it back\n"));
// Write it back
sock->Write(buf, len);
delete[] buf;
//m text->AppendText( ("Test 1 ends\n\n"));
}
void MyFrame::Test2(wxSocketBase *sock)
{
#define MAX MSG SIZE 10000
wxString s;
wxChar *buf = new wxChar[MAX MSG SIZE];
wxUint32 len;
m text->AppendText( ("Test 2 begins\n"));
// We don't need to set flags because ReadMsg and WriteMsg
// are not affected by them anyway.
// Read the message
len = sock->ReadMsg(buf, MAX MSG SIZE * sizeof(wxChar)).LastCount();
s.Printf( ("Client says: %s\n"), buf);
m text->AppendText(s);
m text->AppendText( ("Sending the data back\n"));
// Write it back
sock->WriteMsg(buf, len);
delete[] buf;
m text->AppendText( ("Test 2 ends\n\n"));
#undef MAX MSG SIZE
}
void MyFrame::Test3(wxSocketBase *sock)
{
unsigned char len;
char *buf;
m text->AppendText( ("Test 3 begins\n"));
// 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
sock->Read(&len, 1);
buf = new char[len * 1024];
// Read the data
sock->Read(buf, len * 1024);
m text->AppendText( ("Got the data, sending it back\n"));
// Write it back
sock->Write(buf, len * 1024);
delete[] buf;
m text->AppendText( ("Test 3 ends\n\n"));
}
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)
{
m text->AppendText( ("New client connection accepted\n\n"));
}
else
{
m text->AppendText( ("Error: couldn't accept a new connection\n\n"));
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:
m text->AppendText( ("Unknown test id received from client\n\n"));
}
// 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.
m text->AppendText( ("Deleting socket.\n\n"));
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
}
--------------------------------------- client.cpp ---------------------
/////////////////////////////////////////////////////////////////////////////
// Name: client.cpp
// Purpose: Client for wxSocket demo
// Author: Guillermo Rodriguez Garcia <guille at iies.es>
// Modified by:
// Created: 1999/09/19
// RCS-ID: $Id: client.cpp,v 1.33 2005/09/23 12:52:25 MR Exp $
// Copyright: (c) 1999 Guillermo Rodriguez Garcia
// 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/socket.h"
#include "wx/url.h"
#include "wx/wfstream.h"
#include "wx/utils.h"
// --------------------------------------------------------------------------
// resources
// --------------------------------------------------------------------------
// the application icon
#if defined( WXGTK ) || defined( WXX11 ) || defined( WXMOTIF ) ||
defined( WXMAC )
# include "mondrian.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 for File menu
void OnQuit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
// event handlers for Socket menu
void OnOpenConnection(wxCommandEvent& event);
void OnTest1(wxCommandEvent& event);
void OnTest2(wxCommandEvent& event);
void OnTest3(wxCommandEvent& event);
void OnCloseConnection(wxCommandEvent& event);
#if wxUSE URL
// event handlers for Protocols menu
void OnTestURL(wxCommandEvent& event);
#endif
// event handlers for DatagramSocket menu (stub)
void OnDatagram(wxCommandEvent& event);
// socket event handler
void OnSocketEvent(wxSocketEvent& event);
// convenience functions
void UpdateStatusBar();
private:
wxSocketClient *m sock;
wxTextCtrl *m text;
wxMenu *m menuFile;
wxMenu *m menuSocket;
wxMenu *m menuDatagramSocket;
wxMenu *m menuProtocols;
wxMenuBar *m menuBar;
bool m busy;
// any class wishing to process wxWidgets events must use this macro
DECLARE EVENT TABLE()
};
// --------------------------------------------------------------------------
// constants
// --------------------------------------------------------------------------
// IDs for the controls and the menu commands
enum
{
// menu items
CLIENT QUIT = wxID EXIT,
CLIENT ABOUT = wxID ABOUT,
CLIENT OPEN = 100,
CLIENT TEST1,
CLIENT TEST2,
CLIENT TEST3,
CLIENT CLOSE,
#if wxUSE URL
CLIENT TESTURL,
#endif
CLIENT DGRAM,
// id for socket
SOCKET ID
};
// --------------------------------------------------------------------------
// event tables and other macros for wxWidgets
// --------------------------------------------------------------------------
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 MENU(CLIENT DGRAM, MyFrame::OnDatagram)
#if wxUSE URL
EVT MENU(CLIENT TESTURL, MyFrame::OnTestURL)
#endif
EVT SOCKET(SOCKET ID, MyFrame::OnSocketEvent)
END EVENT TABLE()
IMPLEMENT APP(MyApp)
// ==========================================================================
// implementation
// ==========================================================================
// --------------------------------------------------------------------------
// the application class
// --------------------------------------------------------------------------
bool MyApp::OnInit()
{
// Create the main application window
MyFrame *frame = new MyFrame();
// Show it and tell the application that it's our main window
frame->Show(true);
SetTopWindow(frame);
// success
return true;
}
// --------------------------------------------------------------------------
// main frame
// --------------------------------------------------------------------------
// frame constructor
MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, wxID ANY,
("wxSocket demo: Client"),
wxDefaultPosition, wxSize(300, 200))
{
// Give the frame an icon
SetIcon(wxICON(mondrian));
// Make menus
m menuFile = new wxMenu();
m menuFile->Append(CLIENT ABOUT, ("&About...\tCtrl-A"), ("Show about
dialog"));
m menuFile->AppendSeparator();
m menuFile->Append(CLIENT QUIT, ("E&xit\tAlt-X"), ("Quit client"));
m menuSocket = new wxMenu();
m menuSocket->Append(CLIENT OPEN, ("&Open session"), ("Connect to
server"));
m menuSocket->AppendSeparator();
m menuSocket->Append(CLIENT TEST1, ("Test &1"), ("Test basic
functionality"));
m menuSocket->Append(CLIENT TEST2, ("Test &2"), ("Test ReadMsg and
WriteMsg"));
m menuSocket->Append(CLIENT TEST3, ("Test &3"), ("Test large data
transfer"));
m menuSocket->AppendSeparator();
m menuSocket->Append(CLIENT CLOSE, ("&Close session"), ("Close
connection"));
m menuDatagramSocket = new wxMenu();
m menuDatagramSocket->Append(CLIENT DGRAM, ("Send Datagram"), ("Test UDP
sockets"));
#if wxUSE URL
m menuProtocols = new wxMenu();
m menuProtocols->Append(CLIENT TESTURL, ("Test URL"), ("Get data from the
specified URL"));
#endif
// Append menus to the menubar
m menuBar = new wxMenuBar();
m menuBar->Append(m menuFile, ("&File"));
m menuBar->Append(m menuSocket, ("&SocketClient"));
m menuBar->Append(m menuDatagramSocket, ("&DatagramSocket"));
#if wxUSE URL
m menuBar->Append(m menuProtocols, ("&Protocols"));
#endif
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: Client\nClient
ready\n"),
wxDefaultPosition, wxDefaultSize,
wxTE MULTILINE | wxTE READONLY);
// Create the socket
m sock = new wxSocketClient();
// Setup the event handler and subscribe to most events
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()
{
// No delayed deletion here, as the frame is dying anyway
delete m sock;
}
// 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: Client\n(c) 1999 Guillermo Rodriguez
Garcia\n"),
("About Client"),
wxOK | wxICON INFORMATION, this);
}
void MyFrame::OnOpenConnection(wxCommandEvent& WXUNUSED(event))
{
wxIPV4address addr;
m menuSocket->Enable(CLIENT OPEN, false);
m menuSocket->Enable(CLIENT CLOSE, false);
// Ask user for server address
wxString hostname = wxGetTextFromUser(
("Enter the address of the wxSocket demo server:"),
("Connect ..."),
("localhost"));
addr.Hostname(hostname);
addr.Service(3000);
// Mini-tutorial for Connect() :-)
// ---------------------------
//
// There are two ways to use Connect(): blocking and non-blocking,
// depending on the value passed as the 'wait' (2nd) parameter.
//
// Connect(addr, true) will wait until the connection completes,
// returning true on success and false on failure. This call blocks
// the GUI (this might be changed in future releases to honour the
// wxSOCKET BLOCK flag).
//
// Connect(addr, false) will issue a nonblocking connection request
// and return immediately. If the return value is true, then the
// connection has been already successfully established. If it is
// false, you must wait for the request to complete, either with
// WaitOnConnect() or by watching wxSOCKET CONNECTION / LOST
// events (please read the documentation).
//
// WaitOnConnect() itself never blocks the GUI (this might change
// in the future to honour the wxSOCKET BLOCK flag). This call will
// return false on timeout, or true if the connection request
// completes, which in turn might mean:
//
// a) That the connection was successfully established
// b) That the connection request failed (for example, because
// it was refused by the peer.
//
// Use IsConnected() to distinguish between these two.
//
// So, in a brief, you should do one of the following things:
//
// For blocking Connect:
//
// bool success = client->Connect(addr, true);
//
// For nonblocking Connect:
//
// client->Connect(addr, false);
//
// bool waitmore = true;
// while (! client->WaitOnConnect(seconds, millis) && waitmore )
// {
// // possibly give some feedback to the user,
// // update waitmore if needed.
// }
// bool success = client->IsConnected();
//
// And that's all :-)
m text->AppendText( ("\nTrying to connect (timeout = 10 sec) ...\n"));
m sock->Connect(addr, false);
m sock->WaitOnConnect(10);
if (m sock->IsConnected())
m text->AppendText( ("Succeeded ! Connection established\n"));
else
{
m sock->Close();
m text->AppendText( ("Failed ! Unable to connect\n"));
wxMessageBox( ("Can't connect to the specified host"), ("Alert !"));
}
UpdateStatusBar();
}
void MyFrame::OnTest1(wxCommandEvent& WXUNUSED(event))
{
const wxChar *buf1;
wxChar *buf2;
unsigned char len;
while( 1 )
{
// Disable socket menu entries (exception: Close Session)
m busy = true;
UpdateStatusBar();
m text->AppendText( ("\n=== Test 1 begins ===\n"));
// Tell the server which test we are running
unsigned 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 wxSOCKET WAITALL flag. Also,
// we have disabled menu entries which could interfere with
// the test, so we can safely avoid the wxSOCKET BLOCK 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" across the network, or
// you might be in trouble! Ever heard about big and little
// endian computers?)
m sock->SetFlags(wxSOCKET WAITALL);
buf1 = ("Test string (less than 256 chars!)");
len = (unsigned char)((wxStrlen(buf1) + 1) * sizeof(wxChar));
buf2 = new wxChar[wxStrlen(buf1) + 1];
m text->AppendText( ("Sending a test buffer to the server ..."));
m sock->Write(&len, 1);
m sock->Write(buf1, len);
m text->AppendText(m sock->Error() ? ("failed !\n") : ("done\n"));
m text->AppendText( ("Receiving the buffer back from server ..."));
m sock->Read(buf2, len);
m text->AppendText(m sock->Error() ? ("failed !\n") : ("done\n"));
m text->AppendText( ("Comparing the two buffers ..."));
if (memcmp(buf1, buf2, len) != 0)
{
m text->AppendText( ("failed!\n"));
m text->AppendText( ("Test 1 failed !\n"));
}
else
{
m text->AppendText( ("done\n"));
m text->AppendText( ("Test 1 passed !\n"));
}
m text->AppendText( ("=== Test 1 ends ===\n"));
delete[] buf2;
m busy = false;
UpdateStatusBar();
wxMilliSleep( 32 );
}
}
void MyFrame::OnTest2(wxCommandEvent& WXUNUSED(event))
{
const wxChar *msg1;
wxChar *msg2;
size t len;
// Disable socket menu entries (exception: Close Session)
m busy = true;
UpdateStatusBar();
m text->AppendText( ("\n=== Test 2 begins ===\n"));
// Tell the server which test we are running
unsigned 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(
("Enter an arbitrary string to send to the server:"),
("Test 2 ..."),
("Yes I like wxWidgets!"));
msg1 = s.c str();
len = (wxStrlen(msg1) + 1) * sizeof(wxChar);
msg2 = new wxChar[wxStrlen(msg1) + 1];
m text->AppendText( ("Sending the string with WriteMsg ..."));
m sock->WriteMsg(msg1, len);
m text->AppendText(m sock->Error() ? ("failed !\n") : ("done\n"));
m text->AppendText( ("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( ("Reading the string back with ReadMsg ..."));
m sock->ReadMsg(msg2, len);
m text->AppendText(m sock->Error() ? ("failed !\n") : ("done\n"));
m text->AppendText( ("Comparing the two buffers ..."));
if (memcmp(msg1, msg2, len) != 0)
{
m text->AppendText( ("failed!\n"));
m text->AppendText( ("Test 2 failed !\n"));
}
else
{
m text->AppendText( ("done\n"));
m text->AppendText( ("Test 2 passed !\n"));
}
}
else
m text->AppendText( ("Timeout ! Test 2 failed.\n"));
m text->AppendText( ("=== Test 2 ends ===\n"));
delete[] msg2;
m busy = false;
UpdateStatusBar();
}
void MyFrame::OnTest3(wxCommandEvent& WXUNUSED(event))
{
char *buf1;
char *buf2;
unsigned char len;
// Disable socket menu entries (exception: Close Session)
m busy = true;
UpdateStatusBar();
m text->AppendText( ("\n=== Test 3 begins ===\n"));
// Tell the server which test we are running
unsigned char c = 0xDE;
m sock->Write(&c, 1);
// This test also is similar to the first one but it sends a
// large buffer so that wxSocket is actually forced to split
// it into pieces and take care of sending everything before
// returning.
m sock->SetFlags(wxSOCKET WAITALL);
// Note that len is in kbytes here!
len = 32;
buf1 = new char[len * 1024];
buf2 = new char[len * 1024];
for (int i = 0; i < len * 1024; i ++)
buf1[i] = (char)(i % 256);
m text->AppendText( ("Sending a large buffer (32K) to the server ..."));
m sock->Write(&len, 1);
m sock->Write(buf1, len * 1024);
m text->AppendText(m sock->Error() ? ("failed !\n") : ("done\n"));
m text->AppendText( ("Receiving the buffer back from server ..."));
m sock->Read(buf2, len * 1024);
m text->AppendText(m sock->Error() ? ("failed !\n") : ("done\n"));
m text->AppendText( ("Comparing the two buffers ..."));
if (memcmp(buf1, buf2, len) != 0)
{
m text->AppendText( ("failed!\n"));
m text->AppendText( ("Test 3 failed !\n"));
}
else
{
m text->AppendText( ("done\n"));
m text->AppendText( ("Test 3 passed !\n"));
}
m text->AppendText( ("=== Test 3 ends ===\n"));
delete[] buf2;
m busy = false;
UpdateStatusBar();
}
void MyFrame::OnCloseConnection(wxCommandEvent& WXUNUSED(event))
{
m sock->Close();
UpdateStatusBar();
}
void MyFrame::OnDatagram(wxCommandEvent& WXUNUSED(event))
{
m text->AppendText( ("\n=== Datagram test begins ===\n"));
m text->AppendText( ("Sorry, not implemented\n"));
m text->AppendText( ("=== Datagram test ends ===\n"));
}
#if wxUSE URL
void MyFrame::OnTestURL(wxCommandEvent& WXUNUSED(event))
{
// Note that we are creating a new socket here, so this
// won't mess with the client/server demo.
// Ask for the URL
m text->AppendText( ("\n=== URL test begins ===\n"));
wxString urlname = wxGetTextFromUser( ("Enter an URL to get"),
("URL:"),
T("http://localhost"));
// Parse the URL
wxURL url(urlname);
if (url.GetError() != wxURL NOERR)
{
m text->AppendText( ("Error: couldn't parse URL\n"));
m text->AppendText( ("=== URL test ends ===\n"));
return;
}
// Try to get the input stream (connects to the given URL)
m text->AppendText( ("Trying to establish connection...\n"));
wxYield();
wxInputStream *data = url.GetInputStream();
if (!data)
{
m text->AppendText( ("Error: couldn't read from URL\n"));
m text->AppendText( ("=== URL test ends ===\n"));
return;
}
// Print the contents type and file size
wxString s;
s.Printf( ("Contents type: %s\nFile size: %i\nStarting to download...\n"),
url.GetProtocol().GetContentType().c str(),
data->GetSize());
m text->AppendText(s);
wxYield();
// Get the data
wxFile fileTest(wxT("test.url"), wxFile::write);
wxFileOutputStream sout(fileTest);
if (!sout.Ok())
{
m text->AppendText( ("Error: couldn't open file for output\n"));
m text->AppendText( ("=== URL test ends ===\n"));
return;
}
data->Read(sout);
m text->AppendText( ("Results written to file: test.url\n"));
m text->AppendText( ("Done.\n"));
m text->AppendText( ("=== URL test ends ===\n"));
delete data;
}
#endif
void MyFrame::OnSocketEvent(wxSocketEvent& event)
{
wxString s = ("OnSocketEvent: ");
switch(event.GetSocketEvent())
{
case wxSOCKET INPUT : s.Append( ("wxSOCKET INPUT\n")); break;
case wxSOCKET LOST : s.Append( ("wxSOCKET LOST\n")); break;
case wxSOCKET CONNECTION : s.Append( ("wxSOCKET CONNECTION\n")); break;
default : s.Append( ("Unexpected event !\n")); break;
}
m text->AppendText(s);
UpdateStatusBar();
}
// convenience functions
void MyFrame::UpdateStatusBar()
{
wxString s;
if (!m sock->IsConnected())
{
s.Printf( ("Not connected"));
}
else
{
wxIPV4address addr;
m sock->GetPeer(addr);
s.Printf( ("%s : %d"), (addr.Hostname()).c str(), addr.Service());
}
#if wxUSE STATUSBAR
SetStatusText(s, 1);
#endif // wxUSE STATUSBAR
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());
}
More information about the wx-users
mailing list