Indy UDP 服务器速度非常低

Indy UDP Server very low speed

我正在使用 RAD Studio 10.2 和 Indy 10,一个组件 IdUDPServer。 为了测试UDP连接速度,我安装了程序UDP Test Tool.

我检查 UDP 服务器速度的代码:

#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;
}
//---------------------------------------------------------------------------

我在方法 IdUDPServer1UDPRead 中使用 readCounter 以便稍后与通过下载的测试实用程序发送的数据包数进行比较,但计数器不匹配。可以看出组件IdUDPServer已经很晚了。

可能是什么问题?

TIdUDPServer::ThreadedEvent 属性默认为false。这意味着每次服务器收到数据包时,您的 OnUDPRead 事件处理程序都会通过 TThread::Synchronize() 与主 UI 线程 同步 同步。这当然会降低服务器的整体性能。

为了让您的服务器更快地响应 UDP 数据包,您需要让您的 OnUDPRead 事件处理程序 return 更快地控制 TIdUDPServer。这意味着将 ThreadedEvent 设置为 true 以跳过 TThread::Synchronize() 调用,根本不访问 UI (或者至少更新 UI asynchronously using TThread::Queue() or TIdNotify), 并删除所有拖慢处理程序速度的无用代码(你分配和填充的 char[] 缓冲区不是被用于任何事情,所以这只是浪费开销)。

例如,如果您使用的是基于 Clang 的编译器:

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

否则,如果您使用的是经典编译器:

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

或:

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