Indy UDP Server very low speed - sockets

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

Related

c++ builder ZipProgress callback for the progress bar

I have a simple form, and I'm trying to work with the ProgressBar when a .zip file is being created, based on the ZipDirectoryContents callback. I have seen some Delphi example in the forum, but I don't know it well, and I get several errors. Here an example:
.cpp
#include <system.zip.hpp>
String PreviousFilename;
bool __fastcall createZipFromFolder( String inZipName,
String inSourcePath,
String inTargetPath )
{
bool result = true;
sZipName = "C:\\test\\testBar.zip";
sSourceName = "C:\\test2";
TZipFile* Zip = new TZipFile();
try{
if ( FileExists( sZipName ) ){
Zip->ZipDirectoryContents( sZipName, // destiny
sSourceName, // to include
zcDeflate, // compression mode
OnZipProgressEvent() ); // <--- p callback
Zip->Close();
}
}
catch(...){
result = false;
ShowMessage("Error");
}
delete Zip;
Zip = NULL;
return result;
}
void __fastcall OnZipProgressEvent( TObject* Sender, String FileName, TZipHeader Header, __int64 Position )
{
if ( PreviousFilename != FileName ){
PreviousFilename = FileName;
Form1->ProgressBar1->Max = Header.UncompressedSize;
Form1->ProgressBar1->Position = Position;
}
else{
Form1->ProgressBar1->Position = Position;
Application->ProcessMessages();
}
}
.h
#include <System.Zip.hpp>
public: // User declarations
__fastcall TForm1(TComponent* Owner);
typedef void __fastcall ( __closure * TZipProgressEvent )( TObject*,
String,
TZipHeader,
__int64 );
bool __fastcall createZipFromFolder( String inZipName,
String inSourcePath,
String inTargetPath );
void __fastcall OnZipProgressEvent( TObject* Sender,
String FileName,
TZipHeader Header,
__int64 Position );
};
extern PACKAGE TForm1 *Form1;
extern String PreviousFilename;
#endif
When calling Zip->ZipDirectoryContents(), you need to change OnZipProgressEvent() to &OnZipProgressEvent instead. You are trying to call the callback (with missing parameters) when you should be passing its address.
Also, in your .cpp file, both createZipFromFolder() and OnZipProgressEvent() need to be defined as being members of your Form class.
Also, in OnZipProgressEvent(), the TZipHeader parameter needs to be passed by const reference rather than by value, per the documentation.
Try this:
Unit1.h
...
class TForm1 : public TForm
{
...
private: // User declarations
String PreviousFilename;
void __fastcall OnZipProgressEvent( TObject* Sender,
String FileName,
const TZipHeader &Header,
__int64 Position );
public: // User declarations
__fastcall TForm1(TComponent* Owner);
bool __fastcall createZipFromFolder( String inZipName,
String inSourcePath,
String inTargetPath );
};
extern PACKAGE TForm1 *Form1;
#endif
Unit1.cpp
...
#include "Unit1.h"
#include <System.Zip.hpp>
bool __fastcall TForm1::createZipFromFolder( String inZipName,
String inSourcePath,
String inTargetPath )
{
bool result = true;
sZipName = _D("C:\\test\\testBar.zip");
sSourceName = _D("C:\\test2");
PreviousFilename = _D("");
TZipFile* Zip = new TZipFile();
try{
if ( FileExists( sZipName ) ){
Zip->ZipDirectoryContents( sZipName, // destiny
sSourceName, // to include
zcDeflate, // compression mode
&OnZipProgressEvent ); // <--- p callback
Zip->Close();
}
}
catch(...){
result = false;
ShowMessage(_D("Error"));
}
delete Zip;
Zip = NULL;
return result;
}
void __fastcall TForm1::OnZipProgressEvent( TObject* Sender,
String FileName,
const TZipHeader &Header,
__int64 Position )
{
if ( PreviousFilename != FileName ){
PreviousFilename = FileName;
ProgressBar1->Max = Header.UncompressedSize;
ProgressBar1->Position = Position;
}
else{
ProgressBar1->Position = Position;
Application->ProcessMessages();
}
}

SpawnObject for ak(Clone) (UnityEngine.GameObject), NetworkServer is not active. Cannot spawn objects without an active server

