Jump to content

Recommended Posts

Thanks Daklu!

 

Your first diagram accurately conveys what I'm currently doing. I see how the stepwise routing can decouple things a little bit more, but it seems like there's a lot more "boilerplate" in terms of message handling. With the onion routing approach you only ever have to make the appropriate "RouteToxxx" messages. With step-wise, every time you make a new message you have to effectively propagate some sort of message handling for that message all the way through your code. For me, that's only really 4 layers (not counting the TCP Client/Server as they're effectively blind to messages). If there were more layers though, I feel as if it would quickly become tedious "make work".

 

Also, I have a theoretical objection to it on another level. It requires the routing layers to be opaque to the processes using them. By opaque I mean that they don't just pass the messages, they actually handle them, even if that "handling" IS just passing the message.

 

I acknowledge your criticisms and advice though. I have noticed that I have a lot of static dependencies and a LOT of variant messages carrying typedeffed data structures all throughout my code.

Link to comment
  • Replies 63
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Posted Images

I see how the stepwise routing can decouple things a little bit more, but it seems like there's a lot more "boilerplate" in terms of message handling. With the onion routing approach you only ever have to make the appropriate "RouteToxxx" messages. With step-wise, every time you make a new message you have to effectively propagate some sort of message handling for that message all the way through your code.

 

Yep, it's a tradeoff and the "right" decision depends on the value you assign to various factors.  My development process is very organic and iterative, so I place a high value on practices that let me refactor easily.  Limiting dependencies goes a long ways towards meeting that requirement.  Those using a different dev process will probably weight the factors differently.

 

 

Also, I have a theoretical objection to it on another level. It requires the routing layers to be opaque to the processes using them. By opaque I mean that they don't just pass the messages, they actually handle them, even if that "handling" IS just passing the message.

 

Onion routing does the same thing.  The message still has to be "handled" at every step in the chain--you still need a RouteTo7813R message handling case in your RT TCP Receive loop.  Functionally, the only difference between onion and stepwise routing is in where the message transformations are defined.  In onion routing they are defined by the message sender.  In stepwise routing they are defined at each step.

 

In fact, your topology seems to mix onion routing with stepwise routing.  Specifically, the WinMsgRouting element adds a wrapper message around the data (SendViaTcp) instead of just peeling off a layer and processing what's left.  If I were a new developer on the project, this inconsistency would make it harder for me to figure out how I should implement a new feature.  How much onion routing should I use?  Where should I use stepwise routing instead?  I'd encourage you to use one or the other, but avoid arbitrarily mixing them.

 

-------

 

As an aside to onion vs stepwise routing, I'll point out that your choice of message names naturally limits your ability to easily replace components.  For example, the message RouteTo7813R defines the exact hardware that the software uses.  What if you wanted to replace the 7813R with the new and improved 7814R?  Is there a way you can rename the message to reflect the destination's functionality instead of hardware model?  (RouteToDIO?)

Link to comment

My development process is very organic and iterative, so I place a high value on practices that let me refactor easily.

But would it not be easier to refactor in TCP communication if the extra added processes of TCP send/receive don’t have to be custom created to handle specific messages. And if my end processes are “X” and “UI for X”, how useful is it to have three intermediate message-handling stages? Surely at least one of that long message chain doesn’t need to know what an “Enable Motor” message means?
Link to comment
you still need a RouteTo7813R message handling case in your RT TCP Receive loop. 

Don't know much about this API so may be missing a fundamental implementation aspect here. But if you have a "RouteTo7813R message" (which you presumably you must have for a reciprocal receive case). Is there a reason you cannot have just one wrapper layer (lets call it "Router") and all it does is, well, route? The arguments could be Target, Sender and Payload Message.

Link to comment
In fact, your topology seems to mix onion routing with stepwise routing.  Specifically, the WinMsgRouting element adds a wrapper message around the data (SendViaTcp) instead of just peeling off a layer and processing what's left.  If I were a new developer on the project, this inconsistency would make it harder for me to figure out how I should implement a new feature.  How much onion routing should I use?  Where should I use stepwise routing instead?  I'd encourage you to use one or the other, but avoid arbitrarily mixing them.

