Socket Read blocks indefinitely

Do you have a typical platform dependent issue you're battling with ? Ask it here. Make sure you mention your platform, compiler, and wxWidgets version.
Post Reply
johnnie
Experienced Solver
Experienced Solver
Posts: 64
Joined: Mon Jan 14, 2008 8:59 am
Location: Bangalore
Contact:

Socket Read blocks indefinitely

Post by johnnie » Fri Jul 30, 2010 7:37 am

Hi all,

I am currently working on wxWidgets windows version. I have a serious issue with the read. In order to reproduce this issue, i have changed the sample application provided with wxWidgets for your reference.

The sample code is used with slight change in the client.cpp.
Instead of one client, I have created two clients. Both of the clients writes the data successfully to the server one after another.

At the server side the INPUT event gets generated for the first client. When server starts reading the data, another INPUT event for the second client is received. So the server tries to read the data. The servers completely blocks and the CPU usage goes beyond 50%.

Please help

Regards
Johnnie Alan J

GCC version : 4.5
wxWidgets : 2.8.11
OS : windows XP, service pack 3
--johnniealan --

johnnie
Experienced Solver
Experienced Solver
Posts: 64
Joined: Mon Jan 14, 2008 8:59 am
Location: Bangalore
Contact:

Post by johnnie » Fri Jul 30, 2010 8:35 am

Attaching the file
Attachments
sockets.zip
(50.51 KiB) Downloaded 57 times
--johnniealan --

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Fri Jul 30, 2010 2:19 pm

Can you use a debugger to see precisely where it blocks?
"Keyboard not detected. Press F1 to continue"
-- Windows

johnnie
Experienced Solver
Experienced Solver
Posts: 64
Joined: Mon Jan 14, 2008 8:59 am
Location: Bangalore
Contact:

Post by johnnie » Tue Aug 03, 2010 11:43 am

There is a bug reported for the same problem. I have over come this issue by setting the flags of the client to wxSOCKET_BLOCK| wxSOCKET_NOWAIT.

After resolving this I am facing a new problem related to threads and sockets.

I am creating two client sockets on client.cpp's main thread. I continuously peek on the second socket for any data. If I block the main thread using wxCondition, the secondary thread also blocks on the socket. The data written on the second client from the the server, it doesn't reach the client.

Server Code

Code: Select all

void MyFrame::Test2(wxSocketBase *sock)
{
	const wxChar *buf1;
	wxChar       *buf2;
	unsigned char len;

	buf1 = _("Test string (Broadcast)");
	len  = (unsigned char)((wxStrlen(buf1) + 1) * sizeof(wxChar));

	m_text->AppendText(_("Writing data to the clients\n\n"));
	m_client1->Write(&len, 1);
	m_client1->Write(buf1, len);

	m_client2->Write(&len, 1);
	m_client2->Write(buf1, len);

	m_text->AppendText(_("Test 2 ends\n\n"));

}
Client code taken from socket samples

Code: Select all

/////////////////////////////////////////////////////////////////////////////
// Name:        client.cpp
// Purpose:     Client for wxSocket demo
// Author:      Guillermo Rodriguez Garcia <[email protected]>
// Modified by:
// Created:     1999/09/19
// RCS-ID:      $Id: client.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"
#include "wx/url.h"
#include "wx/wfstream.h"
#include <stdio.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 OnCloseConnection(wxCommandEvent& event);

  // 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;
  wxSocketClient *m_sock2;
  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()
};
class clientThread :wxThread
{
	public:
	wxTextCtrl *m_text2;
	MyFrame *frame;
	wxSocketClient *m_sock;
	clientThread( wxTextCtrl *m_text,wxSocketClient *m_sock2,MyFrame *obj):wxThread(wxTHREAD_JOINABLE)
	{
		frame = obj;
		m_sock = m_sock2;
		m_text2 =m_text;
	}

	/*thread execution starts here*/
  virtual void *Entry(void);
  void create(void);
};
// --------------------------------------------------------------------------
// 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_CLOSE,    MyFrame::OnCloseConnection)
  EVT_MENU(CLIENT_DGRAM,    MyFrame::OnDatagram)
  EVT_SOCKET(SOCKET_ID,     MyFrame::OnSocketEvent)