helloI'm making an object in Unity that gives players random weapons when they hover over it, but it always gives me this warning and doesn't create it.
[ClientRpc]
public void spawnTime()
{
StartCoroutine(spawn());
}
public IEnumerator spawn()
{
Debug.Log("oldu");
yield return new WaitForSeconds(1);
int a = Random.Range(0, guns.Length);
GameObject gun =Instantiate(guns[a], spawnPoint.position,Quaternion.identity);
gun.transform.SetParent(transform);
NetworkServer.Spawn(gun);
}
This is because of you are calling the spawn function from client. You should call it in server.
[Server]
public void spawnTime()
{
StartCoroutine(spawn());
}
[Server]
public IEnumerator spawn()
{
Debug.Log("oldu");
yield return new WaitForSeconds(1);
int a = Random.Range(0, guns.Length);
GameObject gun =Instantiate(guns[a],
spawnPoint.position,Quaternion.identity);
gun.transform.SetParent(transform);
NetworkServer.Spawn(gun);
uint gunNetId = gun.GetComponent<NetworkIdentity>().netId;
uint parentNetId = transform.root.GetComponent<NetworkIdentity>().netId;
RpcSetParent(parentNetId, gunNetId);
}
[ClientRpc]
void RpcSetParent(uint parentNetId, uint childNetId)
{
Transform child = NetworkClient.spawned[childNetId].transform;
Transform parent = NetworkClient.spawned[parentNetId].transform;
child.SetParent(parent);
}
Be sure that you are calling the spawnTime() function from something running in server and networked object. You can filter it something like:
Start(){
NetworkIdentity nid = transform.root.GetComponent<NetworkIdentity>();
if(nid.isServer)
{
spawnTime();
}
}

Using unity without Bolt

I am new to Unity, but not to C#, so I would love to avoid using Bolt. I don't mind spending the extra time making sure that my animations are correct.
I am trying to get a gun to shoot (the animation part [aka recoil])
As you probably can see that there are no parameters (in the first image). In the parameter box (where it says list is empty in the animator window), I clicked on the '+' to create a new parameter trigger (called it "M1911SHOOT")
However it does resolve the Parameter does not exist error message but nothing happens afterwards
Here is my code
M1911.cs
public class M1911 : Weapons
{
private const string IDLE = "M1911IDLE";
private const string BASIC = "M1911SHOOT";
// Start is called before the first frame update
void Start()
{
IDLEANIM = IDLE;
BASICATKANIM = BASIC;
weaponName = "Weapon";
damage = 15;
heavyDamage = 35;
weight = 5;
staminaCost = 5;
range = 3.5f;
atkDelay = .7f;
type = WEAPONTYPE.MELEE;
Init();
}
}
Weapons.cs
public class Weapons : MonoBehaviour
{
protected enum WEAPONTYPE
{
NONE,
RANGED,
MELEE
}
protected string weaponName;
protected int damage;
protected int heavyDamage;
protected int weight;
protected int staminaCost;
protected float range;
protected WEAPONTYPE type;
protected bool isAtking;
protected float atkDelay;
protected string BASICATKANIM;
protected string HEAVYATKANIM;
protected string IDLEANIM;
protected string CURRENTANIMATION;
private Animator _animator;
protected void Init()
{
CURRENTANIMATION = IDLEANIM;
_animator = GetComponent<Animator>();
isAtking = false;
}
public int Attack()
{
if (!isAtking)
{
isAtking = true;
ChangeAnimation(BASICATKANIM);
return damage;
}
return 0;
}
void AttackComplete()
{
isAtking = false;
}
public void ChangeAnimation(string newAnimationState)
{
if(newAnimationState == CURRENTANIMATION)
return;
if (isAtking)
{
CURRENTANIMATION = newAnimationState;
Invoke("AttackComplete", atkDelay);
}
_animator.SetBool(BASICATKANIM, true);
_animator.SetBool(IDLEANIM, false);
CURRENTANIMATION = newAnimationState;
}
}
Player.cs
public class Player : CharacterAttributes
{
public Weapons weapon;
// Start is called before the first frame update
void Start()
{
Init();
}
// Update is called once per frame
void Update()
{
Move();
if (Input.GetMouseButtonDown(0))
Attack();
}
void Move()
{
//Movement stuff
}
void Attack()
{
weapon.Attack();
}
}
Wrong method in Weapon.cs
Needed
_animator.Play(BASICATKANIM);
instead of
_animator.SetBool(IDLEANIM, false);
I wanted to play an animation, not play around with the parameters for the animator

