

Kas Ob.
Members-
Content Count
626 -
Joined
-
Last visited
-
Days Won
10
Everything posted by Kas Ob.
-
Handling TCP send buffer overflow the right way
Kas Ob. replied to Dmitry Onoshko's topic in Network, Cloud and Web
You picked the one of the worst also outdated socket library, literally it is not installed by default in the IDE for many years, it is deprecated. You can't hit that messages limit easily, in fact i doubt that even possible if you tried to do so, to be able to hit that limit with socket messages would be an accomplishment. SOMAXCONN has nothing to do with max connection server can serve or connect, it is about backlog, how many sockets trying to connect at the same exact time (literally at the same millisecond or microsecond), the rest at this exact time will be dropped. You have many to pick from Indy, ICS, mORMot/mORMot2, RealThinClient, these are opensource -
sip Looking for VoIP/SIP client SDKs/components
Kas Ob. replied to omnibrain's topic in Delphi Third-Party
The price you see after clicking buy is not for only for SIP, /nsoftware website only offer Red Carpet license, a license for everything in their products page https://www.nsoftware.com/subscriptions , for individual package you have to contact their sales, don't know now but they used to offer license with source code for individual library too. -
Handling TCP send buffer overflow the right way
Kas Ob. replied to Dmitry Onoshko's topic in Network, Cloud and Web
Stupid me !, not confirming the negation, sorry for that, and you know.. what you can go with loop or without it, the difference is little and close to none, for any non very intensive socket usage like sending/receiving large data (like huge files) also i missed to point the need to remove ioctlsocket , even you are not asking for the available data, ReceiveBuf uselessly internally is doing it, this can be removed by using your own RecvData. -
Handling TCP send buffer overflow the right way
Kas Ob. replied to Dmitry Onoshko's topic in Network, Cloud and Web
This is long story !, in short the answer is yes, loop is way better and will yield better throughput. The little longer one with a suggestion , There is very popular wrong practice of checking for the length of available data over socket then allocate a buffer then perform the receive (recv) on that buffer with the already (assumed) known length, this is waste of time ! i suggest to pre-allocate buffers for TCP, it could be 64kb (exactly 1024*64), or 16kb (any size will work but it is better to have a multiple of 4kb size and not less than 8kb), but it depends on how you expect you traffic speed, anyway.. with that allocated buffer just perform recv with the largest size your buffer can handle/fit, no need to check for available data length. Will work as expected and will squeeze speed and relax the network (vertically cascade) drivers (and TCP stack and provider) from this extra useless operation, operation that go into the kernel with afd driver then return empty handed, while you can recv as much as you can and it will not behave any different, on the contrary will give you all what is there to receive in one shot. -
Handling TCP send buffer overflow the right way
Kas Ob. replied to Dmitry Onoshko's topic in Network, Cloud and Web
And one more thing as reminder, about socket send API https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send You always need to check the result of sent bytes, compare with your own data length, this is standard usage, but keep in mind if send sent part of the packet, this doesn't not mean that the next send for the rest will return fail with WSAEWOULDBLOCK, No, send can partially send for many other situations like busy/full locally or the network driver imposing interrupt moderation... and none of these situations does/should concern you, Just keep in mind unless send return SOCKET_ERROR and WSAEWOULDBLOCK is the WSAGetLastError, then you can safely try to send more, i always use loops. I saw this bad design that caused sluggishness in sending out of wrong assumptions ! -
Handling TCP send buffer overflow the right way
Kas Ob. replied to Dmitry Onoshko's topic in Network, Cloud and Web
Hi, Well, i have this feeling that you are hesitating to do the right out of fear of braking things, i suggest to stop looking at these part of code as fragile as glass vase. Remy brilliantly explained all what do you need to know, now step back to look to the big picture here, you need functionality out of these TClientSocket and TServerClient, they are nice but far from best or very practical design, so .. adjust them to your need and this is the whole point of OOP to begin with. Example, SendBuf do raise exceptions unless you suppress them by changing the ErrorCode in the event, do you need this functionality ? it is not a big deal, but why not add your own function like SendData which takes care of the buffer too, this will simplify the buffering, also if needed add your own events, add somting like buffering triggered to signal traffic congestion, slowness, not responding peer... utilize this in you GUI, nice to see colored stuff indicating connection status. If you see what is going inside SendBuf, all what is needed to extended or replace it with better version is two things 1) Dont forget to Lock then Unlock, accessible "ClientSocket1.Socket.Lock" .. 2) you have the SocketHandle to pass to "send" (the API), also accessible "ClientSocket1.Socket.SocketHandle" Extend them from outside, or if you prefer OOP then things way simpler. For your question about handling errors for Listen in TServerSocket, these are shortcoming in the design, try follow DoActivate logic, and i think you have all what you need to overload these functions with better and more suitable functionality. You can override TCustomWinSocket.Listen with your own, that raise exception in case your (added) event OnServerError is not assigned. In other words, have faith in your self, you got it ! I really suggest to stay away from this, as it is utilizing a threadvar, unless you really know what are you doing, you must know exactly when and who is accessing it, as you described it, can go messy very quick. Good luck and happy coding ! -
Access Violation and Invalid Pointer exception while accessing files from web pages
Kas Ob. replied to sp0987's topic in Indy
Hi, From what i see, and i am guessing here, that exception is not from this code you pasted, but from one or two different places not shown here: One raised : EInvalidPointer : Invalid pointer operation The other raised EAccessViolation : Access violation at address 0047C27C in module 'VRMEditor.exe'. Read of address FFFFFFFx The second exception does look like managed type variable wrongly or unsafely accessed, in other words it was uninitialized yet there was something trying to access or may be just clean it up, or it could be overwritten on the stack and had corrupted value and the exception was triggered in the hidden part of "end;", (aka clean up) Try to extended logging within self.Log(... itself , there most likely your broken code, track memory corruption too. -
ifthen strange return value !
Kas Ob. replied to bravesofts's topic in Algorithms, Data Structures and Class Design
A small correction for this GPT answer: Not every local variable is allocated on the stack, so LObj could be on the stack, or due to optimization have a dedicated CPU register to use. In other words, LObj is either on the stack or in a register, but the result will be the same, the stack might hold data (Value) previously been written (or zero if the stack is never being reached before at this depth), and a register will have a Value from the last usage being from this procedure/function or a previous one. Delphi compiler is less optimized for this registers usage (optimization) for local variable then FPC and less than most other languages compilers, yet it does it sometimes. -
Dynamic array used as a queue. Memory fragmentation?
Kas Ob. replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
Alas, that is the case, and this is why when performance is the target i don't use any managed type, a small record with size, count and a pointer where the item[0] are reference to raw record, with a record helper to provide addition and deteletion. All memory manager i know including system Heap ones, do 16 bytes aligning, the problem in outdated and inefficient RTL managed types design, these should be updated, no memory manager can help with unaligned structure to begin with. -
Best way to set early, global variables in a project, before build-time
Kas Ob. replied to Rollo62's topic in Cross-platform
Well that is possible, but it might be an unneeded extra work. What i meant is something like this Just include the batch file which can have relative path, also it can take a parameter for the output path, even the name of the output file. and from the dproj file <PropertyGroup Condition="'$(Base)'!=''"> <PostBuildEvent><![CDATA[BuildConst.bat $(PostBuildEvent)]]></PostBuildEvent> Also i did always prefer using the inc files in place for naming and versioning, over batch files, thus i have their content in the project and in the EXE description ... -
Dynamic array used as a queue. Memory fragmentation?
Kas Ob. replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
True for almost all cases but not all, there still some few edge cases. Another point, it will works for old and new CPU. Another point, it will help any new optimized memory copy functions to use the SIMD version without going through the first and unaligned 16 bytes, but for this it should be aligned to 16bytes to get the most of juice, meaning that record should be 32bytes. -
Best way to set early, global variables in a project, before build-time
Kas Ob. replied to Rollo62's topic in Cross-platform
Something like this set filename=MyAppConsts.pas @echo on echo building %filename% @echo off (echo unit Unit1;& echo.& echo interface& echo.& echo const) > %filename% echo APPLICATION_APP_NAME = 'MyApp';>> %filename% echo APPLICATION_COMPANY_NAME = 'MyCompany';>> %filename% (echo.& echo implementation& echo.& echo end.) >> %filename% @echo on @echo done building %filename% #exit 0 the result a file "MyAppConsts.pas" unit Unit1; interface const APPLICATION_APP_NAME = 'MyApp'; APPLICATION_COMPANY_NAME = 'MyCompany'; implementation end. there is no earlier than that ! -
Dynamic array used as a queue. Memory fragmentation?
Kas Ob. replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
Another thing, having a record with 17 bytes is little strange, and means you are using packed record, if you are tying to save some performance and minimize time used in copying, then let me assure you are doing the opposite. Remove the packed and/or make sure it is padded to multiple of 4 bytes, meaning 20 bytes should be your minimum, you might see better a little performance right away, even if it is very small it is better, or remove the packed modifier from the record and let the compiler align it for you, unless you are using and exchanging the same records between 32bit and 64bit version, in that case you see how the compiler did it, and replicate the padding yourself with the packed one. -
Dynamic array used as a queue. Memory fragmentation?
Kas Ob. replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
Even when that is the case, i mean allocate new and copy the content, FastMM has very nice algorithm to recycle the system allocated blocks, FastMM request and allocate chunks from OS, lets say we have 1 MB allocated, FastMM will slice it into smaller chunks and provide the application with requested sizes, when a requested size is not available, it will request another big check 1MB and repeat, the probability of you cause fragmentation is very low, as it only will happen with the 1MB(s) chunks, and to do this you will have to requested and not freed too many blocks (huge amount of small sizes) , then free have of them in specific order to cause, but when your lets say list will grow above certain size then FastMM will not utilize the sliced chunks, it will request new form the OS and free (return it to OS) it when done, hence no matter how you changed or resize your list or even tens/hundreds of them you will not be able to cause any memory fragmentation, nor memory access degradation, the performance will more or less stay the same. Relocating on single delete as Stefan pointed is a problem, so do as Dalija suggested or implement you own raw list which will perform relocate on delete, it is easy. One more thing, many thinks linked lists are good and fast, and they are but only when the items count reach something around 500k item. Another thing, if your list doesn't need to be ordered, then on delete move/copy the last item on top the deleted one and decrease the count, hence remove few overheads, in such case your list will need size (capacity) and count (actual items count), grow and resize only when count is equal to size, and never downsize !, the logic is simple here, this size needed once so it could be needed again. -
Dynamic array used as a queue. Memory fragmentation?
Kas Ob. replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
Don't worry there, as long you are using FastMM (or the default memory manager, they are the same) , there is no memory fragmentation, in fact it is impossible to fragment the memory when using FastMM with one allocation, these lists/arrays... are one allocation from the point of view of MM, hence however you operate on them like delete and append, it always one continuous allocation. -
VSoft.Ulid - A Delphi Implementation of ULID for Delphi XE2 or later.
Kas Ob. replied to Vincent Parrett's topic in I made this
You still can (and may be should) use the record variant as Stefan suggested, only extended it a little from case boolean to case integer with 0,1 and 2 where you can align the needed types, in the third (additional) case just put case Integer of 0: ( FRandomness0 : byte; FRandomness1 : byte; FRandomness2 : byte; FRandomness3 : byte; FRandomness4 : byte; FRandomness5 : byte; FRandomness6 : byte; FRandomness7 : byte; FRandomness8 : byte; FRandomness9 : byte); 1: ( FRandomness0_1 : Word; FRandomness2_9 : UInt64) 2: ( FRandomness0_N : NativeUInt); There is no need for padding, the compiler should take care of that. -
VSoft.Ulid - A Delphi Implementation of ULID for Delphi XE2 or later.
Kas Ob. replied to Vincent Parrett's topic in I made this
This made no discernable difference. It is expected with your modern CPU, but the difference will be noticeable when the CPU under high usage, this is just for information and you don't need to do it, i liked to share. Anyway, on my XE8 i found one of these loch ness monsters, the one that i saw in real life and in dreams, the ones that very hard to catch red handed, when the compiler throw the towel and silently produce unoptimized ugly assembly instructions. This is reproducible on my XE8 and would love to know if this case is still in newer versions: 1) create new and empty console applicaiton. 2) add VSoft.Ulid 3) put this line in the main procedure, uses System.SysUtils, VSoft.Ulid; begin TUlid.Create; // we don't care now for memory leak or whatevery end. 4) add 64-bit platform and enable optimize, keep stack frame enabled. 5) use this create, the same i used earlier class function TUlid.InternalNewUlid(timestamp: UInt64): TUlid; var random : UInt64; ts : Int64Rec absolute timestamp; begin result := default(TUlId); //reverse order! result.FTimeStamp0 := ts.Bytes[5]; result.FTimeStamp1 := ts.Bytes[4]; result.FTimeStamp2 := ts.Bytes[3]; result.FTimeStamp3 := ts.Bytes[2]; result.FTimeStamp4 := ts.Bytes[1]; result.FTimeStamp5 := ts.Bytes[0]; random := FXorShift64.Next; PNativeUInt(@result.FRandomness0)^ := NativeUInt(random); random := FXorShift64.Next; Move(random,result.FRandomness2, 8); // comment and uncomment this line and see the difference in assembly code PUInt64(@result.FRandomness0)^ := random; end; The result is astonishing ! Here the difference from my XE8 The compiler with move behaved differently and stupidly. One side note this is also really annoying, though i don't know if this still the same for the newer and enhanced versions it could be handled way better for these limited size like up to 128bit. -
One more thing that bothering me, and you might test and confirm as you or somebody have some insight on this: Do the borders scale ? I mean the border is there for reason and they are one pixel wide, for the window title, but when scaled to 200% do they become 2 pixel ? or they stayed as 1pixel? See, windows shadow bothered me in the past and they changed few times over many Windows versions, their scaling too.
-
I still thinking about this, and as no one added any input then i add my assumption. I think the logic behind this is very simple, Windows has its default drawing (themed or not) and if you are changing its parameters in whole or in some then you are on your own. In examples might be easier to explain, like, while you change the height of an item in ListBox or ListView, then the default drawing/rendering for item will perform according to its default no matter what you have set, if you set the item height to 3 pixel then you will see the item drawn by OS stayed as default like 8 pixel and the items will overlap, same if you set them to something like 50 pixel, the system will not check and adjust the font size neither the image or checkboxes... Its like an unspoken rule, if you are changing the height then you have to continue and override the default drawing, and draw your own title/item.. with your own drawing function and your own font, brush, pen....
-
VSoft.Ulid - A Delphi Implementation of ULID for Delphi XE2 or later.
Kas Ob. replied to Vincent Parrett's topic in I made this
Here another idea. The implementation require 2 consequence random then calculate them in one hit, instead of calling FXorShift64.Next in the middle, in other words add/use Random1 and Random2, use only one Next. -
VSoft.Ulid - A Delphi Implementation of ULID for Delphi XE2 or later.
Kas Ob. replied to Vincent Parrett's topic in I made this
@Vincent Parrett I would suggest to benchmark the following class function TUlid.InternalNewUlid(timestamp: UInt64): TUlid; var random : UInt64; ts : Int64Rec absolute timestamp; begin result := default(TUlId); //reverse order! result.FTimeStamp0 := ts.Bytes[5]; result.FTimeStamp1 := ts.Bytes[4]; result.FTimeStamp2 := ts.Bytes[3]; result.FTimeStamp3 := ts.Bytes[2]; result.FTimeStamp4 := ts.Bytes[1]; result.FTimeStamp5 := ts.Bytes[0]; random := FXorShift64.Next; //Move(random,result.FRandomness0, 2); // randomness 0-1 //PWORD(@result.FRandomness0)^ := UInt16(random); // the exact size PNativeUInt(@result.FRandomness0)^ := NativeUInt(random); // it is safe to overflow here, might yeild better and simpler asm instruction random := FXorShift64.Next; //Move(random,result.FRandomness2, 8); // randomness 2-9 PUInt64(@result.FRandomness0)^ := random; end; Removing the overhead of Move should count for something, i guess !! -
Searching the Internet kept landing me on the same approach, using "Self.Height - ClientHeight" the result was 39 pixel, and using print screen and painter to find the title bar height kept giving me 29 pixel, so some subtraction will be needed from the first, which i think it borders.... Anyway i found this https://stackoverflow.com/questions/28524463/how-to-get-the-default-caption-bar-height-of-a-window-in-windows Which is does return 31 pixel, so it might be your solution, or at least it a lead to a solution. Please share your finding with us.
-
Have you tried WM_GETTITLEBARINFOEX ? Its message structure not available in XE8, so i can't try it, but seeing this : https://stackoverflow.com/questions/60667679/delphi-overlap-window-form-titlebar then TTitleBarInfoEx should be available in newer versions.
-
What is the best way to accomplish this?
Kas Ob. replied to alank2's topic in Network, Cloud and Web
Well, first what comes to mind is MQTT, there is a punch of free and commercial libraries for Delphi/Pascal that provide MQTT. about how to handle no DNS, well if you buy a DNS form anywhere then move it to your free CloudFlare account, then you have very powerful infrastructure to build on, see, you don't need to assign your bought DNS to the server IP, you could use a subdomain, also you could use a subdomain TXT record, the client in this case will not lookup lets say myserver.alank2.com, but will the TXT record for this subdomain (or any domain) where the server IP is stored as plain text value, then connect to it. You can borrow a subdomain form i friend, a trusted one to store your TXT record. CloudFlare has brilliant control over DNS and its records, the slowest changes i witnessed was around 45 seconds over so many years of using their DNS services and thousands of changes and update, (many of these changes were automated using their API), using free CL account. Also just searched for MQTT providers in case you don't want to use your own server at all, and found this https://myqtthub.com/en They looks like have free account to test, it might be enough for you. -
Add onClick event on TCanvas
Kas Ob. replied to direktor05's topic in Algorithms, Data Structures and Class Design
Well, as Francois said it, and i will elaborate a little on that. TCanvas is Delphi/Pascal RTL encapsulation for Device Context: https://learn.microsoft.com/en-us/windows/win32/gdi/device-contexts https://learn.microsoft.com/en-us/windows/win32/gdi/about-device-contexts These are Output devices and has no Input, and by Input i mean there is no hardware user input or interaction, their input is solemnly comes from drawing APIs, and in other words they are GDI drawing object that simulate a painting canvas (real life canvas) to be processed further, like to be rendered on monitor or to be passed to printer.... they are build that way to unify User mode GDI and supply one Interface to different hardware, their functionalities differ based on what the hardware and its driver support, while the interface is the same for them all.