END_EVENT_TABLE()

IMPLEMENT_APP(MyApp)

// ==========================================================================
// implementation
// ==========================================================================

// --------------------------------------------------------------------------
// the application class
// --------------------------------------------------------------------------
void *clientThread::Entry(void)
{
	unsigned char ulength =0;
	const wxChar *buf1;

	wxChar       *buf2;
	unsigned char len;
	unsigned char c = 0xBE;
	char *buf3;
	buf1 = _("Test string (less than 256 chars for socket 2!)");
	len  = (unsigned char)((wxStrlen(buf1) + 1) * sizeof(wxChar));
	buf2 = new wxChar[wxStrlen(buf1) + 1];
	m_sock->Write(&c, 1);
	//  m_text->AppendText(_("\nChar (%d) for socket 2\n"),m_sock2->LastCount());
	m_sock->Write(&len, 1);
	//  m_text->AppendText(_("\nlength sent (%d) for socket 2\n"),m_sock2->LastCount());
	m_sock->Write(buf1, len);
	m_text2->AppendText(_("\nData sent for socket 2\n"));
	while (TRUE)
	{
		m_text2->AppendText(_("\n Peeking the data\n"));
		printf("Peeking the data\n");
                // If main thread is blocked, this Peek always returns Zero.
		m_sock->Peek(&ulength,1);
		printf("Peeking the data: %d",ulength);
		if ( ulength == 0)
		{
			 continue;
		}
		printf("Reading the data: %d",ulength);
	//	m_text2->AppendText(_("\n Reading the data\n"));
		buf3 = new char[ulength];
		if ( buf3 != NULL )
		{
			m_sock->Read(buf3,ulength);
                        break;
		}
	printf("%s\n",buf3);
	
	}
}
void clientThread::create(void)
{
	// create secondary thread
	Create();
	Run();
}

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 sockets
  m_sock = new wxSocketClient();
  m_sock2 = new wxSocketClient();

  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;

  const wxChar *buf1;
  wxChar       *buf2;

  unsigned char len;
  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);

   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 !"));
  }
  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 ..."));

  // created Client two for testing
  m_sock2->Connect(addr, false);
  m_sock2->WaitOnConnect(10);

  if (m_sock2->IsConnected())
	m_text->AppendText(_("Succeeded ! Connection established\n"));
  else
  {
	m_sock2->Close();
	m_text->AppendText(_("Failed ! Unable to connect\n"));
	wxMessageBox(_("Can't connect to the specified host"), _("Alert !"));
  }
  m_sock2->SetTimeout(5);

  m_text->AppendText(_("Sending a test buffer to the server ..."));
  unsigned char c = 0xBE;
  m_sock->Write(&c, 1);
  m_sock->Write(&len, 1);
  m_sock->Write(buf1, len);
  m_text->AppendText(_("\nData sent for socket 1\n"));

  // create thread for listening
  clientThread *cltThread = new clientThread(m_text,m_sock2,this);
	cltThread->create();

UpdateStatusBar();
}

void MyFrame::OnTest1(wxCommandEvent& WXUNUSED(event))
{

	wxMutex *pMutexNotify = new wxMutex;
	wxCondition *pConditionNotify = new wxCondition(*pMutexNotify);

	if ((pMutexNotify->Lock()) != wxMUTEX_NO_ERROR  )
	{
		 m_text->AppendText(_("Mutex Error in NOTIFY()"));
	}
	else
	{
		 m_text->AppendText(_("Mutex SUCCESS in NOTIFY()"));
	}
#if 0
	unsigned char c = 0xCE;
  	m_sock->Write(&c, 1);
#endif
	if ((pConditionNotify->Wait()) != wxCOND_NO_ERROR)
	{
		m_text->AppendText(_("Condition Wait Error in NOTIFY()"));
	}
	else
	{
		m_text->AppendText(_("Condition Wait SUCCESS in NOTIFY()"));
	}

}

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"));
}


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());
}
--johnniealan --

Post Reply