Drag and drop with TTreeView in Firemonkey

I am using C++ Builder 10.2.2 Tokyo with FireMonkey (FMX).
I want to add drag and drop functionality to a TTreeView, so a user can rearrange the order of the tree items. I have added a handler to the TTreeView.OnMouseDown event, based on this Drag and Drop sample project.
With this, the program can now drag and drop to rearrange items, but it seems that there is some default behavior to move a TTreeViewItem to be a child of the TTreeViewItem it is dropped onto, instead of inserting after that item.
How can I override this default behavior, so that a TTreeViewItem is inserted at the same level in the TTreeView, and at an index 1 greater than the TTreeViewItem it is dropped onto?
Following on Abdullah's suggestion, you can achieve this by creating a custom component. Directions to create a custome component in general are here. I recommend installing it in Standard on the Tool Palette, as that's where TTreeView is.
The custom component, here called TMyTreeView, has this in the header in particular:
class PACKAGE TMyTreeView : public TTreeView
{
private:
bool IsAncestor (TTreeViewItem* oItem, TTreeViewItem* oTargetItem);
protected:
int DragDelta;
void StartDrag ();
void __fastcall DragDrop (const Fmx::Types::TDragObject &Data, const System::Types::TPointF &Point);
void __fastcall MouseDown (System::Uitypes::TMouseButton Button, System::Classes::TShiftState Shift, float X, float Y);
void __fastcall MouseMove (System::Classes::TShiftState Shift, float X, float Y);
public:
__fastcall TMyTreeView(TComponent* Owner);
__fastcall ~TMyTreeView ();
TBitmap* DragBmp;
TPointF MouseDownPoint;
TTreeViewItem* DragStartItem;
__published:
};
//---------------------------------------------------------------------------
where the functions are as follows in the corresponding cpp file:
__fastcall TMyTreeView::TMyTreeView(TComponent* Owner)
: TTreeView(Owner)
{
DragBmp = NULL;
DragStartItem = NULL;
DragDelta = 5;
}
//---------------------------------------------------------------------------
__fastcall TMyTreeView::~TMyTreeView ()
{
if (DragBmp)
delete DragBmp;
}
//---------------------------------------------------------------------------
void __fastcall TMyTreeView::MouseMove (System::Classes::TShiftState Shift, float X, float Y)
{
TTreeView::MouseMove (Shift, X, Y);
if ((abs (X-MouseDownPoint.X) > DragDelta) || (abs (Y-MouseDownPoint.Y) > DragDelta))
StartDrag ();
}
//---------------------------------------------------------------------------
void TMyTreeView::StartDrag ()
{
if (!AllowDrag)
return;
if (!DragStartItem)
return;
if (DragBmp)
delete DragBmp;
_di_IFMXDragDropService service;
if ((TPlatformServices::Current->SupportsPlatformService (__uuidof(IFMXDragDropService)) &&
(service = TPlatformServices::Current->GetPlatformService (__uuidof(IFMXDragDropService)))))
{
TDragObject dragData;
if (!DragStartItem)
return;
dragData.Source = DragStartItem;
DragBmp = DragStartItem->MakeScreenshot ();
dragData.Data = DragBmp;
service->BeginDragDrop ((TForm*)this->Owner, dragData, DragBmp);
DragStartItem = NULL;
}
}
//---------------------------------------------------------------------------
void __fastcall TMyTreeView::MouseDown (System::Uitypes::TMouseButton Button, System::Classes::TShiftState Shift, float X, float Y)
{
TTreeView::MouseDown (Button, Shift, X, Y);
if (AllowDrag)
{
DragStartItem = ItemByPoint (X, Y);
MouseDownPoint.X = X;
MouseDownPoint.Y = Y;
}
else
DragStartItem = NULL;
}
//---------------------------------------------------------------------------
void __fastcall TMyTreeView::DragDrop (const Fmx::Types::TDragObject &Data, const System::Types::TPointF &Point)
{
TTreeViewItem* item = ItemByPoint (Point.X, Point.Y);
if (!item)
return;
TTreeViewItem* srcItem = (TTreeViewItem*)Data.Source;
if (!srcItem)
return;
if (IsAncestor (srcItem, item))
return;
if (item->ParentItem ())
item->ParentItem ()->InsertObject (item->Index, srcItem);
else
this->InsertObject (item->Index, srcItem);
//TTreeView::DragDrop (Data, Point);
}
//---------------------------------------------------------------------------
bool TMyTreeView::IsAncestor (TTreeViewItem* oItem, TTreeViewItem* oTargetItem)
{
for (int i=0; i<oItem->Count; i++)
{
TTreeViewItem* item = oItem->Items [i];
if (item == oTargetItem)
return true;
if (IsAncestor (item, oTargetItem))
return true;
}
return false;
}
//---------------------------------------------------------------------------
After installing the custom component to your Tool Palette, you can then add it to your form as you would any other component.
Special thanks to Mike Sutton, who had code to modify an earlier version of TTreeView here.
Once added to a form, set the TMyTreeView control's AllowDrag to true.

