Jump to content

Dmitry Onoshko

Members
  • Content Count

    37
  • Joined

  • Last visited

Everything posted by Dmitry Onoshko

  1. Dmitry Onoshko

    Handling TCP send buffer overflow the right way

    Thanks, made a few corrections to take that into account. I also saw somewhere that receive notification message would be posted to the message queue whenever ReceiveBuf leaves some data unread, so no point making a loop for ReceiveBuf, right?
  2. Dmitry Onoshko

    Handling TCP send buffer overflow the right way

    Well, in fact I do set the ErrorCode in the handler, ’cause the requirement is to provide custom user-friendly socket error handling, and it seems to be much easier to have a single point of failure instead of putting try…excepts every now and then. BTW, am I right that the whole point of checking for WSAEWOULDBLOCK vs some other error code is to avoid adding data to Tx buffer is the socket has already failed? And, if you don’t mind, another small TServerSocket-related question. It seems to only have an OnClientError event but no “OnError”-kind event for the listening socket. Which makes me wonder if there’s any better way to handle, say, listening port being already taken by another program than using SetErrorProc (which feels a bit messy, too).
  3. Dmitry Onoshko

    Handling TCP send buffer overflow the right way

    Thanks, that really makes it much more clear, and since I already have custom wrappers around those TClientSocket and TServerSocket adding a Tx buffer of customizable size to the wrappers looks promising. But one thing is still unclear: SendBuf doesn’t return the WinSock error code and neither of the socket classes seem to have properties to access it. I can only see two possibilities here: (1) the OnError handler that is called from SendBuf if the error is not WSAEWOULDBLOCK and (2) calling WSAGetLastError again myself. The first option leads to complication of the OnError handler which now has to store the error code somewhere just in case anyone asks. The second option feels like jumping through levels: that would require adding WinSock library to uses clause and relying on the fact that the last operation to fail inside SendBuf is the send() I’m interested in. Is there any better option I can’t see?
  4. Suppose there’re two TCP-based protocols that should be implemented with the following gotchas in mind: any message might get broken into pieces while passing through multiple routers; there might not only be well-formed messages, but ill-formed messages and garbage data as well. The logic of extracting messages from a TCP stream can quite easily be abstracted and implemented only once, in a base class (say, TCustomProtocol) that might only use a few virtual abstract methods to perform protocol-specific processing. Then there would be two descendant classes that implement those methods. Note also, that extracting those messages involves actually parsing and “decoding” the messages, as part of the extraction. Now the problem is that whenever a well-formed message is extracted from the stream, an event (say, OnMessage) should be fired passing the parsed message data to the event handler. The point where the event should get fired is obviously in the base class, but the types used to represent the parsed messages are very different due to the nature of those protocols. So, defining the class members for the event in the base class is problematic. I can see several solutions: Define the message parameter of OnMessage in a very generic way: untyped parameter or a (Pointer, Size) pair. This removes type checking from the scene, though, and requires the event handler to do type casting. Define the base class as a parameterized (generic) class: TCustomProtocol<TMessageType>. Then derive TFooProtocol and TBarProtocol using TCustomProtocol<TFooMsg> and TCustomProtocol<TBarMsg> as base classes, define the OnMessage type using TMessageType. This solution is almost good but leaves OnMessage (and any other event define in the base class) with the ugly TCustomProtocol<TMessageType> parameter that the users of TFooProtocol and TBarProtocol should write defining their event handlers. Write all the OnMessage-related stuff separately in descendants. Doubles the amount of code for the stuff that is otherwise the same. I wonder, how would/do you solve the problem with modern Delphi? Thanks in advance for your answers.
  5. type TCustomProtocol<TMessageType> = class type TMessageEvent = procedure(Sender: TCustomProtocol<TMessageType>; const AMessage: TMessageType) of object; private FOnMessage: TMessageEvent; ... end; TCoolProtocol = class(TCustomProtocol<TCoolMessage>) ... end; ... procedure TCoolServer.MessageReceived(Sender: TCustomProtocol<TCoolMessage>; const AMessage: TCoolMessage); var Proto: TCoolProtocol absolute Sender; begin // Handling goes here end; The first parameter here has a long type specification which actually contains two type names. Besides, the procedure header basically repeats itself: one TCoolMessage would be enough to understand what’s going on. Hmmm, I’ve just felt that the wider problem here is that there seems to be no way to define the event in such a way that Sender type is always the descendant that can extract the message. That would also allow the handler to get access to all the methods provided by the specific descendant. Anyway, the generic-based approach works, it just doesn’t seem nice enough.
  6. Sorry, I failed to state that one of the parameters of the event handler should be the protocol object that extracted the message (so that the event handler can perform certain actions on the object), that’s the reason I complain about the ugly TCustomProtocol<TMessageType> argument. So, yes, that’s my approach number 2, but the disadvantage is that ugly argument type then.
  7. Well, the second approach actually starts with TFooProtocol = class(TCustomProtocol<TFooMsg>) and TBarProtocol = class(TCustomProtocol<TBarMsg>), since the descendants have to implement abstract methods from the base class. So, the names are already used. And since OnMessage should be defined in the base class, and the base class should normally know nothing about its descendants, I can see no way to use such type definitions without breaking the concepts of OOP.
  8. Consider the following structure of a project. A unit called MyTypes. Types used throughout the project are declared here (in its interface section). A unit called UnitA. It implement useful classes, and those classes have events and methods with parameters of types from MyTypes unit. Obviously there’s a “uses MyTypes” clause in the interface section of the unit. A unit called UnitB. It uses UnitA in its interface section and implements some higher-level logic on top of what that unit contains. Now UnitB might need to use types from MyTypes unit to interact with UnitA. Say, to store some values temporary before passing them to UnitA’s classes. And since definitions are not transitive between units, I can see two possibilities here. Using all the units UnitB uses both MyTypes and UnitA. This way it knows the types declared in both units. The disadvantage is that whoever writes UnitB should now be aware of which other units to add to “uses” clause. Redefining the types in UnitA UnitB now uses only UnitA, but UnitA has the following definitions in its interface section: type TSomeType = MyTypes.TSomeType; TOtherType = MyTypes.TOtherType; ... UnitB now only has to have UnitA in its “uses” clause. But then UnitA might have like A LOT of such “transitive” definitions, and it’s quite easy to skip some of them. What are the recommendations in general and for modern Delphi particularly? Is such “transitive” definition considered OK? Does it probably have some special name then?
  9. I’ve finally decided to give a try to the relatively new System.Net.Socket unit and its TSocket class. After successful connection of a client TCP socket (also monitored with Wireshark) and performing EndConnect I immediately do Socket.BeginReceive(MyCallback); expecting to get called back when some data arrives. But if the server doesn't transmit anything, ESocketError 'Timeout receiving data' gets raised a lot of times by this piece of code: procedure TSocket.WaitToReceiveData; begin if WaitForData(ReceiveTimeout) = TWaitResult.wrTimeout then raise ESocketError.CreateRes(@sSocketReceiveTimeout); end; which is called from here: function TSocket.BeginReceive(const AsyncCallback: TAsyncCallback; Count: Integer; Flags: TSocketFlags): IAsyncResult; begin Result := TSocketReceiveAsyncResult.Create(Self, function: TBytes begin if Count < 0 then WaitToReceiveData; Receive(Result, Count, Flags); end, AsyncCallback).Invoke; end; The timeout applied is 0, so the asynchronous Receive basically turns into not-so-tight polling spin loop. It obviously is quite inconvenient when debugging the program (tons of useless ESocketErrors), but what really worries me is the waste of processor time that happens. Is the TSocket class really usable these days? Is there some good way to get notified about data arrival without blocking, using arbitrarily chosen timeouts and busy waiting? (It’s Delphi 11 CE.) And, if Indy, ICS and other third-party libraries are not allowed, does this leave me with ScktComp and hand-written WinSock-based implementation?
  10. Dmitry Onoshko

    System.Net.Socket: TSocket.BeginReceive timeout

    Yep, that’s exactly how I got them working. I should have expressed my point somewhat more precisely when talking about “by default”.
  11. Dmitry Onoshko

    System.Net.Socket: TSocket.BeginReceive timeout

    I’m pretty sure I pushed “Continue” in the debugger exception message and almost immediately stopped at a breakpoint I’ve put somewhere before the WaitForData call. I was also quite surprised that it got like out of nowhere. I guess, I could try to reproduce it in a separate test project (in my code BeginReceive was only called in connect callback and after successful receive callback, the latter obviously didn’t have a chance to run). Just maybe somewhat later, in case it’s worth doing that. Or maybe it really was my mistake, I couldn’t find the source of multiple attempts in a reasonable amount of time. And later, when the errors are for a valid reason, that would be a pain to debug either with ESocketError ignored by the debugger or with tons of irrelevant ESocketErrors. The former is no better than the latter. Third-party dependencies have their cons long-term-wise. In fact, I’ve already written a set of base classes to wrap socket libraries without interfering the rest of the program. So, moving from one to another might be a bit easier. Still, any library not shipped with Delphi CE for free is not welcome by default. And Indy uses blocking model which makes me worry about serving like a few thousands of clients (expected amount of persistent connections). I’m actually afraid of ScktComp.TServerSocket as well, but it at least looks promising in spite of not being available by default in modern versions of Delphi.
  12. Thanks, guys. I felt something was a bit wrong with such definitions in spite of them being quite an obvious alternative. Frankly speaking, this part is quite unexpected for me, since I never had a chance to dive deep into RTTI, and the “classical” Pascal treated types T1 and T2 equal whenever there ould be a T1 = T2 declaration. I think I understand the reasons, but I’ll have to read more on topic to be sure.
×