我遇到了一个不寻常的问题。我有一个 C++ Boost.ASIO 网络服务器,为了处理传入的请求,我正在使用以下代码:
boost::asio::async_read_until(
socket_,
response_,
"\r\n\r\n",
boost::bind(
&connection::handle_read_headers,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
);
(其中“socket_”是我的 boost::asio::ip::tcp::socket,“response_”是 boost::asio::streambuf)
我试图只获取请求的 header ,然后我执行第二个 async_read_until,transfer_exactly 匹配从请求 header 解析的“Content-Length”。问题是上面的代码需要 100-900 毫秒才能在非常现代的服务器上返回(从那个读取 block ,直到调用 handle_read_headers())。传入请求如下所示:
POST /load HTTP/1.1
host: www.mysite.com
Accept: */*
Accept-Encoding: gzip,deflate
Content-type: application/x-www-form-urlencoded
From: googlebot(at)googlebot.com
Origin: http://www.mysite.com
Referer: http://www.mysite.com/another-page/
User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
X-Forwarded-For: 66.249.75.103
X-Forwarded-Port: 80
X-Forwarded-Proto: http
Content-Length: 287
Connection: keep-alive
and-the-actual-content-is-here.... (287 bytes worth)
header 似乎以\r\n\r\n 结尾,它确实在一直读取到 EOF 之前触发了 handle_read_headers() 函数(因此它没有读取整个页面)——它实际上正在跳闸正则表达式。这些请求来自 Google,因此我非常有信心他们不会延迟。
关于为什么需要这么长时间才能返回,有什么我可以忽略的吗?我可能错过了 aync_read_until 的任何其他捕获?
谢谢!
编辑/更新: 好吧,现在我很困惑。在尝试 megabyte 的建议时,我从 streambuf 切换到字符数组(运气不好),然后我重构了我的代码以使用 async_read_some 而不是 async_read_until,并且只是手动扫描分隔符。我还将所有操作系统变量 (sysctrl.conf) 重置为默认值(以缩小可能性)。不幸的是,我仍然看到以下代码使用相同的传入 POST 请求调用 handle_read() 时有 100-900 毫秒的延迟:
socket_.async_read_some(
boost::asio::buffer(response_),
boost::bind(
&connection::handle_read,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
);
response_ 现在在哪里:
boost::array<char, 4096> response_;
无济于事(同样的 100-900 毫秒延迟)。这不可能是正常的——有什么想法吗?
编辑2: 根据 Rhashimoto 的建议,我启用了处理程序跟踪并在日志中发现了这个奇怪的地方:
[2013-07-05 15:58:39 - Thread 7fae57e3f700]: Incoming connection (0ms elapsed)
@asio|1373054319.874916|506*508|socket@0x7fae50004f98.async_receive
@asio|1373054319.874963|506*509|socket@0x7fffd40fed68.async_accept
@asio|1373054319.875008|<506|
@asio|1373054320.609088|>508|ec=system:0,bytes_transferred=512
@asio|1373054320.609233|508*510|socket@0x7fae50004f98.async_receive
@asio|1373054320.609264|<508|
@asio|1373054320.609284|>510|ec=system:0,bytes_transferred=404
[2013-07-05 15:58:40 - Thread 7fae57e3f700]: Received packet headers (638 bytes) - 734ms elapsed
async_accept 和 async_receive 之间有超过 700 毫秒的间隔。在代码中,它来自此 block (实际上直接来自 http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/examples/cpp03_examples.html 的“HTTP 服务器 2”- server.cpp 和 connection.cpp):
new_connection_->start();
new_connection_.reset(new connection(
io_service_pool_.get_io_service()
));
acceptor_.async_accept(
new_connection_->socket(),
boost::bind(
&server::handle_accept,
this,
boost::asio::placeholders::error
)
);
从 start() 到:
void connection::start()
{
boost::asio::async_read_until(
socket_,
response_,
"\r\n\r\n",
boost::bind(
&connection::handle_read_headers,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
);
}
当调用 handle_read_headers() 时,已经过了 700 毫秒。
有人有什么想法吗?我完全迷路了。
非常感谢!
最佳答案
让我们看看处理程序日志
[2013-07-05 15:58:39 - Thread 7fae57e3f700]: Incoming connection (0ms elapsed)
@asio|1373054319.874916|506*508|socket@0x7fae50004f98.async_receive
@asio|1373054319.874963|506*509|socket@0x7fffd40fed68.async_accept
@asio|1373054319.875008|<506|
@asio|1373054320.609088|>508|ec=system:0,bytes_transferred=512
@asio|1373054320.609233|508*510|socket@0x7fae50004f98.async_receive
@asio|1373054320.609264|<508|
@asio|1373054320.609284|>510|ec=system:0,bytes_transferred=404
[2013-07-05 15:58:40 - Thread 7fae57e3f700]: Received packet headers (638 bytes) - 734ms elapsed
从日志中我们可以看到 async_receive 被调用了两次:第一次被调用(#508)在处理程序设置(#506)之后的 734 毫秒。现在,第二个 async_receive 在处理程序设置 (#508) 后 53 微秒被调用 (#510)。就是这样,第二个处理程序调用的速度非常快,因为数据(那 404 个字节)已经在 TCP 堆栈中准备好了。
结论:这不是处理程序调用延迟,而是传输延迟。可能是 ISP 或平衡器出了问题,或者 Google 真的不想用请求和设置延迟来打扰您。
UPD:我想你可以用 tcpdump
附言我不喜欢 HTTP 服务器 2 示例中的 io_service_pool_ 实现。这也会导致一些问题,但我认为这不是当前的情况。
关于C++ Boost.ASIO async_read_until 慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17478230/
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
CSV.open(name,"r").eachdo|row|putsrowend我得到以下错误:CSV::MalformedCSVErrorUnquotedfieldsdonotallow\ror\n文件名是一个.txt制表符分隔文件。我是专门做的。我有一个.csv文件,我转到excel,并将文件保存为.txt制表符分隔的文件。所以它是制表符分隔的。CSV.open不应该能够读取制表符分隔的文件吗? 最佳答案 尝试像这样指定字段分隔符:CSV.open("name","r",{:col_sep=>"\t"}).eachdo|row|
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
我在我正在处理的一些代码中发现了这一点。它旨在解决从磁盘读取key文件的要求。在生产环境中,key文件的内容位于环境变量中。旧代码:key=File.read('path/to/key.pem')新代码:key=File.read('|echo$KEY_VARIABLE')这是如何工作的? 最佳答案 来自IOdocs:Astringstartingwith“|”indicatesasubprocess.Theremainderofthestringfollowingthe“|”isinvokedasaprocesswithappro
我有这个代码File.open(file_name,'r'){|file|file.read}但是Rubocop发出警告:Offenses:Style/SymbolProc:Pass&:readasargumenttoopeninsteadofablock.你是怎么做到的? 最佳答案 我刚刚创建了一个名为“t.txt”的文件,其中包含“Hello,World\n”。我们可以按如下方式阅读。File.open('t.txt','r',&:read)#=>"Hello,World\n"顺便说一下,由于第二个参数的默认值是'r',所以这样
我有以下代码,它下载一个文件,然后将文件的内容读入一个变量。使用该变量,它执行一个命令。这个配方不会收敛,因为/root/foo在编译阶段不存在。我可以通过多个聚合和一个来解决这个问题ifFile.exist但我想用一个收敛来完成它。关于如何做到这一点有什么想法吗?execute'download_joiner'docommand"awss3cps3://bucket/foo/root/foo"not_if{::File.exist?('/root/foo')}endpassword=::File.read('/root/foo').chompexecute'join_domain'd
我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“
有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=
出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t