I'm using RAD Studio 10.2 with Indy 10, a component IdUDPServer
.
To test the speed of UDP connection, I installed the program UDP Test Tool.
My code for checking speed of the UDP server:
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
int readCounter = 0;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Memo1->Clear();
TIdSocketHandle *SocketHandle = IdUDPServer1->Bindings->Add();
SocketHandle->IP = "127.0.0.1";
SocketHandle->Port = 14014;
IdUDPServer1->Active = true;
if (IdUDPServer1->Active == true) {
Memo1->Lines->Add("Сервер стартовал");
Button1->Enabled = false;
Button2->Enabled = true;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Memo1->Clear();
IdUDPServer1->Active = false;
IdUDPServer1->Bindings->Clear();
if(IdUDPServer1->Active == false) {
Memo1->Lines->Add("Сервер остановлен");
Button1->Enabled = true;
Button2->Enabled = false;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdUDPServer1UDPRead(TIdUDPListenerThread *AThread, const TIdBytes AData,
TIdSocketHandle *ABinding)
{
readCounter++;
Edit1->Text = readCounter;
char* szBuff = new char[AData.Length];
memset(szBuff, 0, AData.Length);
BytesToRaw(AData, szBuff, AData.Length);
Memo1->Lines->Add(ToHex(AData));
Memo1->Clear();
delete szBuff;
}
//---------------------------------------------------------------------------
I use the readCounter
in the method IdUDPServer1UDPRead
for later comparison with the number of packets sent via the downloaded test utility, but the counters do not match. It can be seen that the component IdUDPServer
is very late.
What could be the problem?
The TIdUDPServer::ThreadedEvent
property is false
by default. That means every time the server receives a data packet, your OnUDPRead
event handler is synced with the main UI thread synchronously via TThread::Synchronize()
. That will, of course, slow down the server's overall performance.
To make your server react to the UDP packets more quickly, you need to make your OnUDPRead
event handler return control to TIdUDPServer
more quickly. That means setting ThreadedEvent
to true
to skip the TThread::Synchronize()
call, do not access the UI at all (or, at least, update the UI asynchronously using TThread::Queue()
or TIdNotify
), and remove any useless code that is slowing down your handler (you are allocating and filling a char[]
buffer that is not being used for anything at all, so that is just wasted overhead).
For example, if you are using a Clang-based compiler:
// make sure ThreadedEvent=true...
void __fastcall TForm1::IdUDPServer1UDPRead(TIdUDPListenerThread *AThread, const TIdBytes AData, TIdSocketHandle *ABinding)
{
++readCounter;
TThread::Queue(nullptr,
[=]() {
Edit1->Text = readCounter;
Memo1->Lines->Add(ToHex(AData));
}
);
}
Otherwise, if you are using a classic compiler:
// See "Handling Anonymous Method Types in C++":
// http://docwiki.embarcadero.com/RADStudio/en/How_to_Handle_Delphi_Anonymous_Methods_in_C%2B%2B
class TMyQueueProc : public TCppInterfacedObject<TThreadProcedure>
{
private:
int m_counter;
TIdBytes m_bytes;
public:
TMyQueueProc(int ACounter, const TIdBytes &AData) : m_counter(ACounter), m_bytes(AData) {}
INTFOBJECT_IMPL_IUNKNOWN(TInterfacedObject);
void __fastcall Invoke()
{
Form1->Edit1->Text = m_counter;
Form1->Memo1->Lines->Add(ToHex(m_bytes));
}
};
// make sure ThreadedEvent=true...
void __fastcall TForm1::IdUDPServer1UDPRead(TIdUDPListenerThread *AThread, const TIdBytes AData, TIdSocketHandle *ABinding)
{
++readCounter;
TThread::Queue(NULL, _di_TThreadProcedure(new TMyQueueProc(readCounter, AData)));
}
Or:
#include <IdSync.hpp>
class TMyNotify : public TIdNotify
{
private:
int m_counter;
TIdBytes m_bytes;
protected:
void __fastcall DoNotify()
{
Form1->Edit1->Text = m_counter;
Form1->Memo1->Lines->Add(ToHex(m_bytes));
}
public:
TMyNotify(int ACounter, const TIdBytes &AData) : TIdNotify(), m_counter(ACounter), m_bytes(AData) {}
};
// make sure ThreadedEvent=true...
void __fastcall TForm1::IdUDPServer1UDPRead(TIdUDPListenerThread *AThread, const TIdBytes AData, TIdSocketHandle *ABinding)
{
++readCounter;
(new TMyNotify(readCounter, AData))->Notify();
}