He’s actually using what I call “Outer Envelopes”.  You didn’t like them when I suggested them before:D In fact, I use a “Send Via TCP” outer envelope in my TCP message system.

Link to comment
He’s actually using what I call “Outer Envelopes”.  You didn’t like them when I suggested them before:D In fact, I use a “Send Via TCP” outer envelope in my TCP message system.

I think you'll find I didn't comment on your suggestion before at all. I just shut up because I was told to stop reading because it was POOP.

 

They are talking about Onion and Chain Routing of messages. The former is (in your terminology) an  envelope inside an envelope inside an envelope ...ad nauseum. The latter is an envelope with a friends address with a "please forward to this other friend ".....ad nauseum. I'm just suggesting they just send it directly to the recipient by using a dispatcher. I have no idea how it would be implemented or what your "envelopes" do. I'm sure Daklu would come up with an elegant solution given the description if it was viable. For me, it's just a case of using a keyword in a  string and making sure something is listening for it but the principle is the same. Therefore it is Chain Routing with a fixed 2 level depth.

Link to comment
But would it not be easier to refactor in TCP communication if the extra added processes of TCP send/receive don’t have to be custom created to handle specific messages. And if my end processes are “X” and “UI for X”, how useful is it to have three intermediate message-handling stages? Surely at least one of that long message chain doesn’t need to know what an “Enable Motor” message means?

 

Having to insert a TCP layer into an existing application isn't something I've needed to do much, so I don't spend too much effort considering that particular change request.  My customers usually know up front what kind of network support is needed.  That said, the TCP layer is one place where I will often use a simple Send message instead of implementing custom messages for the receiver.  (In fact my diagram above shows the TCP layer receiving a Send message instead of an EnableMotor message.)  It just depends on how the app is structured, what the dependency graph looks like, and what I'm trying to accomplish.

 

When a TCP actor exposes a Send message, other parts of the application have explicit knowledge of the TCP actor by virtue of having to use the Send message.  When a TCP actor exposes receiver-specific messages is has a more transparent proxy-like interface.  The message sender can send the message without knowing or caring whether the receiver is local or across the network.

 

If the link between the sender and receiver will always be over the network, I often use explicit ('Send' message) TCP actors.  If the receiver may or may not be over the network (i.e. unit testing) I'm more likely to build the TCP layer as a proxy and implement receiver-specific messages.

 

 

Don't know much about this API so may be missing a fundamental implementation aspect here. But if you have a "RouteTo7813R message" (which you presumably you must have for a reciprocal receive case). Is there a reason you cannot have just one wrapper layer (lets call it "Router") and all it does is, well, route? The arguments could be Target, Sender and Payload Message.

 

Nope, no reason you can't do that.  Using a single message dispatcher gives you a star messaging topology.  Alex is already using a tree topology, so my answer is oriented towards that.  Personally I prefer a tree topology over a star topology because it more clearly defines subsystems and (imo) it is easier to verify the subsystems are not being improperly accessed by other actors.

 

 

 

He’s actually using what I call “Outer Envelopes”.

 

My understanding of the intent of Outer Envelopes is:

  1. A sends a message to B in an outer envelope.
  2. B does some data processing and sticks the results in the inner envelope.
  3. B sends the inner envelope to C, as previously defined by the inner envelope.

With the onion routing Alex is doing there isn't (presumably) any processing done at B.  It just removes the outermost layer and sends the message on its way.  Structurally onion routing and outer envelopes are the same, but according to my understanding the intent is a little bit different.

 

The main advantage to onion routing is you can easily figure out who the receiver is without inspecting the code at each hop.  If any of the hops do their own processing then you've just lost that advantage.  A new developer is going to have to inspect the code at each hop anyway to figure out what is happening, so all you've done is extend the dependencies through the system.

 