smart pointer to manage socket file descriptor

A smart pointer clears the memory if the pointer gets out of scope. I wanted to adapt this to a file descriptor, like a socket. There you need a user defined deleter, because close() is the function to free the file descriptor (fd) resources.
I found this useful page, unfortunately, most approaches did not work for me. Below is a working solution I found up to now, which is a little nasty. Because uniqu_ptr expects a pointer I created int *fd to store the fd value, therefore, I had to close(*fd) and delete fd in my custom deleter.
(1) Is there a better way?
Options A and B, which are based on the hints provided by the mentioned web page, are much nicer but causing odd compiler errors.
(2) Does anyone know how to correctly use these alternatives?
I'm using Qt Creator 3.0.1 with CONFIG += c++11 option and gcc version 4.8.2
#include "ccommhandler.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <memory>
#include <qdebug.h>
//for Option A and B
struct CloseHandleDeleter {
typedef int pointer;
void operator()(int handle) const
{
}
};
//custom deleter, working
class MyComplexDeleter
{
public:
MyComplexDeleter() {}
void operator()(int* ptr) const
{
qDebug() << "Deleting ";
close(*ptr);
delete ptr;
}
};
CCommHandler::CCommHandler()
{
//Option A doesn't work
//std::unique_ptr<int, CloseHandleDeleter> file( socket(AF_INET, SOCK_STREAM, 0) );
//Option B doesn't work
//std::unique_ptr<int, int()(int)> filePtr( socket(AF_INET, SOCK_STREAM, 0) , close);
MyComplexDeleter deleter;
int *fd = new int;
*fd = socket(AF_INET, SOCK_STREAM, 0);
std::unique_ptr<int, MyComplexDeleter> p( fd , deleter);
}
Edit:
The posted answer by Nevin is right, it solves my initial problem.
The comment of learnvst caused to rethink my problem, and I have to say I may made it much more complex than needed, because the following simple class should also solve my problem of auto-free the memory of a resource or as in my case, to close the file descriptor:
class SocketHandler
{
int _fd;
public:
SocketHandler(int FD):_fd(FD){}
~SocketHandler() { if(_fd!=-1) close(_fd); }
operator int() const { return _fd; }
};
Because fd isn't a pointer, I wouldn't try to pigeonhole it into unique_ptr. Instead, create a custom class whose interface is based on unique_ptr, as in (caution: totally untested):
class unique_fd
{
public:
constexpr unique_fd() noexcept = default;
explicit unique_fd(int fd) noexcept : fd_(fd) {}
unique_fd(unique_fd&& u) noexcept : fd_(u.fd_) { u.fd_ = -1; }
~unique_fd() { if (-1 != fd_) ::close(fd_); }
unique_fd& operator=(unique_fd&& u) noexcept { reset(u.release()); return *this; }
int get() const noexcept { return fd_; }
operator int() const noexcept { return fd_; }
int release() noexcept { int fd = fd_; fd_ = -1; return fd; }
void reset(int fd = -1) noexcept { unique_fd(fd).swap(*this); }
void swap(unique_fd& u) noexcept { std::swap(fd_, u.fd_); }
unique_fd(const unique_fd&) = delete;
unique_fd& operator=(const unique_fd&) = delete;
// in the global namespace to override ::close(int)
friend int close(unique_fd& u) noexcept { int closed = ::close(u.fd_); u.fd_ = -1; return closed; }
private:
int fd_ = -1;
};