我找到了一份构建长拉式 TCP 套接字服务器作为设备服务器的工作。我开发的时候选择了Twisted。它适用于我的 Python 设备模拟器。然而,真实设备发送连接(或组合)的 TCP 数据包。我知道这在实际网络和设备中是正常的,尽管 TCP 数据包很短。
它有三个框架结构:
\xFDAA + "realtime_data" + \xCCDD (length is fixed at 150B)
\xFDCC + "extra_data" + \xCCDD (length is fixed at 190B)
\xFDCC + "extra_data" + \xCCDD (length is fixed at 192B)
很明显,\xFDAA\xFDCC是header,\xCCDD是EOT。所以他们确实有束缚。并且它们还隐含了固定长度,没有在协议(protocol)本身中定义。
但是,我不知道如何使用现有的 Twisted 方法处理自定义框架的串联数据包。在我的开发过程中,我使用了 dataReceiver。
到目前为止,我正在尝试解析数据包并将其存储在协议(protocol)工厂的缓冲区中。当每个新数据包到达时,我会将之前缓冲的数据与新数据组合起来进行解析(如果连接则合并,如果收到组合数据包则将它们分开......但这看起来很脏)。
我查看了 twistedmatrix.com 的常见问题解答。它推荐了以下解决方案:
LineReceiver (with \r\n ending chars)
NetstringReceiver (with callback for every string received)
Int8/16/32Receiver (with prefix length information)
然后还推荐使用 AMP 和 PB 高级消息传递。
我想听听 twisted 专家关于如何使用 twisted 官方实现它的任何建议。 URL/演示代码非常有用。
最佳答案
LineReceiver、NetstringReceiver、Int8/16/32Receiver的集合都没有,
AMP 或 PB 适用于您的问题,因为它们都是实现
特定的框架(在后两者的情况下,消息传递)协议(protocol)。
相反,您有一个要实现的自定义协议(protocol)。
幸运的是,这相对简单:Twisted 通过您的
IProtocol 实现的 dataReceived 方法。
处理这类事情的最好方法实际上是实现一个简单的
首先是功能,而不是担心它究竟是如何被插入的
进入扭曲。在您的情况下,您需要一个解析协议(protocol)的函数;
但是,由于 dataReceived 可能会向您发送部分数据包,因此您需要
确保该函数返回 2 个东西:解析后的数据,以及任何剩余的
缓冲。一旦你有了这样的功能,你就可以将它插入到 Protocol
子类化很容易。
您对协议(protocol)的解释不是很清楚,所以这可能不是很清楚 正确,但我将您对消息格式的描述解释为:
octet 0xFD
octet 0xAA
150 octets of "realtimeData"
octet 0xCC
octet 0xDD
octet 0xFD
octet 0xCC
190 octets of "extraData1"
octet 0xCC
octet 0xDD
octet 0xFD
octet 0xCC
192 octets of "extraData2"
octet 0xCC
octet 0xDD
换句话说,单个协议(protocol)消息的长度为 544 字节,并且包含 3 必须正确的字段和 12 个字节的填充。
所以让我们首先编写一个 Message 类来表示一 strip 有这些的消息
三个字段,使用标准库struct模块解析序列化
它的领域:
from struct import Struct
class Message(object):
format = Struct(
"!" # Network endian; always good form.
"2s" # FD AA
"150s" # realtimeData
"4s" # CC DD FD CC
"190s" # extra1
"4s" # CC DD FD CC
"192s" # extra2
"2s" # CC DD
)
def __init__(self, realtimeData, extra1, extra2):
self.realtimeData = realtimeData
self.extra1 = extra1
self.extra2 = extra2
def toBytes(self):
return self.format.pack(
b"\xFD\xAA", self.realtimeData, b"\xCC\xDD\xFD\xCC", self.extra1,
b"\xCC\xDD\xFD\xCC", self.extra2, b"\xCC\xDD"
)
@classmethod
def fromBytes(cls, octets):
[fdaa, realtimeData, ccddfdcc, extra1, ccddfdcc2, extra2,
ccdd] = cls.format.unpack(octets)
# verify message integrity
assert fdaa == b"\xFD\xAA"
assert ccddfdcc == b"\xCC\xDD\xFD\xCC"
assert ccddfdcc2 == b"\xCC\xDD\xFD\xCC"
assert ccdd == b"\xCC\xDD"
return cls(realtimeData, extra1, extra2)
@classmethod
def parseStream(cls, streamBytes):
sz = cls.format.size
messages = []
while len(streamBytes) >= sz:
messageData, streamBytes = streamBytes[:sz], streamBytes[sz:]
messages.append(cls.fromBytes(messageData))
return messages, streamBytes
这里与 Twisted 接口(interface)的重要部分是最后的
parseStream 方法,将一堆字节变成一堆消息,以及
尚未解析的剩余字节。然后我们可以有一个 Protocol
理解实际的网络流,如下所示:
from twisted.internet.protocol import Protocol
class MyProtocol(Protocol):
buffer = b""
def dataReceived(self, data):
messages, self.buffer = Message.parseStream(self.buffer + data)
for message in messages:
self.messageReceived(message)
def messageReceived(self, message):
"do something useful with a message"
与其调用 self.messageReceived,不如调用方法
self 的一些其他属性,或者可能将 Message 对象中继到
与此协议(protocol)关联的工厂。由你决定!既然你这么说
你想“解析数据包并将其存储在工厂的缓冲区中”,也许你
只想做 self.factory.messagesBuffer.append(message)。希望这个
看起来比你的“数据包连接”方法更干净,这不是
描述清楚足以让我理解你认为令人反感的地方
关于它。
关于python - 处理具有自定义帧结构的级联 TCP 流的扭曲协议(protocol)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33949409/
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano
我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>