There are very few situations where I might use an outer envelope.  Here's one:

 

post-7603-0-19528300-1371151880.png

 

In this example Comp1.A collects data for analysis.  Comp1 sends the data to Comp2 for analysis.  After analysis is complete Comp2 sends the results back to Comp1, which then sends the results to B, C, or D.  I would consider an outer envelope if all of the following conditions are true:

  1. The ultimate destination (B, C, or D) is known prior to sending the data to Comp2 for analysis.
  2. Data analysis takes longer than data collection.  In other words, it is possible for multiple data packets to be analyzed at the same time.  (If only one data packet can be analyzed at a time, I'd likely just use a field in Comp1.MsgHndlr to identify the final destination.)
  3. The originator is already dependent on the final destination.  I don't want to create dependencies between A and B, C, or D where none existed previously.
  4. I want to keep Comp2 free from dependencies on Comp1.
     

Link to comment
 (In fact my diagram above shows the TCP layer receiving a Send message instead of an EnableMotor message.) 

Opps.  Sorry, I missed that.

 

When a TCP actor exposes a Send message, other parts of the application have explicit knowledge of the TCP actor by virtue of having to use the Send message.  When a TCP actor exposes receiver-specific messages is has a more transparent proxy-like interface.  The message sender can send the message without knowing or caring whether the receiver is local or across the network.

Not if you have a dynamic-dispatched “Send” method, in which case the wrapping of the original message in the SendViaTCP message can be inside the Send method.  It’s the same technique you’re using in your LapDog PrefixQueue, where the sending process is unaware that the messages it is sending are having a prefix added.  Similarly, a process doesn’t have to know it is sending messages via TCP.  

 

 

My understanding of the intent of Outer Envelopes is:...

This isn’t really what I’m thinking of.  “Outer Envelope” suggests a message holding another message.  I don’t see why the inner message need be empty (an unfilled “inner envelope”).

 

— James

Link to comment
Hey guys,

 

I'm glad to have sparked such an interesting debate (to me at least). What diagramming software are you using Daklu? I'm finding it difficult to convey what's going on without drawing it. Here is my attempt with powerpoint:

post-16778-0-44830300-1371160551_thumb.p

 

As ShaunR said, the windows and LVRT "main" loops are acting as routing layers for UI->TCP->Process and vice versa. In the Windows Routing Loop, the message handler sees "RouteToLVRT" and knows that it has to send that message over TCP, so wraps it in the TCP Clients "Send" message. "RouteToWindows" in the LVRT router has the same effect. If I want to effectively bypass a layer, i.e. have one UI spin up another sub-UI then I just implement "SendToLVRT" as a simple 'pass-on' all the way up until it reaches Windows Routing Loop. Alternatively, I could hand the sub-UI Windows Routing Loops queue..?

 

@Daklu: What I meant by opacity was that, as I understand it, for every new message in a stepwise architecture, I need to propagate message handling code all the way down the chain. For Onion style, creating a new message from any given UI to it's corresponding hardware gives me no developer overhead, I just wrap it in the appropriate "envelopes" and away we go. The only time I add new intermediate handling is when a new process or new UI gets added. The reason the Win and LVRT msg handlers add wrappers when they want to send via TCP is that it makes UI/processes blind to the fact they're talking over the network, and the TCP processes never need to implement any messaging logic except send and receive methods, error handling and shutdown/startup. There is likely a better way to do this, but I haven't thought too hard about how I would make it more general.

 

Also, you're right, I should definitely rename the messages to reflect functionality rather than hardware! I think I made that decision originally because the 7813R specifically is a jack of all trades FPGA that I'm using for a number of different hardware control and measurements.

 

Hopefully that clarifies things a bit.

Edited by AlexA
Link to comment
This isn’t really what I’m thinking of.  “Outer Envelope” suggests a message holding another message.  I don’t see why the inner message need be empty (an unfilled “inner envelope”).

 

Fair enough.  Though I like "onion routing" better.  :)

 

 

