You are on page 1of 16
‘aioarz021 Halla CH! C+ at Your Service - CodeProject 009) CODE PROJECT Hello C#! C++ at Your Service Espen Harlinn 13 Mar 2021. CPOL A NET Core client implemented in Ci using TepClient and a multi-threaded server implemented in C+ Using the NET Core implementation of TepClient to develop a client for a multi-threaded server developed in C++ that uses the Windows Extensible Storage Engine (ESE) as its database engine. The server uses an I/O completion port with a thread-pool to process client request fe (14" of March, 2021) - 1.9 MB Download the updated source code for this ar Introduction ‘This isthe fourth article about a pet project | am working on. While itis a work in progress, | feel some things are starting to fall into place. ‘At this point, Ihave a C++ framework that makes it easy to create a multithreaded server that communicates using TCP/IP. Since a server without a client is rather pointless, | thought it would be interesting to create a client library using C# for NET Core ‘that can be used with the server. | hope you wil find it interesting too — because it performs rather wel: Wirote 527048 records in 1,7629398 seconds, 309488,33305792726 records per second. lirote 527040 records in 1,7059422 seconds, 308943,64416332514 records per second. Retrieved 1054@8@ records in 1,4269109 seconds, 738714,6597598642 records per second. Retrieved 105480 records in 1,4674932 seconds, 718286,1222116736 records per second. ‘The server stores data using Microsofts’ extensible storage engine (ESE) Using the System.Net Sockets. TcpClient is really easy, and if we disregard the OTO classes for the data-model, the Client is implemented in just above 600 lines of C# code. | think that is rather neat because ‘The dient implements 21 methods that can be used to: © connect to the server © disconnect from the server © test the performance of just sending data to the server, without updating the database © perform CRUD on the data-model implemented by the server, updating the database + There isa decent level of error handling, including throwing exceptions on the NET side for exceptions thrown by the C++ code on the server ‘The data-model implemented by the server is the one | created for Using C++ to Simplify the Extensible Storage Engine (ESE) API ~ Part 2. hitps:slww.codeproject.com/Artcles/5279846/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print a6 saioarz021 Halla CH! C+ at Your Service - CodeProject ‘The client and server exchange data using a custom binary format that is efficient and easy to implement. | know you have heard this one before There are only 10 types of people in the world: those who understand binary, and those who don't. but these days itis easy to forget that computers only understand binary data, Sure, you can use Snappy, or something similar, 10 compress JSON and XML to reduce bandwidth requirements, but that adds to the cost of generating and processing the data ~as if ‘the cost of parsing and generating text isn't high enough, If you have tried writing an efficient parser for floating point numbers, yyou will know what | mean, JSON and XML are excellent for exchanging data with other parties because these formats are so broadly supported across platforms and technology stacks, but once the data is inside your pond, you should do as Google, Microsoft, and any other big cloud operator, and use Protacol Buffers, or something similar, to serialize and deserialize your data: + Protocol Buffers: According to the FAQ “Protocol buffers are used by practically everyone inside Google" ‘= Bond: According to the github page for the project “Bond is broadly used at Microsoft in high scale services." Apache Thrift: Originally created by Facebook ‘ FlatGuffers: Originally created at Google for game development and other performance-critical applications. + Cap'n Proto: Written by Kenton Varda, the primary author of Protocol Buffers version 2 ‘Your mileage will obviously vary, but for a cloud deployment, you could cut the costs of running back-end services by more than 90% and provide a more responsive service at the same time Binary vs JSON Most will find this pretty obvious, but if you are in doubt: Here are the numbers to back the above claim, generated by the Cit program that is used to demonstrate how to use the C# client library to work with the server. First, we send a bunch of records to the server, without storing the data, ust to get an idea about how this performs: Sendt 527840000 records in 31.4532607 seconds, 16756291.343746118 records per second. ‘The server received one thousand batches of 527 040 SensorPoint objects that were placed in a std: :vector object, ready for further processing on the server. ‘Then we serialize and send the same amount of data as JSON to the server: hitps:slww.codeproject.com/Artcles/5279846/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print 26 saioarz021 Halla CH! C+ at Your Service - CodeProject Serialized and sendt 52740000 records as JSON in 462,185403 seconds, 1140321, 6037958688 records per second. ‘The server received one thousand batches of 527 040 SensorPoint objects as JSON that were placed ina std object, ready for parsing, This used quite a bit more time than sending the binary payload. tring ‘A point | would lke to make: Normally it's not the network transfer of the JSON data that makes this so expensive, itis the process of generating the JSON. Just serilizing data to JSON, sending it nowhere: Serialized 527040082 records to JSON in 419,02034 seconds, 1257790,970242638 records per second. ‘makes it clear that more than 90% of the time was spent serializing the data to JSON, and not transmitting and receiving the data fon the server. Converting the JSON data back into a form that can be used by a computer program costs even more Deserialized 527@4008@ records from JSON in 618,1851519 seconds, 852568, 108213754 records per second. Serialzing, sending, and deseriaizing the data using the binary format created for the server is more than 33 times as efficient as doing the same thing using JSON, and this is knowledge that can be used to cut costs ‘To perform these experiments yourself, you need to build two of the provided projects: 1. ExampleSocketServer@2 2.HarLinn. Examples. TestTcpClient .Net ‘To run the server, use the following command: ExampleSocketServer@2.exe -c -r -t -u F:\Database\ESE\Test \Database.edb where “F\Database\ESE\Test\Database.edb" is the path to the database directory. Harlinn. Examples. TestTcpClient .Net does not take any arguments, just execute it from the command-line to see the output written to the console. Building the Code Instructions for building the code are provided in Build.md located in the $(SolutionDir)Readme folder ‘The ESE tests use an environment variable HCC_TEST_DATA_ROOT, and this must be set to the full path to a directory where the tests can create a database. Make sure there is at least 10 GB of free space on the drive containig this directory, TepClient If you have tried using the TepCLient earlier, and been disappointed by its performance, that is probably because you have tied +0 perform many small read and write operations using the NetworkStream directly. Reading and writing small fragments of datas typical for data serialization and deserialzation, so anything that can improve the performance for this is important. Fortunately, NET provides a nice solution for this problem out of the box System. 10. Buf feredStream void InitializeSession(ulong id) { _sessionId = id; Var networkStrean = GetNetworkStream(); _bufferedStream = new System.I0.BufferedStream(networkStream, ushort.MaxValue / 2); Treader = new BinaryReader(_bufferedStream, Systen.Text.Encoding.Default, true); hitpsslwwu.codeproject.com/Antcles/5279848/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print 36 ‘aioarz021 Halla CH! C+ at Your Service - CodeProject _nriter = new BinaryWriter(_bufferedStream, System.Text.Encoding.Default, true); ‘The client puts a Buf feredStream between the BinaryReader and BinaryWriter objects that will be used to serialize and deserialize the data, and this really improves the performance, alot! Using BinaryReader and BinaryWriter for serialization is, as you know, a straightfonward process: public class Named : IReadwrite « Guid _id; string _name; public virtual void Read(BinaryReader reader) { _id = reader Readcuid(); “name = reader.ReadString(); public virtual void Write(Binarybiniter writer) { writer Write(_id); weiter.Write(_nane); On the C++ side of things, we also have a BinaryReader* class and a BinaryWriter class, that works well with their NET counterparts as long as the default encoding is used for character and string data. Each C# client-side implementation performs the same sequence of tasks: + Write the request: Write a byte containing the RequestReplyType identifying the function to call on the server. Write the session id and the request id \Write the parameters, if any tothe function, call Flush() on the BinaryWriter to causing the BuFFeredStream to flush any buffered data to the NetworkStream ensuring that everything writen so far is sent to the server. ‘Read the reply from the server: © Read a byte containing the RequestReplyType identifying the function that was called on the server, or RequestReplyType. Fault indicating that the reply contains error information. © Ifthe RequestReplyType matches the one that was sent 1 Read the session id and the request id from the reply, check that they match what was sent to the server. 1» Read the reply data if any is expected from the server. © Ifthe RequestReplyType is equal to RequestReplyType. Fault: = Read the error information sent by the server and throw an exception. © Inthe RequestReplyType is anything else = Throw an exception A typical call to the server is implemented lke this: public Catalogitem GetCatalogitem(Guid itenId) { Jock (_syncObj) const RequestReplyType requestReplyType = RequestReplytype.GetCatalogitem; Catalogitem result = null; var requestId = WriteRequest(requestReplytype, itemtd) ; ReadAndValidateReplyHeader(requestReplyType, request); var reader Reader; hitpsslwwu.codeproject.com/Artcles/5279848/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print ane ‘aioarz021 Halla CH! C+ at Your Service - CodeProject var found = reader.ReadBoolean(); if (found) { + return result; result = CatalogrtemFactory.Read(reader) ; Each of the methods implemented by the client library is about as simple as the above piece of code. ‘The server writes a boolean value to the stream, which is set to true if it found the requested CatalogItem Catalogitem is the base class for the Catalog and Asset classes, and the CatalogItemFactory reads a 16-bit value indicating which one its, creates and object of that type, which then deserialzes 1 1 rest of the data from the stream for that type: public static Catalogiten Create(CatalogitenType kind) { switch (kind) t case Catalogrtentype. Catalog: return new Catalog(); case CatalogrtenType.Asset return new Asset(); default: throw new Exception(“Unsupported catalog iten type"); } y public static Catalogitem Read(BinaryReader reader) « var kind = CatalogItem.ReadKind(reader); var result = Create(kind) ; result Read(reader) ; return result; y Pretty simple, but also a powerful technique that can be used to handle deserialization for types belonging te large inheritance hierarchies In the implementation of GetCatalogItem, | call WriteRequest: long WriteRequest(RequestReplyType requestReplyType, Guid id) { var result = WriteSessionHeader(requestReplyType) ; var writer = Writer; weiter.Write(id) ; weiter.Flush(); return result; y passing RequestReplyType. GetCatalogltem for the requestReplyType parameter, and | will get to that shortly. The call to writer . Flush () is really important because this will cause the Buf FeredSt ream to write the contents ofits buffer to the NetworkSt ream, This i also the last thing the client does before waiting for a reply from the server. ulong WriteSessionHeader(RequestReplyType requestReplyType) ( RequireValidsession(); var requestIa = NewRequest(); var writer = Writers writer.Write((byte)requestReplyType) ; weiter Write(_session!d); writer .Write(requestId) ; return request; hitps:slwwu.codeproject.com/Antcles/5279846/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print 56 saioarz021 Halla CH! C+ at Your Service - CodeProject WriteSessionHeader is the method that writes the start ofa request tothe server, starting with writing the value of the requestReplyType parameter as a single byte indicating which function it wants the server to perform. Next comes a 64-bit integer identifying the session on the server, and then a 64-bit counter identifying the request made by ths client to the server. ‘The RequestReplyType, session id and request id will be included in the header of the reply from the server, so we will Know that something did not get seriously mixed up server-side, The server uses a thread-pool, where the sessions are not tied to a particular thread, so I put ths into the protocol as a way to verify ths, and that isthe task performed by ReadAndValidateReplyHeader: void ReadAndValidateReplyHeader(RequestReplylype requestReplylype, ulong expectedRequestId) { var reader = Reader; var replytype = (RequestReplyType)reader .ReadByte(); if (replyType |= requestReplyType) { HandleinvalidReplyType(replyType, requestReplyType) > else if (replyType == RequestReplyType.Fault) t } Ulong sessionId = reader.ReadUInt64(); HandleFault(reader) ; Af (sessionId != sessionId) { var message = string.Format("Invalid session id: {8}, expected:(1) ", sessionId, _sessiontd); ‘throw new Exception(message); > long requestId = reader.ReadUInt64(); Af (requestid != expectedRequest Id) { var message = string.Format("Invalid request id: (@), expected:(1) ", requestId, expectedRequestId); ‘throw new Exception(message) ; > ‘The HandleFault method throws a plain vanilla Except ion containing the error message from the server: void HandleFault(BinaryReader reader) { var faultReply = new Types.FaultReply(); faultReply.Read(reader) ; ‘throw new Exception(faultReply.Message); + ‘The above is not much, but it goes a long way when it comes to establishing a decent mechanism for passing errors from the server to the client Using the TepCLient this way is remarkably easy, and the code for the method that retrieved 738 714 records per second from the server is equally simple: public SensorPoint{] GetSensorPoints(Guid sensorid, DateTime intervalstart, DateTime intervalénd) ( Jock (_syncobj) t const RequestReplyType requestReplyType = RequestReplyType.GetSensorPoints; var requestId = WriteRequest(requestReplyType, sensorid, intervalStart, intervalénd); ReadAndvalidateReplyHeader(requestReplylype, requestid); var reader = Reader; var count = reader.ReadInt32(); var result = new SensorPoint[count]; for (int i = @; 1 < count; i++) { hitpsslwwu.codeproject.com/Antcles/5279848/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print 516 ‘aioarz021 Halla CH! C+ at Your Service - CodeProject result[i].Read(reader); + return result; (Once we know that we have a valid reply, we retrieve the number of records to read from the stream, and since SensorPoint implements the IReadWrite interface, it knows how to deserialize tse. Server::TcpSimpleListener ‘The code for this article is based on the code | created for the last article about ESE. have made a few minor modifications to that code, and nearly everything else required to implement a working server example is provided in a single header file: ServerEngine h. (Once you have built the ExampleSocketServer02 project, run the server using the following commands -t -u F:\Database\ESE\Test\Database.edb ExanpleSocketServer@2.exe -¢ The implementation of the maiin function is straightforward int main( int arge, char* argv[] ) { try t Enginedptions options; if ( ParseOptions( argc, argv, options ) ) { ServerEngine engine( options, "TestInstance” ); WSA wsa; constexpr size_t ThreadPoolSize = 12; constexpr size_t SocketCount = 200; 10: :Context context( ThreadPoolsize ); Address address( options.Port ); Server: :TcpSimpleListener Listener( context, address, SocketCount, &engine ); context.start( ); puts( "Press enter to exit" ); while ( getc( stdin ) != "\n" context.Stop( ); + catch ( std:rexception& exc ) { std::string message = exc.what( ); printf( "Exception: %s", message.c_str( ) )3 ? return 05 + ‘This server implementation use the template ‘template class TepSimpleListener : public TepListener, ‘TepSimpleConnectionandler, ProtocolT> > « public: using Base = TepListenercTepSinpleListener, ‘TepSimpleConnectionlandler, ProtocolT> >; hitpsslwwu.codeproject.com/Artcles/5279848/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print 716 ‘aioarz021 Halla CH! C+ at Your Service - CodeProject tenplatectypenane ...Args> TepSimpleListener( IO::Context& context, const Address& listenaddress, size_t clientSocketCou Argsia... args ) : Base( context, listenkddress, clientSocketCount, std::forwardcArgs>( args)... ) ub which can be instantiated for a protocol implementation. Any class that implements a template function with the following signature can be used: ‘template bool Process( 10: :BinaryReader& requestReader, 10: :BinaryWriter& replyWriter ) ‘The framework will create an instance ofthe class specified by the ProtocolT template parameter for each connection, storing the arguments provided through args ina std:tuple<> that will be used to pass those arguments to the contructor of the ProtocolT type. Just like for the C# client, we have a IO: :BinaryReader<> and a IO: :BinaryWriter<> that will be used for serialization and deseriaization. The actual handling of the protocol is performed by the Protocol class. Reads and writes are buffered, and writes to the underlying socket are fully asynchronous, while reads from the socket are partially asynchronous. The write buffers comes from a pool of buffers that is shared between all the connection handlers, while there isa single read buffer is for each connection handler. Writes are queued, enabling a protocol implementation to generate a large amount of output without waiting for the client to catch up. When Protocol: : Process (..) retums false the framework will close the connection, and when it returns true it will begin a new asynchronous read operation after flushing all outstanding writes in the write queue for the connection, ‘The framework calls the Protocol : : Process(...) whenever there is data available for processing. The implementation pf Protocol only knows about the ServerEngine, and the I0: :BinaryReader<> and I0: :BinaryWriter<> abjects, This ensures thatthe implementation of Protocol is transport independent, whichis nice. The Protocol implementation: rocess(..) function just reads # byte ide! tfying the function to call and uses a Switch to call the template bool Process( 10: :BinaryReader& requestReader, 10: :Binarywriter& replywriter ) { bool result = true; auto requestType = ReadRequestType( requestReader ); switch ( requestType ) { case RequestReplyType: :CloseSession: CloseSession( requestReader, replywriter ); result = false; + break; case RequestReplyType: :GetCatalogiten: { GetCatalogrten( requestReader, replyhiriter ); t break; ? hitpsslwwu.codeproject.com/Antcles/5279848/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print ane ‘aioarz021 Halla CH! C+ at Your Service - CodeProject return result; Each server-side function implementation performs the same sequence of tasks: + Read the session id and the request id ‘+ Read the expected parameters, if any, to the function. ‘= Use the session id to find the session implementation, If this is a valid session: © Lock the session © Perform the requested operation using the SeSSion object. Ifeverything goes as expe 1 Reply to the client by writing the reply header Write a byte containing the value of RequestReplyType identifying the fun 1 Write the session id and the request id 1 Write the reply data if any is produced by the funetion © Ian exception was caught: ault 1 Write a byte containing the value of RequestReplyType = Write the session id Write the error code Write the error message + If this is not a valid session © Write an error reply tothe client, using the same format as for an exception Since you already know the client-side implementation of GetCatalogl tem, it should be easy to understand its server-side counterpart ‘template void GetCatalogitem( 10: :BinaryReader& requestReader, 10: :BinaryWriter& replywriter ) { constexpr RequestReplyType ReplyType = RequestReplyType: :GetCatalogitem; auto [sessionId, requestId] = ReadSessionRequestHeader( requestReader ); auto itemId = requestReader.ReadGuid( ); auto* session = engine_.FindSession( sessionId ); if ( session ) { ‘SERVERSESSION_TRY « Catalogitem catalogiten; auto found = session->GetCatalogitem( itenTd, catalogitem ); writeReplyHeader( replyhriter, sessionId, requestid ); replyWriter.weite( found ); Af ( found ) Weite( replydriter, catalogitem ); } + SERVERSESSION_CATCH( ); ? else { InvalidSession( replyriter, sessionId ); } + ReadSessionRequestHeader just reads the session id and request id using the BinaryReader: ‘template std: :pair ReadSessionRequestHeader( 10: :BinaryReader& reader ) hitpsslwwu.codeproject.com/Antcles/5279848/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print ane ‘aioarz021 Halla CH! C+ at Your Service - CodeProject « auto sessionId = reader.ReadUInt6a( )5 auto requestId = reader.ReaduInt6d( ); return { sessionId, requestid }; + ‘Then the implementation reads the single parameter, itemId, from the stream, [At this point, we are done reading request information, and iti time to retrieve the session. If found, we lock on the session, and if not, this is reported back to the client by the InvalidSess.ion function define SERVERSESSION_TRY std: :unique_lock lock( *session ); try SERVERSESSION_TRY is 2 macro that locks the session and starts a try/cattch block. Any exception thrown by the implementation will be caught by SERVERSESSION_CATCH( ), which will write the appropriate error information to the reply stream define SERVERSESSTON_CATCH() \ catch ( const Core: :€xception& ex ) \ (\ WeiteFault( replybriter, sessionId, ex ); \ v\ catch ( const st an WeiteFault( replykiriter, sessionId, exc ); \ v\ catch ( const ThreadAbortéxception& ) \ (\ throws \ rrexception& exc ) \, Unknownexception( replyhiriter, sessionId ); \ ‘The above works well as long as nathing has been written to the reply. If something goes wrong while serializing the reply, that will indicate that something is seriously wrong with the state of the socket, causing vill cause the server implementation to reset the connection, 1 error reporting functions to throw too — which With a lock on a valid session in place, the implementation of GetCatalogItem just cals the implementation of the GetCatalogItem on the Session object, and then writes the result to the reply stream, ServerEngine and ServerSession ‘The Server Engine class is derived from template class EngineT, where Dis the derived type ServerEngine, and T is the ServerSession type. By using the curiously recurring template pattern, the EngineT template can pass a reference to its derived type to the constructor forthe session implementation. The Server Engine class does not provide any functionality beyond what is implemented by the EngineT template, but the template needs to know what kind of SeSSioN objects it is going to manage. Similarly, ServerSession is derived from templatectypename T> class SessionT, where T is the SessionEngine class. The ServerSession adds some critical pieces of functionality, that is required to be able to safely lock the session while processing client requests by threads from the thread-pool The ServerSession class uses the Critical Section from the Synchronization with Visual C++ and the Windows API article class ServerSession : public SessionT inique_ptr criticalSection_; hitps:slwwu.codeproject.com/Artcles/5279848/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print 10116 ‘aioarz021 Halla CH! C+ at Your Service - CodeProject ‘The reason for using a uniique_ptr<> to hold the CriticalSection, is that the CritticalSect ion will havea lifetime that goes slightly beyond the lifetime of the session: void Close( ) { std: :unique_lock lock( *criticalSection_ ); auto ciriticalsection = std::move( criticalsection_ ); Base::Close( ); y Base: :Close() will lose the ESE session handle, and then tell the Server Engine to destroy the session, and we need to allow the destructor for lock to safely call unLOck() on the critical section, so it cannot ust go away until the lock goes out of scope ‘The ServerSession implements the C++ BasicLockable requirement that describes the minimal characteristics of types that provide exclusive blocking void lock( ) const « criticalSection_->Enter( ); auto& eseSession = EseSession( ); Urnt64 context = (UInt64)this; eseSession.SetContext( context ); printf( "Set context: %11u\n", context ); + The Lock() function calls Enter () on the CriticalSecion, before calling SetContext (...) on the ESE session associating the session with the current thread, This association overrides the default behavior of ESE where an entire transaction for a given session must occur within same thread ‘The unLock() function removes the association with the current thread, before releasing the lock held on the critical section, void unlock( ) const { auto& eseSession = EseSession( ); eseSession.ResetContext( ); criticalSection_->Leave( )} Umnt6s context = (vinta) this; printf( "Reset context: %Llu\n", context ); y ‘The above implementations of Lock () and unlock) allows the session to be served by one thread from the thread-pool for cone cal, an another thread for the next Using the C# Client Library ‘The download includes the source code for the executable that was used to test the C# client library, and here are a few “high- lights’ ‘The main class of the client library is called Session, and the following snippet creates a session object and connects to the void Connect() { _session = new Session( localhost’ Tsession.connect(); 42000); ‘To clase the connection: hitps:slww.codeproject.com/Artcles/5279846/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print m6 saioarz021 Halla CH! C+ at Your Service - CodeProject void Disconnect() i 4 (session I= null) c _session.Close(); ) “session = ull; y To build » data-data model, we frst need to create on or more catalogs at the root of the catalog structure: var catalog = _session.CreatedrRetrieveCatalog(Guid. Empty, name’ Passing an empty GUid indicates that this will be a root catalog, otherwise the Guid has to identify an existing catalog. Once we have a catalog, we can add an Asset: var asset = _session.CreateOrRetrieveAsset(catalog.1d, name); and then we can create a Sensor: var sensor = _session.CreateOrRetrieveSensor(asset.1d, name); With a Sensor object in place, we can store a timeseries of SensorPoint data for the sensor: SensorPoint[] GenerateSensorPoints(Sensor sensor, TimeSpan offset) « var points = GenerateSensorPoints (offset); var stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); _session.StoreSensorPoints(sensor.Id, points); Stopwatch. Stop(); var seconds = stopwatch. Elapsed. TotalSeconds; var pointsPersecond = points. Length / seconds; Console.Out.WriteLine("Wrote {8} records in {1} seconds, {2} records per second.", points.Length, seconds, pointsPerSecond) ; return points; retrieving timeseries data for an interval is done using: _pointsiRetrieved = _session.GetSensorPoints(_sensor1a.Id, _intervalStart, _intervalEnd); The End Hopefully, you learned something interesting, and useful, from this article, My hope is that | was able to provide enough information here to get you interested in trying out alternatives for serializing and desralizing data sent between the components of your solutions. Personally, | realy like the performance | can get out of FlatBuffers and Cap'n Proto, and Microsofts’ Bond has features, such as inheritance, that | find highly desirable, Apache Thrift and Goggles’ Protocol Buffers are the ones most widely used, with larger eco-systems surrounding them, Each have their strengths, and by writing this article, my goal was to provide a few insights that will help you pick the one that is Fight for your projects, As this pet project moves forwards, | will try to find ways to integrate at least one them with the server framework. So, until next time: Happy coding! hitps:slww.codeproject.com/Artcles/5279846/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print 1216 saioarz021 Halla CH! C+ at Your Service - CodeProject History 18!” of September, 2020: Initial post o'* of September, 2020: Fixed misssing inline for two functions in HCCEse.h, and the ESE tests now use an environment variable, HCC_TEST_DATA ROOT, to configure where the test database will be created. 6° of October, 2020 - Bug fixes, cleaned up most ofthe unt tests. 7" of October, 2020 - More unit tests for the Harlinn.Common Core library 1 October, 2020 - More unit tests for the Harlin. Common .Core library 13" October, 2020 - More unit tests for the HarLinn . Common . Core library, and two new examples for the Harlin. Windows library. 17" October, 2020 - Fix for TimerQueue and TimerQueueTimer, more unit tests for the Harlin. Common .Core library 18" December, 2020: © Bug fixes for O:FileStream © Initial http server development support = Synchronous server: §(SolutionDir)Examples\Core\HTTP\Server\HttpServerExO1 = Asyncronous server: $(SolutionDir)Examples\Core\HTTP\Server\HttpServerEx02 © Simplified asynchronous 1/0, Timers, Work and events for Windows waitable kernel objects using Windows thread pool API: $(SolutionDir}Examples\Core\ThreadPools\HExIpex01 1 anuary, 2021 © Improved support for asychronous server development © New design for working with sockets © Concept based stream implementations 11" of February, 2021: © Bug fixes © Initial C+ + ODAC support 2st” of February, 2021 © Updated LMDB. © Updated xxHash © Added the inital implementation of very fast hash based indexes for large complex keys using LMDB: © Fast asychronous logging - nearly done =) 3° of March, 2021: ization related classes 1 Securityld: Wrapper for SID and related operations 1 ExplicitAccess: Wrapper for EXCPLICIT ACCESS. 1 Trustee: Wrapper for TRUSTEE = SecurityldAndDomain: Holds the result from LookupAccountName = LocalUniqueld: Wrapper for LUID ‘= AccessMask: Makes it easy to inspect the rights assigned to an ACCESS MASK 1 AccessMaskT<> 1 EventWaitHandleAccessMask Inspect and manipulate the rights of an EventWaitHandle. 1 MutexAccessMask: Inspect and manipulate the rights of a Mutex. 1 SemaphoreAccessMask: Inspect and manipulate the rights of a Semaphore, 1 WaitableTimerAccessMask: Inspect and manipulate the rights of 2 WaitableTimer. 1 FileaAccessMask: Inspect and manipulate file related rights. * DirectoryAccessMask: Inspect and manipulate directory related rights. = PipeAccessMask: Inspect and manipulate pipe related rights. 1 ThreadAccessMask Inspect and manipulate thread related rights. 1 ProcessAccessMask: Inspect and manipulate process related rights 1 GenericMapping: Wrapper for GENERIC_MAPPING 1 AccessControlEntry: This is a set of tiny classes that wraps the ACE hitps:slwwn.codeproject.com/Antcles/5279846/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print 1316 saioarz021 Halla CH! C+ at Your Service - CodeProject = AccessContr ryBase<,> 1 AccessAllowedAccessControlEntry 1 AccessDeniedAccessControlEntry = SystemAuditAccessControlEntry 1 SystemAlarmAccessControlEntry 1 SystemResourceAttributeAccessControlEntry = SystemScopedPolicyldAccessControlEntry 1 SystemMandatoryLabelAccessControlentry 1 SystemProcessTrustLabelAccessControlEntry 1 SystemAccessFilterAccessControlEntry = AccessDeniedCallbackAccessControlEntry 1 SystemAuditallbackAccessControlEntry 1 SystemAlarmCallbackAccessControlEntry = ObjectAccessControléntryBase-<,> = AccessAllowedObjectAccessControlEntry 1 AccessDeniedObjectAccessControléntry 1 SystemAuditObjectAccessControlEntry 1 SystemAlarmObjectAccessControlEntry = AccessAllowedCallbackObjectAccessControlEntry 1 AccessDeniedCallbackObjectAccessControlEntry 1 SystemAuditCallbackObjectAccessControléntry 1 SystemAlarmCallbackObjectAccessControlEntry 1 AccessControlList: Wrapper for ACL * PrivlegeSet: Wrapper for PRIVILEGE_SET '= SecurityDescriptor: Early stage implementation of wrapper for SECURITY_DESCRIPTOR = SecurityAttrioutes: Very early stage implementation of wrapper for SECURITY_ATTRIBUTES Token: Early stage implementation of wrapper for an access token = Domaindbject 1 User: Information about a local, workgroup or domain user = Computer: Information about a local, workgroup or domain computer = Group: local, workgroup or domain group Users: vector of User objects Groups: vector of Group objects A of March, 2021 - more work on security related stuff: ‘Token: A wrapper for a Windows access token with a number of supporting classes like 1 TokenAccessMask: An access mask implmentation for the access rights of a Windows access token. 1 TokenGroups: A wrapper/binary compatible replacement for the Windows TOKEN_GROUPS type with a C++ container style interface, = TokenPrivileges: A wrapper/binary compatible replacement for the TOKEN_ PRIVILEGES type with a C++ container style interface, "= TokensStatistcs: A binary compatible replacement for the Windows TOKEN. STATISTICS type using types implemented by the library such as LocalUniqueld, TokenType and ImpersonationLevel. = TokenGroupsAndPrivileges: A Wrapper/binary compatible replacement for the Windows TOKEN_GROUPS_AND_PRIVILEGES type. = TokenAccessinformation: A wrapper/binary compatible replacement for the Windows TOKEN_ACCESS INFORMATION type. 1 TokenMandatoryLabel: A wrapper for the Windows TOKEN_MANDATORY_LABEL type. SecurityPackage: Provides access to information about a Windows security package. SecurityPackages: An std:unordered_map of information about the security packages installed on the system, CredentialsHandle: A wrapper for the Windows CredHandle type, SecurityContext: A wrapper for the Windows ChxtHandle type CryptosBlob and Crypto:BlobT: C++ style _CRYPTOAPI_BLOB replacement CertiticateContext: A wrapper for the Windows PCCERT_CONTEXT type, provides access to a X.508 certificate. CertificateChain: A wrapper for the Windows PCCERT_CHAIN_CONTEXT type which contains an array of simple certificate chains and a trust status structure that indicates summary validity data on all of the connected simple chains. © ServerOcspResponseContext: Contains an encoded OCSP response. © ServerOcspResponse: Represents a handle to an OCSP response associated with a server certificate chain hitps:slww.codeproject.com/Artcles/5279846/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print 146 saioarz021 Halla CH! C+ at Your Service - CodeProject © CertificateChainEngine: Represents a chain engine for an application. © CertificateTrustList: A wrapper for the Windows PCCTL_CONTEXT type which contains both the encaded and. decoded representations of a CTL. It also contains an opened HCRYPTMSG handle to the decoded, eryptographically signed message containing the CTL_INFO a its inner content. © CertificateRevocationList: Contains both the encoded and decoded representations of a certificate revocation lst (RD, © Certificatestore: A storage for certificates, certificate revocation lists (CRLs), and certificate trust lsts (CTLs) License This article, along with any associated source code and files, scensed under The Code Project Open License (CPOL) About the Author Espen Harlinn Architect Ulriken Consulting AS Norway i Senior Architect - Uliken Consulting AS. Specializing in integrated operations and high performance computing solutions, I've been fooling around with computers since the early eighties, 've even done work on CP/M and MP/M, Wrote my first “real” program on a BBC micro model 8 based on a series in a magazine at that time, It was fun and | got hooked fn this thing called programming A few Highlights: ‘High performance application server development ‘= Model Driven Architecture and Code generators ‘Real-Time Distributed Solutions + C.C++, GH, Java, TSQL, PL/SQL, Delphi, ActionScript, Per, Rexx + Microsoft SQL Server, Oracle RDBMS, IBM DB2, PastGreSQl ‘+ AMQP, Apache qpid, RabbitM, Microsoft Message Queuing, IBM WebSphereMQ, Oracle TuxidoM@ * Oracle WebLogic, IBM WebSphere + Corba, COM, DCE, WCF + AspenTech InfoPlus.21(1P21), OsiSot PI More information about what I do for a living can be found at: harlinn.com or Linkedin You can contact me at espen@harlinn.no Comments and Discussions hitps:slww.codeproject.com/Artcles/5279846/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print 1516 ‘aioarz021 Halla CH! C+ at Your Service - CodeProject Of 12 messages have been posted fortis article Visit https//www.cedeproject.com/Articles/5279846/Hello-Csharp- Cplusplus-at-Your Service to post and view comments on this article, oF click here to get a print view with messages. Permalink Axticle Copyright 2020 by Espen Harlinn Advertise Everything else Copyright © CodeProject, 1999- Privacy 2021 Cookies Terms of Use \web03 2620210308. hitps:slwwn.codeproject.com/Antcles/5279846/Hello-Csharp-Cplusplus-at-Your Service dlsplay=Print 1816

You might also like