基于命令的协议解析器中每个命令的唯一类?
我正在用 C# 编写 MSN Messenger 客户端,并选择为 MSNP 协议编写自己的解析器,因为我查看了其他客户端的源代码,但发现代码不符合我通常的标准 --特别是对线程同步的思考非常缺乏。
首先,我编写了一个通用解析器,它接受“规则”,告诉它如何解析命令。
例如,我设置了一条规则,规定命令代码“VER”具有事务 ID 和参数列表。
这很有效,但它始终是一个临时解决方案。我的目的是制作一个成熟的解析器,它单独查看每个命令和参数。
例如
,如果命令代码是“VER”,则创建一个 VersionCommand 类,向其传递事务 ID 以及接受的协议列表。
那么我的代码可以轻松地解释命令,而不会弄乱参数索引等(verCmd.TrId & verCmd.AcceptedProtocols)
我担心的是,为每种命令类型使用单独的类会浪费资源。
所以我的问题是——这是否浪费?是否有其他基于命令的协议实现采用类似的方法?我想做的事情有先例吗,还是一个愚蠢的想法?
I'm writing a MSN Messenger client in C# and have opted to write my own parser for the MSNP protocol because I've looked at the source of other clients and I don't find the code to be up to my usual standard -- in particular a great lack of thought has been given to thread synchronization.
At first, I had written a generic parser that accepts "rules" which tell it how to parse commands.
For example, I set up a rule which dictates that the command code "VER" has a transaction id, and a list of arguments.
This worked ok, but it had always been an interim solution. My intention had been to make a fully fledged parser which looked at each command and argument individually.
For example
if command code is "VER" then create a VersionCommand class, passing it the transaction id along with the list of accepted protocols.
then my code can easily interpret the command without messing with parameter indexes and such (verCmd.TrId & verCmd.AcceptedProtocols)
My concern is that it's wasteful of resources to use a separate class for each command type.
So my question is - is it wasteful? are there any other command based protocol implementations which take a similar approach? is there any precedent for what i want to do, or is it a moronic idea?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
你所提议的并不是浪费;相反,您只是在“功能丰富”和“简单”(关于界面和解析)之间进行权衡。
我们已经完成了您建议的很多工作。。关键问题:我可以让这个变得简单吗(例如,像平面解析“跳转表”),或者我的解析需求和实现是否需要基础设施来允许未来特定
于 应用程序的扩展?回答这个问题,我们已经做了很多,很多:
如果“否”,你有一个离散的(长)(平面)解析列表,你“尝试” ”来解析一个命令(及其参数),失败,然后继续下一次尝试,等等,直到您放弃了所有二十个(或一些数量)“测试”的命令。 好处:扁平、简单,每个命令都可以有自己的自定义参数(因为每次解析尝试都可以验证特定于该命令的参数)。这并不要求您为每个命令都有一个类(但如果您愿意的话也可以)。例如,您可以有一个单个
MyCommand
类,它尝试以二十种不同的方式解析自身,以暗示具有不同参数的二十种不同的枚举命令类型。如果“是”,那么您正在投资一个框架。通常,这是为了获得一个可以以特定于应用程序的方式扩展的“引擎”。在我们的例子中,它还倾向于反映命令的几个层次结构,其中每个层次结构都可以以特定于应用程序的方式“扩展”命令。而且,因为这些是单独的层次结构,所以我们在重用状态和逻辑(不同层次结构具有公共基类)方面获得了巨大的好处。在这种情况下,每个层次结构的“基础”“嗅探”命令,如果匹配,则找出派生最多的实例中的哪个应该执行解析和实例化。这极大简化了解析,因为不同的层次结构有不同的数据处理需求(并且该代码是在基础中建立的),并且您没有单一的解析器。通常,我们为每种命令类型都有一个派生类,并具有自己的自定义参数要求。这些派生类按“层次结构”分组,这些层次结构可能(也可能不)共享公共基类(例如,“树”或“森林”模型)。
如果您希望您的协议相对有界/不变,具有一致的命令参数和类型,那么“扁平”效果很好。如果您想要特定于应用程序的可扩展性,请继续投资每类类型一个命令的基础架构 - 在初始实现的“脚步”之后,它效果很好,特别是当您后来意识到参数不正确并且您需要改变实施(这种情况经常发生)。使用每类一个命令(其中还包含特定于命令的解析,而不是超级怪物大师解析器)可以更容易地做到这一点,尽管我承认这有很多更多代码来使基础设施到位。
What you propose is not wasteful; rather, you're merely suffering the trade-off between "feature rich" and "simple" (regarding the interface and the parsing).
We've done what you propose a lot. The pivotal question: Can I make this simple (e.g., like a flat parsing "jump table"), or are my parsing demands and implementation requiring an infrastructure to permit future application-specific extension?
Based on the answer to the question, we've done both, a lot:
If "no", you have a discrete (long) list of (flat) parsing where you "attempt" to parse a command (with its parameters), fail, and then drop through to the next attempt, etc., until you've dropped through all twenty (or some number) of the commands that are "tested". Benefit: Flat, simple, each command can have its own custom parameters (because each parse attempt can validate the parameters specific to that command). This does not require you to have a class for every command (but you can if you want). For example, you could have a single
MyCommand
class, which attempts to parse itself in twenty different ways to imply twenty different enumerated command types with different parameters.If "yes", you are investing in a framework. Typically, this is to get an "engine" that can be extended in an application-specific manner. In our case, it also tends to reflect several hierarchies of commands, where each hierarchy can be "extended" for commands in application-specific ways. And, because these are separate hierarchies, we get great benefits in re-used state and logic (with common base classes for the different hierarchies). In this case, the "base" of each hierarchy "sniffs" the command, and if it matches, figures out which of the derived-most instances should perform the parsing-and-instantiation. This dramatically simplifies parsing, because you have different data handling needs for different hierarchies (and that code is established in the base), and you don't have one-monster-parser. Typically, we have a derived class for each command type, with its own custom parameter requirements. These derived classes are grouped in "hierarchies", which may (or may not) share a common base class (e.g., "tree" or "forest" model).
If you expect your protocol to be relatively bounded/unchanged, with consistent command parameters and types, "flat" works great. If you want application-specific extensibility, go ahead and invest in the one-command-per-class-type infrastructure -- after the "footwork" for initial implementation, it works GREAT, especially when you later realize your parameters are incorrect and you need to change implementation (which happens all the time). This is much easier to do with one-command-per-class (which also contains your command-specific parsing, rather than a super-monster-master-parser), although I concede it was a lot more code to get that infrastructure in place.