Not if you have a dynamic-dispatched “Send” method, in which case the wrapping of the original message in the SendViaTCP message can be inside the Send method.  It’s the same technique you’re using in your LapDog PrefixQueue, where the sending process is unaware that the messages it is sending are having a prefix added.  Similarly, a process doesn’t have to know it is sending messages via TCP.  

 

My comment was directed at systems using stepwise routing, not onion routing.  You are correct the PrefixQueue overrides the Send method in the same way you are suggesting, but the use case is different.  I use the PrefixQueue to send messages from subactors up to managing actors so the managing actor can identify the sender.  The managing actor sets the prefix for the branch of its own input queue prior to instantiating the subactor and giving it the queue.  If you apply what you are describing to Alex's diagram, you are wrapping messages sent from the managing actor to the subactor--the reverse of what I do with the PrefixQueue.

 

Overriding Send to wrap all messages in a SendViaTCP message is functionally the same as not having a message handler in the TCP actor and automatically sending all the messages over the network.  The wrapping serves no purpose.  Furthermore, if you automatically forward all messages over the network you give up the ability to send messages to the TCP actor itself.  When you do want to send a message to the TCP actor, you have to put conditionals in the Send method to only wrap those messages that should be sent over the network.  Now your TCP actor has a MessageQueue subclass customized only for itself.

 

Combining onion routing with dynamic dispatching the Send method adds complexity that, imo, is usually unnecessary.  I'm not saying it isn't useful sometimes, just that it seems to use dynamic dispatching because it can instead of basing the decision on the value it adds to the codebase.  (Of course, I likely value certain code characteristics differently than you.)

 

 

@Daklu: What I meant by opacity was that, as I understand it, for every new message in a stepwise architecture, I need to propagate message handling code all the way down the chain. For Onion style, creating a new message from any given UI to it's corresponding hardware gives me no developer overhead, I just wrap it in the appropriate "envelopes" and away we go.

 

Until something requires slightly changing the structure of the application, such as combining functional components into a subsystem and inserting a managing actor.  Then you have to revisit everything that sends a message there and change it to reflect the new structure.  That can be impossible in some deployment situations.  With stepwise routing all the changes are localized.

 

I understand the appeal of onion routing--it is very easy to send messages through the message tree without modifying any code in the tree.  When you write a piece of functionality it has to be coupled to *something* for it to be useful.  Onion routing couples the functionality to the destination component and every component along the route.  I want to restrict the coupling to code that is nearby.  To achieve that, you need to use stepwise routing.

 

 

What diagramming software are you using Daklu?

 

yED.  It's not great, but it's free.

Link to comment

@Daklu.

 

