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();
}
我正在使用 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();
}