wxSocketClient silently stops receiving messages

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
User avatar
zoxks
In need of some credit
In need of some credit
Posts: 8
Joined: Tue Apr 27, 2021 11:38 pm

wxSocketClient silently stops receiving messages

Post by zoxks » Thu May 13, 2021 4:26 pm

I have a setup where a TCP server sends me \n terminated messages every 30ms or so, and I am trying to receive them with wxSocketClient. All works well, and my parsing works great for about 5-6 seconds, then wxSocketClient just stops emitting socket events. I've checked the server and it is still sending the same messages to what it thinks is a valid socket, but I just don't receive them.
My receiving code looks like this:

Code: Select all

void Sockhop::OnSocketEvent(wxSocketEvent& event)
{
	cout << "Event" << "\n";
	wxSocketBase* sockBase = event.GetSocket();

	switch (event.GetSocketEvent())
	{
	case wxSOCKET_INPUT:
	{

		// Disable input events while parsing;
		sockBase->SetNotify(wxSOCKET_LOST_FLAG);
		sockBase->SetFlags(wxSOCKET_WAITALL);

		cout << "New message" << "\n";

		char *bufPtr = messageBuffer;

		wxUint32 totalRd = 0;

		wxUint32 lenRd = 1;
		while (lenRd > 0 && wxString::FromUTF8(bufPtr - 1, 1) != '\n')
		{
			lenRd = sockBase->Read(bufPtr++, 1).LastCount();
			totalRd += lenRd;
		}

		if (!totalRd) return;

		// parse message
		auto message = json::parse(wxString::FromUTF8(messageBuffer, totalRd));

		OnMessage(message);

		cout << "Finished message" << "\n";

		//Enable input events again.
		sockBase->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG);
		break;


	}
	default:
		cout << "Other message" << "\n";
	}

}

Notice I put message printing both before and after handling the message to make sure I wasn't blocking the socket.
Output is:

Code: Select all

...
Event
New message
DATA: bots.c7ab112c-8216-11e7-bb31-be2e44b06b34.datastore.platform.pdo.bus_voltage, 51.14507293701172
Finished message
Event
New message
DATA: bots.c7ab112c-8216-11e7-bb31-be2e44b06b34.datastore.platform.pdo.bus_voltage, 51.031959533691406
Finished message
Event
New message
DATA: bots.c7ab112c-8216-11e7-bb31-be2e44b06b34.datastore.platform.pdo.bus_voltage, 51.1656379699707
Finished message
Event
New message
DATA: bots.c7ab112c-8216-11e7-bb31-be2e44b06b34.datastore.platform.pdo.bus_voltage, 51.147647857666016
Finished message
Event
New message
DATA: bots.c7ab112c-8216-11e7-bb31-be2e44b06b34.datastore.platform.pdo.bus_voltage, 51.18363571166992
Finished message

(Here it just hangs after finishing that last message
Am I missing something dumb here? What steps can I take to further diagnose this?
Thanks guys! :)
Oh also, this forum is amazing. After years of getting flamed on Stack overflow, you guys are a refreshing change :lol:

User avatar
doublemax
Moderator
Moderator
Posts: 16022
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxSocketClient silently stops receiving messages

Post by doublemax » Thu May 13, 2021 4:51 pm

Code: Select all

sockBase->SetNotify(wxSOCKET_LOST_FLAG);
sockBase->SetFlags(wxSOCKET_WAITALL);

[...]

//Enable input events again.
sockBase->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG);
I've never worked with sockets, so i don't know if this is a common thing when handling socket events, but this look suspicious to me. Just for a test i'd remove this and check if the behavior changes.

I'd also suggest to read the chapter about sockets in the wxWidgets book. While the book is pretty old and outdated in many parts, i think it has a good introduction to socket programming with wxWidgets. Maybe you spot something helpful.

The book is not free, but a PDF is very easy to find using Google...
Use the source, Luke!

User avatar
zoxks
In need of some credit
In need of some credit
Posts: 8
Joined: Tue Apr 27, 2021 11:38 pm

Re: wxSocketClient silently stops receiving messages

Post by zoxks » Thu May 13, 2021 5:09 pm

Good idea.
I've tried disabling those flags but I still get the same behavior :(

User avatar
zoxks
In need of some credit
In need of some credit
Posts: 8
Joined: Tue Apr 27, 2021 11:38 pm

Re: wxSocketClient silently stops receiving messages

Post by zoxks » Thu May 13, 2021 5:22 pm

Ok I found this from page 465 of that book. An example for socket clients that looks pretty similar to mine:

Code: Select all

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(CLIENT_CONNECT, MyFrame::OnConnectToServer)
EVT_SOCKET(SOCKET_ID, MyFrame::OnSocketEvent)
END_EVENT_TABLE()

void MyFrame::OnConnectToServer(wxCommandEvent & WXUNUSED(event)) {
  wxIPV4address addr;
  addr.Hostname(wxT(“localhost”));
  addr.Service(3000);

  // Create the socket
  wxSocketClient * Socket = new wxSocketClient();

  // Set up the event handler and subscribe to most events
  Socket -> SetEventHandler( * this, SOCKET_ID);
  Socket -> SetNotify(wxSOCKET_CONNECTION_FLAG |
    wxSOCKET_INPUT_FLAG |
    wxSOCKET_LOST_FLAG);

  Socket -> Notify(true);
  // Wait for the connection event
  Socket -> Connect(addr, false);
}

void MyFrame::OnSocketEvent(wxSocketEvent & event) {
    // The socket that had the event
    wxSocketBase * sock = event.GetSocket();
    // Common buffer shared by the events
    char buf[10];
    switch (event.GetSocketEvent()) {
    case wxSOCKET_CONNECTION: {

      // Fill the arry with the numbers 0 through 9
      // as characters
      char mychar = ‘0’;
      for (int i = 0; i < 10; i++) {
        buf[i] = mychar++;
      }
      // Send the characters to the server
      sock -> Write(buf, sizeof(buf));
      break;
    }
    case wxSOCKET_INPUT: {
      sock -> Read(buf, sizeof(buf));
      break;
    }
    // The server hangs up after sending the data
    case wxSOCKET_LOST: {
      sock -> Destroy();
      break;
    }
}
The only difference being that they are reading in all available data into a buffer at once, not reading till the next newline. I wonder if I'm getting multiple messages and only parsing the first one, and blocking up the socket in that way.

User avatar
doublemax
Moderator
Moderator
Posts: 16022
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxSocketClient silently stops receiving messages

Post by doublemax » Thu May 13, 2021 5:26 pm

What happens inside "OnMessage(message);" ? Can it take longer than 30ms to process the data?

IOW, is it possible that the event queue gets saturated when new events come in every 30ms?

Apart from that, i'm out of ideas. I'd probably try to move the code to a secondary thread and use sockets in blocking mode without events.
Use the source, Luke!

User avatar
zoxks
In need of some credit
In need of some credit
Posts: 8
Joined: Tue Apr 27, 2021 11:38 pm

Re: wxSocketClient silently stops receiving messages

Post by zoxks » Thu May 13, 2021 6:33 pm

Hey, got it! I think the internal read buffer was filling up as I was only ever reading one JSON message worth of data, leaving the rest in the buffer. I altered my code to loop and read as many messages as possible, and only return if there was a partial message, or no message at all:

Code: Select all

void Sockhop::OnSocketEvent(wxSocketEvent& event)
{
	wxSocketBase* sockBase = event.GetSocket();

	switch (event.GetSocketEvent())
	{
	case wxSOCKET_INPUT:
	{

		wxUint32 lastLenRd = 1;
		wxUint32 lastTotalRd = 0;

		//Loop while we continue to have data being read
		while (lastLenRd > 0)
		{
			lastTotalRd = 0;
			
			char* bufPtr = messageBuffer;

			//Read until either we run out of message, or get a terminator
			while (lastLenRd > 0 && wxString::FromUTF8(bufPtr - 1, 1) != '\n')
			{
				lastLenRd = sockBase->Read(bufPtr++, 1).LastCount();
				lastTotalRd += lastLenRd;
			}

			//The last read was not empty. Must have been a \n
			if (lastLenRd > 0)
			{

				// parse message
				auto message = json::parse(wxString::FromUTF8(messageBuffer, lastTotalRd));
				OnMessage(message);

			} else if (lastTotalRd > 0)
			{
				//We got to the end (but not a \n) unread all this stuff and wait for the next message
				sockBase->Unread(bufPtr, lastTotalRd);

			}

		}

		break;


	}
	default:;
	}

}
Ahh the bliss of code that doesn't freeze. :D
Thank you so much for your help!

Post Reply