wxWidgets Socket Server Beispiel memory leak?
-
Guten Tag,
ich habe mir das wxWidgets Socket Server Beispiel mal genauer angeguckt und meine ein memory leak entdeckt zu haben.
Wenn der Server geöffnet ist und ein Client sich verbindet, müsste ein memory leak entstehen, wenn nun einfach der Server geschlossen wird, da nur das Server socket deleted wird, nicht aber das Client socket. Habe ich Recht?
Hier ist nochmal das Socket Server Beispiel:
///////////////////////////////////////////////////////////////////////////// // Name: server.cpp // Purpose: Server for wxSocket demo // Author: Guillermo Rodriguez Garcia <guille@iies.es> // Modified by: // Created: 1999/09/19 // RCS-ID: $Id: server.cpp 35650 2005-09-23 12:56:45Z MR $ // 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 }
Mit freundlichen Grüßen,
DarkBug
-
Die Antwort auf diese Frage ist momentan ziemlich wichtig für mein Projekt. Bitte helft mir.
-
Nein, sehe da kein memleak. Das Clientsocket wird ja auch nirgends im sichtbaren code mit new erzeugt.
Lebt also evtl. nur so lange wie das Event Objekt.Wenns nur um die Sockets geht: boost::asio kann hier auch eine sehr gute Alternative sein.
-
event.GetSocket(), als auch m_server->Accept(false) legen bei einer neuen Verbindung mit new ein neues Socket an und geben einen Pointer darauf zurück. Wenn nun Beispielsweise jedoch ein wxSOCKET_INPUT Event auftritt, gibt event.GetSocket() den Pointer zu dem bereits erzeugten Socket zurück. Da bei einem wxSOCKET_LOST Event das passende Socket gelöscht wird, tritt kein memleak auf, wenn der Server geschlossen wird, nachdem alle Clients disconnected sind.
Ich habe den Client Socket Pointer als Membervariable der Klasse MyFrame hinzugefügt und im Destruktor habe ich ein "delete sock;" hinzugefügt.
Test 1:
-Server geöffnet
-Server geschlossenErgebnis: Fehlermeldung, wie zu erwarten, da der Pointer auf einen Randomwert initialisiert wurde, wo kein Objekt liegt, weil der Pointer im Konstruktor nicht auf NULL gesetzt wurde.
Test2:
-Server geöffnet
-Einen Client verbunden
-Test 1 durchgeführt, damit der Pointer durch event.GetSocket() korrekt gesetzt ist
-Server geschlossenErgebnis: Keine Fehlermeldung, wie erwartet, da der Pointer auf das noch nicht gelöschte Client Socket zeigt und dieses dann löscht.
Folglich entstehen memleaks, wenn der Server geschlossen wird und noch Clients verbunden sind. Oder sehe ich das falsch?
-
*push*
-
Mag das jemand debuggen, um meine Aussage zu überprüfen?