我想运行一个每秒有大量请求的负载测试。我在 Go 中编写了一个套接字发送器和一个接收器。发送方向端口 7357 发送大量数据包,每个数据包都包含以纳秒为单位的当前时间。接收方在端口 7357 上监听并解析每条消息,计算延迟。
问题是在读取时我在一个 conn.Read() 中得到了多个数据包。我知道这意味着我实际上每个数据包发送多条消息:每个 conn.Write() 不发送套接字数据包,但它等待一段时间然后与下一个合并(或接下来的几个)在发送之前。
如何确保每个 conn.Write() 都作为单独的数据包通过套接字单独发送? 注意:我不想重新发明 TCP,我只想模拟来自多个外部实体的负载,每个实体发送一条消息。
我已经搜索了文档,但似乎没有 conn.Flush() 或类似内容。我试过使用缓冲编写器:
writer := bufio.NewWriter(conn)
...
bytes, err := writer.Write(message)
err = writer.Flush()
没有错误,但我仍然在接收端收到混合数据包。我也试过在每个 conn.Write() 之后做一个 0 字节的假 conn.Read(),但它也没有用。发送诸如 \r\n 之类的消息终止符似乎没有任何区别。最后,默认情况下禁用 Nagle 算法,但我调用了 tcp.SetNoDelay(true) 作为衡量标准。
在 Node.js 中,我设法在每个 socket.write() 之后使用 setImmediate() 来实现这个技巧: setImmediate()在继续之前等待所有 I/O 完成。我怎样才能在 Go 中执行相同的操作以便获得单独的数据包?
发送:
func main() {
conn, _ := net.Dial("tcp", ":7357")
defer conn.Close()
for {
timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
conn.Write([]byte(timestamp))
conn.Read(buff)
}
}
接收:
func main() {
listen, _ := net.Listen("tcp4", ":7357")
defer listen.Close()
for {
conn, _ := listen.Accept()
go handler(conn)
}
}
func handler(conn net.Conn) {
defer conn.Close()
var buf = make([]byte, 1024)
for {
conn.Read(buf)
data := string(buf[:n])
timestamp, _ := strconv.ParseInt(data, 10, 64)
elapsed := timestamp - time.Now().UnixNano()
log.Printf("Elapsed %v", elapsed)
}
}
为了易读性已删除错误处理,但在实际代码中对其进行了彻底检查。它在第一次运行 strconv.ParseInt() 时崩溃,并出现 value out of range 错误,因为它收到了很多合并的时间戳。
最佳答案
曾经有一条规则,在允许任何人编写任何使用 TCP 的代码之前,他们必须从内存中重复以下句子并解释其含义:“TCP 不是一种消息协议(protocol),它是一种不保留应用程序消息边界的可靠字节流协议(protocol)。”
除了您建议的解决方案根本无法通过 TCP 可靠地实现这一事实之外,它不是减少延迟的解决方案。如果网络不堪重负,使用更多数据包发送相同数据只会使延迟更糟。
TCP 是一种字节流协议(protocol)。它提供的服务是字节流。期间。
您似乎想要一个在 TCP 上工作的低延迟消息协议(protocol)。伟大的。设计并实现。
获得低延迟的主要技巧是使用应用程序级确认。 TCP ACK 标志将搭载在确认上,提供低延迟。
不要禁用 Nagling。只有当您无法设计出旨在首先与 TCP 一起使用的适当协议(protocol)时,才需要这种 hack。由于与您建议的解决方案相同的原因,它会在非理想条件下使延迟变得更糟,即使有可能,也是一个糟糕的主意。
但是您必须设计并实现消息协议(protocol)或使用现有协议(protocol)。您的代码期望 TCP(它不是消息协议(protocol))以某种方式向它传递消息。那是不会发生的,期间。
How can I make sure that each conn.Write() is sent individually through the socket as a separate packet? Note: I don't want to reinvent TCP, I just want to simulate the load from a number of external entities that send a message each.
即使你可以,那也不会如你所愿。即使它们以单独的数据包发送,也不能保证另一端的 read 不会合并。如果你想发送和接收消息,你需要一个 TCP 没有的消息协议(protocol)。
In Node.js I managed to do the trick with a setImmediate() after each socket.write(): setImmediate() waits for all I/O to finish before continuing. How can I do the same in Go so I get separate packets?
您可能已将其从“碰巧不起作用”更改为“当我尝试时碰巧起作用”。但由于我已经解释过的原因,你永远无法可靠地完成这项工作,你是在做傻事。
如果你想发送和接收消息,你需要精确定义“消息”是什么,并编写代码来发送和接收它们。没有可靠的捷径。 TCP 是一种字节流协议(protocol),句号。
如果您关心延迟和吞吐量,请设计一个优化的消息协议(protocol)以在 TCP 上分层以优化这些。不要禁用 Nagle,因为需要 Nagle 来防止病理行为。只有当您无法更改协议(protocol)并且坚持使用并非设计在 TCP 之上的协议(protocol)时,才应禁用它。禁用 Nagle 会把您的一只手绑在背后,并在糟糕的网络条件下通过增加发送数据所需的数据包数量而导致延迟和吞吐量显着下降,即使这没有任何意义。
您可能想要/需要应用程序级别的确认。这与 TCP 配合得很好,因为 TCP ACK 将搭载在应用程序级确认上。
关于sockets - 如何为 Go 中写入的每个连接发送单独的数据包?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46728989/
我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我刚刚为fedora安装了emacs。我想用emacs编写ruby。为ruby提供代码提示、代码完成类型功能所需的工具、扩展是什么? 最佳答案 ruby-mode已经包含在Emacs23之后的版本中。不过,它也可以通过ELPA获得。您可能感兴趣的其他一些事情是集成RVM、feature-mode(Cucumber)、rspec-mode、ruby-electric、inf-ruby、rinari(用于Rails)等。这是我当前用于Ruby开发的Emacs配置:https://github.com/citizen428/emacs
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送
我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
我的工作要求我为某些测试自动生成电子邮件。我一直在四处寻找,但未能找到可以快速实现的合理解决方案。它需要在outlook而不是其他邮件服务器中,因为我们有一些奇怪的身份验证规则,我们需要保存草稿而不是仅仅发送邮件的选项。显然win32ole可以做到这一点,但我找不到任何相当简单的例子。 最佳答案 假设存储了Outlook凭据并且您设置为自动登录到Outlook,WIN32OLE可以很好地完成此操作:require'win32ole'outlook=WIN32OLE.new('Outlook.Application')message=
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit