delays time sending data to many clients

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

delays time sending data to many clients

Postby mark_c » Thu Sep 19, 2019 1:13 pm

I'm studying delays in sending windows packets when many clients are connected.
How come if I connect 20 or more clients to this simple server I don't see time differences on the various clients?
I expected at least a few milliseconds of difference between the various clients that receive the data.

thanks

Code: Select all
void __fastcall TMyThread1::MySincrSock1()
{
   int bytesent=0;
        AnsiString old = msg;
        int sizemessage;

   try{
      for(int actconn = 0; actconn < Form1->ServerSocket1->Socket->ActiveConnections; actconn++)
      {
                        msg+="," + IntToStr(GetTickCount()) + "," + IntToStr(actconn)+ ";\r\n";

                        sizemessage = msg.Length();

                        do
                        {
                 bytesent = Form1->ServerSocket1->Socket->Connections[actconn]->SendBuf(msg.c_str(), msg.Length());
                                sizemessage -= bytesent;
         }
                        while(sizemessage > 0);

                        msg=old;
      }
   } catch(...) { }
}
//---------------------------------------------------------------------------
mark_c
BCBJ Guru
BCBJ Guru
 
Posts: 170
Joined: Thu Jun 21, 2012 1:13 am

Re: delays time sending data to many clients

Postby rlebeau » Wed Sep 25, 2019 1:09 pm

mark_c wrote:How come if I connect 20 or more clients to this simple server I don't see time differences on the various clients?


Because GetTickCount() DOES NOT have 1 millisecond precision, like you are expecting. The default time resolution on Windows (the interval of time between timer updates) can be as low as 4ms or as high as 35ms, depending on Windows version (you can use timeGetDeviceCaps() or NtQueryTimerResolution() to query the current resolution). So it is certainly possible that your thread loop is able to send packets to all 20 clients before the GetTickCount() counter is updated by the OS.

If you need the packets to have different timer values, you will have to either:

  • Sleep() the loop between sends.
  • use timeBeginPeriod() or NtSetTimerResolution() to set a higher resolution (still not guaranteed to get 1 millisecond precision, though).
  • use a higher resolution timer, such as QueryPerformance(Counter|Frequency)() (which is wrapped by Embarcadero's TStopwatch class) or C++11's std::high_resolution_clock class.

Also, on a side note, your use of the TServerSocket::ActiveConnections and TServerSocket::Connections[] properties is not thread-safe. The main UI thread is free to update them while your worker thread is using them. So you MUST synchronize access to the TServerSocket between the UI thread and a worker thread to avoid such race conditions.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1610
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: delays time sending data to many clients

Postby mark_c » Thu Sep 26, 2019 12:29 pm

thanks Remy,
regarding the problem of synchronization between the main thread and the TServerSocket, this declaration should be right to avoid race condition, is it correct?

Code: Select all
class TMyThread1 : public TThread
{
protected:
   void __fastcall Execute();
public:
   __fastcall TMyThread1();
   void __fastcall MySincrSock1();
   void __fastcall MySincrGrid1();
   String msg;
};
TMyThread1 *Thread1 = NULL;

//---------------------------------------------------------------------------

void __fastcall TMyThread1::MySincrSock1()
{
   int bytesent=0;
   AnsiString old = msg;
   int sizemessage;

   try{
      for(int actconn = 0; actconn < Form1->ServerSocket1->Socket->ActiveConnections; actconn++)
      {
         msg+="," + IntToStr(GetTickCount()) + "," + IntToStr(actconn)+ ";\r\n";

         sizemessage = msg.Length();

         do
         {
            bytesent = Form1->ServerSocket1->Socket->Connections[actconn]->SendBuf(msg.c_str(), msg.Length());
            sizemessage -= bytesent;
         }
         while(sizemessage > 0);

         msg=old;
      }
   } catch(...) { }
}
//---------------------------------------------------------------------------

void __fastcall TMyThread1::Execute()
{
   int i=0;
        while (!Terminated)
   {
      msg.sprintf("Y27.5,1,192.168.1.200,%d",i++);
      Synchronize(&MySincrSock1);
      if( i >10) i=0;
   }
}
//---------------------------------------------------------------------------
mark_c
BCBJ Guru
BCBJ Guru
 
Posts: 170
Joined: Thu Jun 21, 2012 1:13 am

Re: delays time sending data to many clients

Postby rlebeau » Fri Sep 27, 2019 11:20 am

mark_c wrote:regarding the problem of synchronization between the main thread and the TServerSocket, this declaration should be right to avoid race condition, is it correct?


Yes, that usage of Synchronize() will work.

However, your use of the 'old' variable is a little odd, but more importantly you have a logic bug in your SendBuf() loop. You are not passing the correct parameters to SendBuf() if it needs to be called more than once per socket.

Try this instead:

Code: Select all
void __fastcall TMyThread1::MySincrSock1()
{
    try
    {
        for(int actconn = 0; actconn < Form1->ServerSocket1->Socket->ActiveConnections; ++actconn)
        {
            TCustomWinSocket *Socket = Form1->ServerSocket1->Socket->Connections[actconn];
            AnsiString msgToSend;

            //msgToSend = msg + "," + IntToStr(GetTickCount()) + "," + IntToStr(actconn) + ";\r\n";
            msgToSend.sprintf("%s,%u,%d;\r\n", msg.c_str(), GetTickCount(), actconn);

            char *message = msgToSend.c_str();
            int sizemessage = msg.Length();

            try
            {
                do
                {
                    int bytesent = Socket->SendBuf(message, sizemessage);
                    if (bytesent == -1)
                    {
                        if (WSAGetLastEError() == WSAEWOULDBLOCK)
                            continue;
                        Socket->Close();
                        break;
                    }
                    message += bytesent;
                    sizemessage -= bytesent;
                }
                while (sizemessage > 0);
            }
            catch (const Exception &)
            {
                Socket->Close();
            }
        }
    }
    catch (...) { }
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1610
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA


Return to Technical

Who is online

Users browsing this forum: No registered users and 14 guests

cron