I downloaded the lapdog and it looks like I was mistaken as to what it was (my fault for jumping in-apologies). From this and previous  conversations, I had somehow got into my head that it was a messaging system (kind of like the Actor Framework or Data Broadcasting Library). It looks, however, like it is a queue wrapper which is functionally identical to my queue.vi (but I don't bother with types).

 

@ AlexA

So I've taken the lapdog stuff, ignored all the types and written a cut-down version of my stringy messaging using the lapdog as the core rather than my queue.vi.(they are virtually interchangeable). The messaging itself is fairly topology agnostic (onion, chained, star etc) since it basically depends on how you put the strings together and how you disassemble them (just concatenate to onion route).

 

I cobbled together an example in light of your requirements to so you could see how I would put Lapdog to use for message forwarding accross TCPIP. From this point, it becomes the programmers preference as to what to do next (I, for example have a COMMS.vi instead of TCPIP.vi which uses the transport.lvlib to give me TCPIP, UDP, Bluetooth and websockets and the UI would communicate with an additional layer rather than directly so that sequencing and application state can be accounted for). The routing, mechanism, however, is there in it's entirety (you will see that VI names are used to provide unique queue name/message routes).

 

That's the easy stuff. :) The hard stuff is responses if they are required (for which I use events).. :lol:

 

(Hmmm. For some reason I cannot upload the example-something to do with the downtime today?

Here's a download link instead: Stringy Lapdog Example)

Edited by ShaunR
Link to comment
@Daklu.

I downloaded the lapdog and it looks like I was mistaken as to what it was (my fault for jumping in-apologies). From this and previous  conversations, I had somehow got into my head that it was a messaging system (kind of like the Actor Framework or Data Broadcasting Library). It looks, however, like it is a queue wrapper which is functionally identical to my queue.vi (but I don't bother with types).

 

No apology necessary.  I think there's a lot of value in showing both OO and non-OO ways to accomplish things.  (However, I admit to skipping your posts where you just rant about LVOOP.  :P )

 

You are correct that LapDog.Messaging is a very lightweight wrapper around queues.  I've always intended for it to be used as a base for building more complex systems, like the AF or DBL, with specific features each user needs.  Arguably, the only unique thing I did with LDM is in the Dequeue method where I converted timeouts and errors into messages, and even that isn't some radical departure from the norm.

 

 

(Hmmm. For some reason I cannot upload the example-something to do with the downtime today?

Here's a download link instead: Stringy Lapdog Example)

 

What?  I have to register?  Bleh...

Link to comment

My comment was directed at systems using stepwise routing, not onion routing.  You are correct the PrefixQueue overrides the Send method in the same way you are suggesting, but the use case is different.  I use the PrefixQueue to send messages from subactors up to managing actors so the managing actor can identify the sender.  The managing actor sets the prefix for the branch of its own input queue prior to instantiating the subactor and giving it the queue.  If you apply what you are describing to Alex's diagram, you are wrapping messages sent from the managing actor to the subactor--the reverse of what I do with the PrefixQueue.

The technique of overriding a “Send” method can be used in multiple different ways.  PrefixQueue might not be the most closely-related example.

 

Overriding Send to wrap all messages in a SendViaTCP message is functionally the same as not having a message handler in the TCP actor and automatically sending all the messages over the network.  The wrapping serves no purpose.  Furthermore, if you automatically forward all messages over the network you give up the ability to send messages to the TCP actor itself.  When you do want to send a message to the TCP actor, you have to put conditionals in the Send method to only wrap those messages that should be sent over the network.  Now your TCP actor has a MessageQueue subclass customized only for itself.

Well, as an example, here is the “Send” override method of my “RemoteTCPMessenger” class:

 

post-18176-0-92211500-1371247622_thumb.p

 

As you can see, RemoteTCPMessenger wraps and sends messages to a TCP Client Actor.  Other methods of RemoteTCPMessenger can send alternate messages to TCP Client to control it.  Could I send the TCP messages directly and skip the actor?  Well, in this case I have to route message replies and published event messages back through the TCP connection and thus need some process listening on that.  Once I have to have the client actor anyway, it is cleaner and simpler to let it handle all aspects of the TCP connection.  A TCP connection is too complex a thing to be left to a passive object.

Link to comment

@James

I read through what I assume was your presentation from the Euro CLA.  There are some things in there I really like and will probably incorporate into my own messaging systems.  One thing in particular I am leaning towards is a generalized MessageTransport class.  On the other hand, I also found it pretty confusing trying to understand it all just from the slides and some of the terminology is very odd to me.  For example, I assume Send.Send method is equivalent to MsgQueue.Enqueue?

 

 

 

As you can see, RemoteTCPMessenger wraps and sends messages to a TCP Client Actor.  Other methods of RemoteTCPMessenger can send alternate messages to TCP Client to control it.

 

RemoteTCPMessenger is the message transport for other actors to send messages to the RemoteTCP actor, correct?  And in addition to a Send method, which wraps the original message in a SendViaTCP message, you also have another method with a name something like 'SendButDontForward' if the message is intended for the RemoteTCP actor itself?

 

 

 

Could I send the TCP messages directly and skip the actor?... A TCP connection is too complex a thing to be left to a passive object.

 

I agree--a TCP connection is too complex to be left to a passive object.  You still want a TCP Send and TCP Receive loop, along with some way to monitor what they are doing.  My point was that if all your messages are automatically onioned in a SendViaTCP message by RemoteTCPMessenger.Send, you could accomplish the same thing by not onioning the message and instead feeding it directly from the sender to the TCP Send loop. 

 

Of course, if you do that then the RemoteTCP actor become 100% transparent, blindly forwarding all messages to the network, which you probably don't want.  So to enable sending messages intended for the RemoteTCP actor itself, you added a SendButDontForward message to the transport.  Now I not only have to make sure I'm sending the correct messages, but I have to make sure each message is using the correct 'Send' method depending on whether the message is stopping at the TCP actor or going across the network.  There are more details the developer needs to keep track of, the api for using the TCP actor is more complicated, and there are more opportunities to make mistakes.  What's the upside? 

 

If you'll forgive me for saying so, in my opinion the necessity of a SendButDontForward method is a code smell that points directly at the root problem.  Creating RemoteTCPMessenger and overriding the Send method to wrap the messages in a SendViaTCP message is a mistake.  I think it is more clear to either fully acknowledge the existence of the TCP actor by explicitly wrapping messages destined for the network client in a TCP.Send message on the same block diagram that is sending the message, or completely ignoring the TCP actor's existence by creating a proxy of the network client with an identical interface.  (The proxy would handle all the TCP details internally.)  Your mix of sort-of-acknowledging it and sort-of-ignoring it is confusing for me and my little brain.

Link to comment
 For example, I assume Send.Send method is equivalent to MsgQueue.Enqueue?

It would be Address.Send if I were doing it today.  “Send” is anything to which I can send a message.  It’s a bit confusing because it is more general than a communication method like a queue (such methods are under the subclass “Messenger”).

 

Of course, if you do that then the RemoteTCP actor become 100% transparent, blindly forwarding all messages to the network, which you probably don't want.  So to enable sending messages intended for the RemoteTCP actor itself, you added a SendButDontForward message to the transport.  Now I not only have to make sure I'm sending the correct messages, but I have to make sure each message is using the correct 'Send' method depending on whether the message is stopping at the TCP actor or going across the network.  There are more details the developer needs to keep track of, the api for using the TCP actor is more complicated, and there are more opportunities to make mistakes.  What's the upside? 

No, I’m actually going for 100% transparent TCP communication.  Having message-sending code by able to work with any transport method was the original motivation of my messaging system.   Whether that is really achievable with the intricacies of TCP I’m not sure, as I have not had a TCP project to work on in years.  But there is no “SendButDontForward” message.

 

If you'll forgive me for saying so, in my opinion the necessity of a SendButDontForward method is a code smell that points directly at the root problem.  Creating RemoteTCPMessenger and overriding the Send method to wrap the messages in a SendViaTCP message is a mistake.  I think it is more clear to either fully acknowledge the existence of the TCP actor by explicitly wrapping messages destined for the network client in a TCP.Send message on the same block diagram that is sending the message, or completely ignoring the TCP actor's existence by creating a proxy of the network client with an identical interface.  (The proxy would handle all the TCP details internally.)  Your mix of sort-of-acknowledging it and sort-of-ignoring it is confusing for me and my little brain.

Well, part of my philosophy is to have simple subcomponents whose messaging interaction is configured by higher-level components.   So the subcomponent still needs to be provided a simple “address” to “send” to, even if the higher-level component knows that “address” as a more complex object with extra methods.  

 

 

Edit: Forgot to add: RemoteTCPMessenger is intended to either BE a network proxy, or be the Messenger inside a network proxy.

Link to comment
What?  I have to register?  Bleh...

Well. That's not obvious since I can't find out how much I'm using and the error message is

"You can upload up to Uploading is not allowed of files (Max. single file size: 50MB)"

 

It was fine before the downtime yesterday and I've just deleted 2 of my CR submissions (>1 MB) and it still won't work (the example is only 75KB). So I don't think that is the problem (unless you are just intimating that I have to pay to help someone-bleh).

Edited by ShaunR
Link to comment

Shaun, I think Daklu is referring to the need to register on your site in order to download the example.

 

I just tried a test of attaching a VIPM package to this post and “This upload failed”, so perhaps the issue is with LAVA.

 

 

 

 

BTW, here is the presentation slides Daklu is referring to (it’s on the CLA group at NI.com, but that group is restricted):

 

 

 

CLA Summit 2013 Final.pptx

 

In hindsight, I think it was too technical; I should have focused more on the “what” then the “how”.  

Link to comment
Shaun, I think Daklu is referring to the need to register on your site in order to download the example.

Ah. right. (Sorry Daklu). I'll go and fix that in a bit

 

OK. Fixed. Don't have to register (I'm always logged in so didn't notice you had to).

Edited by ShaunR
Link to comment
OK. Fixed. Don't have to register.

 

Thanks Shaun.  It looks like you use a similar technique as the JKI state machine.  It's much easier for me to understand when I separate the message ID and payload.  Packing everything in a single string hurts my brain too much.

 

Do you use the vi name to name queues as a matter of convention?

 

 

 

But there is no “SendButDontForward” message.

 

Uh uh. A SendButDontForward method, not message.  Earlier you said, "Other methods of RemoteTCPMessenger can send alternate messages to TCP Client to control it."  If the RemoteTCPMessenger.Send method wraps all incoming messages in a SendViaTCP message so the TCP actor will automatically forward them through the network, RemoteTCPMessenger needs other methods to send messages to the TCP actor without wrapping it in SendViaTCP.  Either a general purpose RemoteTCPMessenger.SendButDontForward method or unique methods for each public call.  (RemoteTCPMessenger.SetPortNumber, RemoteTCPMessenger.Close, etc.)

 

 

 

Edit: Forgot to add: RemoteTCPMessenger is intended to either BE a network proxy, or be the Messenger inside a network proxy.

 

If this means what I said above about making the network layer either 100% visible or 100% invisible to your main app, then I agree.  I don't think overriding Send is the best way to get you there though.  (Your system inverts the message/transport dependency from what I'm used to, so I may not be fully understanding how the elements are used.)

Link to comment
Thanks Shaun.  It looks like you use a similar technique as the JKI state machine. 

 

I think it just looks like the JKI because it uses delimited strings and string cases. There is no state, the strings are hierarchic and atomic so it is much simpler. That is not to say you could not build a QSM style handler, but I highly recommend not to and instead think in terms of atomic functions associated with strings. I think it is more akin to SCPI in that it is hierarchical messages.

 

It's much easier for me to understand when I separate the message ID and payload.  Packing everything in a single string hurts my brain too much. 

 

If a single string is unintuitive, just add another [payload/data/DaklusStuff] terminal and concatenate inside the send. The advantage of a single string is that it's easier to document (scan diagrams and list messages) and create scripts. Although the former goes out the window when you start dynamically generating the messages.

 

Do you use the vi name to name queues as a matter of convention?

 

No. It's part of the messaging strategy and key to the routing. It allows you to modularise the code to effectively create an API messaging interface whose "address" (or target as I call it) is defined simply by naming the VI handler (it can be extended for clones too, but this is an example). It helps, of course, if the "target" describes the modules' capabilities (like DVM, FILE, DB etc) and that would be a "convention" I practice since it allows conversations such as:

FILE->LOAD->c:tempcfg.cfg

DVM->SET->VOLT->3.9

DB->QUERY->SELECT * FROM test;

Edited by ShaunR
Link to comment

@ShaunR Huh, that's really cool, I've never thought of attempting to script control of my VIs like that. Though, now that I think about it, it makes a heap of sense for testing everything. I wonder if you can use VI scripting to parse the list of cases in a case structure (just checked and you can). Cool, you could write some sort of automated tester that grabs all the message names a VI expects from the case structure Framenames, then trys to send them different messages.

 

I guess this is the point of making everything a string, but with LapDog I can't see how you'd programmatically infer what type of message should be arriving in any given case so it could be generated. I guess there might be a way to crawl one of the message libraries and try to just send everything in there... I dunno, just daydreaming now. 

 

@Daklu This is not really the right place to go query this, but I was just wondering why you didn't do the required casting for the various messages within each "Get XXX Message.vi"?

Link to comment
@ShaunR Huh, that's really cool, I've never thought of attempting to script control of my VIs like that. Though, now that I think about it, it makes a heap of sense for testing everything. I wonder if you can use VI scripting to parse the list of cases in a case structure (just checked and you can). Cool, you could write some sort of automated tester that grabs all the message names a VI expects from the case structure Framenames, then trys to send them different messages.

 

I guess this is the point of making everything a string, but with LapDog I can't see how you'd programmatically infer what type of message should be arriving in any given case so it could be generated. I guess there might be a way to crawl one of the message libraries and try to just send everything in there... I dunno, just daydreaming now. 

 

@Daklu This is not really the right place to go query this, but I was just wondering why you didn't do the required casting for the various messages within each "Get XXX Message.vi"?

 

Indeed. In fact, if you can put a file write in the send (i.e. save the message with a timestamp) you can load it back up and playback a recording. If you match the timestamp with an error log, you can replay everything the operator did to replicate an error ;)

 

I'm not sure what you mean by "infer" the message type. You "know" what the type is for each message payload (it's planned) so you "know" what to unflatten with.if it's non-stringy. It's no different from "knowing" what get message to place in each frame in the lapdog example but without having to have VIs for every labview type you are going to support. It's just data seralisation.

Edited by ShaunR
Link to comment
Earlier you said, "Other methods of RemoteTCPMessenger can send alternate messages to TCP Client to control it."  If the RemoteTCPMessenger.Send method wraps all incoming messages in a SendViaTCP message so the TCP actor will automatically forward them through the network, RemoteTCPMessenger needs other methods to send messages to the TCP actor without wrapping it in SendViaTCP.  Either a general purpose RemoteTCPMessenger.SendButDontForward method or unique methods for each public call.  (RemoteTCPMessenger.SetPortNumber, RemoteTCPMessenger.Close, etc.)

Well, the methods that send messages meant for the “TCP Client Actor” are dynamic-dispatch overrides of “Create” and “Destroy”.  The only extra API method that RemoteTCPMesenger adds to the standard Messenger API is “Remote Service”, which is called first to define the IP address and service name to connect to.

 

But I’ve lost the chain of thought.  Remember, I need RemoteTCPMessenger to work in an extensive body of code that works with the generic “Send” and “Messenger” classes, thus I need to have it work through a predefined simple API (Create, Send, etc.), not some new TCP-specific API.  Large parts of the codebase must be blind to the fact that it is using TCP.  If the internals of RemoteTCPMessenger need to be slightly unclear to achieve this, that is no big problem, as the user of the messaging package doesn’t need to know this internal detail.

 

If this means what I said above about making the network layer either 100% visible or 100% invisible to your main app, then I agree.  I don't think overriding Send is the best way to get you there though.  (Your system inverts the message/transport dependency from what I'm used to, so I may not be fully understanding how the elements are used.)

 

Could you expand further?  I send messages to an address, after someone has created the address; which I think is the same as how Lapdog does it.

 

Here, BTW, is an example I’m going to add to the next version:  A TCP client that communicates by request-reply with a server, and receives the messages back (for demonstration) in three different ways (by queue, User Event, or Notifier).  The only TCP-specific API method is the “Remote Service” VI called first.

post-18176-0-91388200-1371460733_thumb.p

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.




×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.