??xml version="1.0" encoding="utf-8" standalone="yes"?>国职业棒球比分:BlogJava-庄周梦蝶-随笔分类 - 棒球比分大小怎么算|վ//www.355548.live/killme2008/category/37396.html生活、程序、未?/description>zh-cnThu, 17 Nov 2011 13:44:56 GMTThu, 17 Nov 2011 13:44:56 GMT60演示TCP慢启动和滑动H口机制的动?/title><link>//www.355548.live/killme2008/archive/2011/11/16/363913.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 15 Nov 2011 23:34:00 GMT</pubDate><guid>//www.355548.live/killme2008/archive/2011/11/16/363913.html</guid><wfw:comment>//www.355548.live/killme2008/comments/363913.html</wfw:comment><comments>//www.355548.live/killme2008/archive/2011/11/16/363913.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>//www.355548.live/killme2008/comments/commentRss/363913.html</wfw:commentRss><trackback:ping>//www.355548.live/killme2008/services/trackbacks/363913.html</trackback:ping><description><![CDATA[今天看到的一个演CTCP慢启动和滑动H口机制的动画,很Ş?br /> <a target="_blank">osischool.com</a><br /> <embed type="application/x-shockwave-flash" width="620" height="400" src="//www.355548.live/Files/killme2008/tcp_slow_start.zip"></embed><img src ="//www.355548.live/killme2008/aggbug/363913.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.355548.live/killme2008/" target="_blank">dennis</a> 2011-11-16 07:34 <a href="//www.355548.live/killme2008/archive/2011/11/16/363913.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>|络~程中Nagle法和Delayed ACK的测?/title><link>//www.355548.live/killme2008/archive/2011/06/30/353441.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 30 Jun 2011 08:01:00 GMT</pubDate><guid>//www.355548.live/killme2008/archive/2011/06/30/353441.html</guid><wfw:comment>//www.355548.live/killme2008/comments/353441.html</wfw:comment><comments>//www.355548.live/killme2008/archive/2011/06/30/353441.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>//www.355548.live/killme2008/comments/commentRss/353441.html</wfw:commentRss><trackback:ping>//www.355548.live/killme2008/services/trackbacks/353441.html</trackback:ping><description><![CDATA[<br />    <a >Nagle法</a>的立意是良好的,避免|络中充塞小包Q提高网l的利用率。但是当Nagle法遇到<a >delayed ACK</a>悲剧发生了。Delayed ACK的本意也是ؓ了提高TCP性能Q跟应答数据捎带上ACKQ同旉?a >p涂H口l合?/a>Q也可以一个ack认多个D|节省开销?br />    悲剧发生在这U情况,假设一端发送数据ƈ{待另一端应{,协议上分为头部和数据Q发送的时候不q地选择了write-writeQ然后再readQ也是先发送头部,再发送数据,最后等待应{。发送端的伪代码是这?br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />//www.CodeHighlighter.com/<br /><br />--><span style="color: #000000;">write(head);<br />write(body);<br />read(response);</span></div><br />接收端的处理代码cMq样Q?br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />//www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">read(request);<br />process(request);<br />write(response);</span></div><br />   q里假设head和body都比较小Q当默认启用nagle法Qƈ且是W一ơ发送的时候,Ҏnagle法Q第一个段head可以立即发送,因ؓ没有{待认的段Q接收端收到headQ但是包不完_l箋{待body辑ֈqgqACKQ发送端l箋写入bodyQ这时候nagle法起作用了Q因为headq没有被ACKQ所以body要gq发送。这造成了发送端和接收端都在{待Ҏ发送数据的现象Q发送端{待接收端ACK head以便l箋发送bodyQ而接收端在等待发送方发送bodyqgqACKQ悲剧的无以a语。这U时候只有等待一端超时ƈ发送数据才能l往下走?br /><br />   正因为nagle法和delayed ack的媄响,再加上这Uwrite-write-read的编E方式造成了很多网贴在讨论Z么自己写的网l程序性能那么差。然后很多h会在帖子里徏议禁用Nagle法吧,讄TCP_NODELAY为true卛_用nagle法。但是这真的是解决问题的唯一办法和最好办法吗Q?br /><br />   其实问题不是出在nagle法w上的,问题是出在write-write-readq种应用~程上。禁用nagle法可以暂时解决问题Q但是禁用nagle法也带来很大坏处,|络中充塞着封包,|络的利用率上不去,在极端情况下Q大量小包D|络拥塞甚至崩溃。因此,能不止q是不禁止的好,后面我们会说下什么情况下才需要禁用nagle法。对大多数应用来_一般都是连l的h——应答模型Q有h同时有应{,那么h包的ACK其实可以延迟到跟响应一起发送,在这U情况下Q其实你只要避免write-write-read形式的调用就可以避免延迟现象Q利用writev做聚集写或者将head和body一起写Q然后再readQ变成write-read-write-read的Ş式来调用Q就无需用nagle法也可以做C延迟?br /><br />   writev是系l调用,在Java里是用到<a >GatheringByteChannel</a>.write(ByteBuffer[] srcs, int offset, int length)Ҏ来做聚集写。这里可能还有一点值的提下Q很多同学看java nio框架几乎都不用这个writev调用Q这是有原因的。主要是因ؓJava的write本n对ByteBuffer有做临时~存Q而writev没有做缓存,D试来看write反而比writev更高效,因此通常会更推荐用户head和body攑ֈ同一个Buffer里来避免调用writev?br /><br />   下面我们做个实际的代码试来结束讨论。这个例子很单,客户端发送一行数据到服务器,服务器简单地这行数据返回。客L发送的时候可以选择分两ơ发Q还是一ơ发送。分两次发就是write-write-readQ一ơ发是write-read-write-readQ可以看看两UŞ式下延迟的差异?strong>注意Q在windows上测试下面的代码Q客L和服务器必须分在两台机器上,gwinsock对loopbackq接的处理不一栗?/strong><br /><br />    服务器源码:<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />//www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">package</span><span style="color: #000000; "> net.fnil.nagle;<br /><br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.io.BufferedReader;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.io.InputStream;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.io.InputStreamReader;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.io.OutputStream;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.net.InetSocketAddress;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.net.ServerSocket;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.net.Socket;<br /><br /><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">class</span><span style="color: #000000; "> Server {<br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">static</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">void</span><span style="color: #000000; "> main(String[] args) </span><span style="color: #0000FF; ">throws</span><span style="color: #000000; "> Exception {<br />        ServerSocket serverSocket </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> ServerSocket();<br />        serverSocket.bind(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> InetSocketAddress(</span><span style="color: #000000; ">8000</span><span style="color: #000000; ">));<br />        System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Server startup at 8000</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />        </span><span style="color: #0000FF; ">for</span><span style="color: #000000; "> (;;) {<br />            Socket socket </span><span style="color: #000000; ">=</span><span style="color: #000000; "> serverSocket.accept();<br />            InputStream in </span><span style="color: #000000; ">=</span><span style="color: #000000; "> socket.getInputStream();<br />            OutputStream out </span><span style="color: #000000; ">=</span><span style="color: #000000; "> socket.getOutputStream();<br /><br />            </span><span style="color: #0000FF; ">while</span><span style="color: #000000; "> (</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">) {<br />                </span><span style="color: #0000FF; ">try</span><span style="color: #000000; "> {<br />                    BufferedReader reader </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> BufferedReader(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> InputStreamReader(in));<br />                    String line </span><span style="color: #000000; ">=</span><span style="color: #000000; "> reader.readLine();<br />                    out.write((line </span><span style="color: #000000; ">+</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">\r\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">).getBytes());<br />                }<br />                </span><span style="color: #0000FF; ">catch</span><span style="color: #000000; "> (Exception e) {<br />                    </span><span style="color: #0000FF; ">break</span><span style="color: #000000; ">;<br />                }<br />            }<br />        }<br />    }<br />}<br /></span></div><br />服务端绑定到本地8000端口Qƈ监听q接Q连上来的时候就dd一行数据,q将数据q回l客L?br /><br />客户端代码:<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />//www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">package</span><span style="color: #000000; "> net.fnil.nagle;<br /><br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.io.BufferedReader;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.io.InputStream;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.io.InputStreamReader;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.io.OutputStream;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.net.InetSocketAddress;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; "> java.net.Socket;<br /><br /><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">class</span><span style="color: #000000; "> Client {<br /><br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">static</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">void</span><span style="color: #000000; "> main(String[] args) </span><span style="color: #0000FF; ">throws</span><span style="color: #000000; "> Exception {<br />        </span><span style="color: #008000; ">//</span><span style="color: #008000; "> 是否分开写head和body</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">        </span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; "> writeSplit </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">false</span><span style="color: #000000; ">;<br />        String host </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">localhost</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;<br />        </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> (args.length </span><span style="color: #000000; ">>=</span><span style="color: #000000; "> </span><span style="color: #000000; ">1</span><span style="color: #000000; ">) {<br />            host </span><span style="color: #000000; ">=</span><span style="color: #000000; "> args[</span><span style="color: #000000; ">0</span><span style="color: #000000; ">];<br />        }<br />        </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> (args.length </span><span style="color: #000000; ">>=</span><span style="color: #000000; "> </span><span style="color: #000000; ">2</span><span style="color: #000000; ">) {<br />            writeSplit </span><span style="color: #000000; ">=</span><span style="color: #000000; "> Boolean.valueOf(args[</span><span style="color: #000000; ">1</span><span style="color: #000000; ">]);<br />        }<br /><br />        System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">WriteSplit:</span><span style="color: #000000; ">"</span><span style="color: #000000; "> </span><span style="color: #000000; ">+</span><span style="color: #000000; "> writeSplit);<br /><br />        Socket socket </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> Socket();<br /><br />        socket.connect(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> InetSocketAddress(host, </span><span style="color: #000000; ">8000</span><span style="color: #000000; ">));<br />        InputStream in </span><span style="color: #000000; ">=</span><span style="color: #000000; "> socket.getInputStream();<br />        OutputStream out </span><span style="color: #000000; ">=</span><span style="color: #000000; "> socket.getOutputStream();<br /><br />        BufferedReader reader </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> BufferedReader(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> InputStreamReader(in));<br /><br />        String head </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">hello </span><span style="color: #000000; ">"</span><span style="color: #000000; ">;<br />        String body </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">world\r\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;<br />        </span><span style="color: #0000FF; ">for</span><span style="color: #000000; "> (</span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> i </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">0</span><span style="color: #000000; ">; i </span><span style="color: #000000; "><</span><span style="color: #000000; "> </span><span style="color: #000000; ">10</span><span style="color: #000000; ">; i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">) {<br />            </span><span style="color: #0000FF; ">long</span><span style="color: #000000; "> label </span><span style="color: #000000; ">=</span><span style="color: #000000; "> System.currentTimeMillis();<br />            </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> (writeSplit) {<br />                out.write(head.getBytes());<br />                out.write(body.getBytes());<br />            }<br />            </span><span style="color: #0000FF; ">else</span><span style="color: #000000; "> {<br />                out.write((head </span><span style="color: #000000; ">+</span><span style="color: #000000; "> body).getBytes());<br />            }<br />            String line </span><span style="color: #000000; ">=</span><span style="color: #000000; "> reader.readLine();<br />            System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">RTT:</span><span style="color: #000000; ">"</span><span style="color: #000000; "> </span><span style="color: #000000; ">+</span><span style="color: #000000; "> (System.currentTimeMillis() </span><span style="color: #000000; ">-</span><span style="color: #000000; "> label) </span><span style="color: #000000; ">+</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; "> ,receive:</span><span style="color: #000000; ">"</span><span style="color: #000000; "> </span><span style="color: #000000; ">+</span><span style="color: #000000; "> line);<br />        }<br />        in.close();<br />        out.close();<br />        socket.close();<br />    }<br /><br />}<br /></span></div><br /><br />   客户端通过一个writeSplit变量来控制是否分开写head和bodyQ如果ؓtrueQ则先写head再写bodyQ否则将head加上body一ơ写入。客L的逻辑也很单,q上服务器,发送一行,{待应答q打印RTTQ@?0ơ最后关闭连接?br /><br />   首先Q我们将writeSplit讄为trueQ也是分两ơ写入一行,在我本机试的结果,我的机器是ubuntu 11.10Q?br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />//www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">WriteSplit:</span><span style="color: #0000FF; ">true</span><span style="color: #000000; "><br />RTT:</span><span style="color: #000000; ">8</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">40</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">40</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">40</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">39</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">40</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">40</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">40</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">40</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">40</span><span style="color: #000000; "> ,receive:hello world<br /></span></div><br />    可以看到Q每ơ请求到应答的时间间隔都?0msQ除了第一ơ。linux的delayed ack?0msQ而不是原来以为的200ms。第一ơ立即ACKQ似乎跟linux的quickack mode有关Q这里我不是特别清楚Q有比较清楚的同学请指教?br /><br />     接下来,我们q是writeSplit讄为trueQ但是客L用nagle法Q也是客户端代码在connect之前加上一行:<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />//www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">        Socket socket </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> Socket();<br />        socket.setTcpNoDelay(</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">);<br />        socket.connect(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> InetSocketAddress(host, </span><span style="color: #000000; ">8000</span><span style="color: #000000; ">));</span></div><br />    再跑下测试:<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />//www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">WriteSplit:</span><span style="color: #0000FF; ">true</span><span style="color: #000000; "><br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">1</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br /></span></div><br />   q时候就正常多了Q大部分RTT旉都在1毫秒以下。果然禁用Nagle法可以解决延迟问题?br />   如果我们不禁用nagle法Q而将writeSplit讄为falseQ也是head和body一ơ写入,再次q行试Q记的将setTcpNoDelayq行删除Q:<br /><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />//www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">WriteSplit:</span><span style="color: #0000FF; ">false</span><span style="color: #000000; "><br />RTT:</span><span style="color: #000000; ">7</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">1</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000;"> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br />RTT:</span><span style="color: #000000; ">0</span><span style="color: #000000; "> ,receive:hello world<br /></span></div><br />   l果跟禁用nagle法的效果类伹{既然这P我们q有什么理׃定要用nagle法呢?通过我在<a >xmemcached</a>的压中的测试,启用nagle法在小数据的存取上甚至有一定的效率优势Qmemcached协议本n是个连l的h应答的模型。上面的试如果在windows上跑Q会发现RTT最大会?00ms以上Q可见winsock的delayed ack时?00ms?br /><br />   最后一个问题,什么情况下才应该禁用nagle法Q当你的应用不是q种q箋的请?#8212;—应答模型Q而是需要实时地单向发送很多小数据的时候或者请求是有间隔的Q则应该用nagle法来提高响应性。一个最明显是例子是telnet应用Q你L希望敲入一行数据后能立卛_送给服务器,然后马上看到应答Q而不是说我要q箋敲入很多命o或者等?00ms才能看到应答?br /><br />   上面是我对nagle法和delayed ack的理解和试Q有错误的地方请不吝赐教?br /><br />   转蝲h明出处:<a id="Editor_Edit_hlEntryLink" title="view: Nagle法和Delayed ACK的一个测? href="../archive/2011/06/30/353441.html" target="_blank">//www.355548.live/killme2008/archive/2011/06/30/353441.html</a><br />   <br />  <img src ="//www.355548.live/killme2008/aggbug/353441.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.355548.live/killme2008/" target="_blank">dennis</a> 2011-06-30 16:01 <a href="//www.355548.live/killme2008/archive/2011/06/30/353441.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java NIO~程的技巧和陷阱 - 棒球比分大小怎么算|վ//www.355548.live/killme2008/archive/2011/06/30/353422.htmldennisdennisThu, 30 Jun 2011 03:07:00 GMT//www.355548.live/killme2008/archive/2011/06/30/353422.html//www.355548.live/killme2008/comments/353422.html//www.355548.live/killme2008/archive/2011/06/30/353422.html#Feedback0//www.355548.live/killme2008/comments/commentRss/353422.html//www.355548.live/killme2008/services/trackbacks/353422.html d做的分nQ一直上传slidesharep|Q今天又试了下,成功了。这个主题主要介lJava NIO~程的技巧和陷阱Q解M一些NIO框架的源码,以及~写高性能NIO|络框架所需要注意的技巧和~陷。关注这斚w的朋友可以看一下。去q写了篇blog提供了pdf版本的下载,?a href="//www.355548.live/killme2008/archive/2010/11/22/338420.html">q里?br />


dennis 2011-06-30 11:07 发表评论
]]>
Unix domain socket和memcached - 棒球比分大小怎么算|վ//www.355548.live/killme2008/archive/2009/10/15/298301.htmldennisdennisWed, 14 Oct 2009 22:12:00 GMT//www.355548.live/killme2008/archive/2009/10/15/298301.html//www.355548.live/killme2008/comments/298301.html//www.355548.live/killme2008/archive/2009/10/15/298301.html#Feedback0//www.355548.live/killme2008/comments/commentRss/298301.html//www.355548.live/killme2008/services/trackbacks/298301.html 1Q在同一L上,unix domain socket比一般的tcp socket快上一倍,性能因素q是一个主要原因?br /> 2Qunix domain socket可以在同一L的不同进E之间传递文件描q符
3Q较新的unix domain socket实现把客LID和组ID提供l服务器Q可以让服务器作安全查?br />
   memcached的FAQ中也提到Z安全验证Q可以考虑让memcached监听unix domain socket。Memcached支持q一点,可以通过-s选项指定unix domain socket的\径名Q注意,Z可移植性,量使用l对路径Q因为Posix标准声称lunix domain socketl定相对路径导致不可预计的后果Q我在linux的测试是可以使用相对路径。假设我memcachedl定?home/dennis/memcachedQ可以这样启动memcached:

memcached -s /home/dennis/memcached


端口呢?没有端口了,/home/dennis/memcachedq个文g你可以理解成FIFO的管道,unix domain socket的server/client通过q个道通讯?br />
   libmemcached支持通过unix domain socket来访问memcachedQ基于libmemcached实现的client应该都可以用这一功能。目前来看,javaq_׃不支持^台相关的unix domain socketQ因此无法n受memcached的这一Ҏ?br />
   不过有一个开源项目通过jni支持实现了unix domain socketQ这个项目称?a title="juds" >juds。核心类׃个,使用非常单。下载文件后Q解压羃Qmake & make install卛_。注意,Makefile中写MJAVA_HOMEQ手工修改即可。看一个例子,l典的Time server:
package com.google.code.juds.test;

import java.io.IOException;

import com.google.code.juds.*;
import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class TimeServer {
    
public static void main(String[] args) {
        
try {
            UnixDomainSocketServer server 
= new UnixDomainSocketServer(
                    
"/home/dennis/time", UnixDomainSocket.SOCK_STREAM);
            OutputStream output 
= server.getOutputStream();
             Date date 
= new Date();
             DateFormat dateFormat 
= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            output.write(dateFormat.format(date).getBytes());
        } 
catch (IOException e) {
                    e.printStackTrace();
        }

    }

}

    通过UnixDomainSocketServer创徏serverQ指定类型ؓSOCK_STREAMQjuds也支持UDPcd。client的用如?
        byte[] b = new byte[128];
       
UnixDomainSocketClient socket = new UnixDomainSocketClient("/home/dennis/time",
                UnixDomainSocket.SOCK_STREAM);
        InputStream in 
= socket.getInputStream();
        in.read(b);
        System.out.println(
"Text received: \"" + new String(b) + "\"");
        socket.close();
    昄Qjudsq只支持dIOQ考虑可进一步用select、poll来扩展实现非dIO?br />
    最后一个例子,通过juds讉Kmemcached的unix domain socketQ简单的version协议调用Q?br />
byte[] b = new byte[128];
        UnixDomainSocketClient socket 
= new UnixDomainSocketClient("/home/dennis/memcached",
                UnixDomainSocket.SOCK_STREAM);
        OutputStream out 
= socket.getOutputStream();
        String text 
= "version\r\n";
        out.write(text.getBytes());
        InputStream in 
= socket.getInputStream();
        in.read(b);
        System.out.println(
"Text received: \"" + new String(b) + "\"");
        socket.close();
   输出
     Text received: "VERSION 1.4.1"


dennis 2009-10-15 06:12 发表评论
]]>
ACE_Select_Reactor在win32上编译的问?/title><link>//www.355548.live/killme2008/archive/2009/02/03/253089.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 03 Feb 2009 07:40:00 GMT</pubDate><guid>//www.355548.live/killme2008/archive/2009/02/03/253089.html</guid><wfw:comment>//www.355548.live/killme2008/comments/253089.html</wfw:comment><comments>//www.355548.live/killme2008/archive/2009/02/03/253089.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.355548.live/killme2008/comments/commentRss/253089.html</wfw:commentRss><trackback:ping>//www.355548.live/killme2008/services/trackbacks/253089.html</trackback:ping><description><![CDATA[    ACE_Reactor在windows上默认不是用ACE_Select_ReactorQ而是ACE_WFMO_ReactorQ封装了WaitForMultipleObjects和WSAEventSelectQ。如果想选择ACE_Select_ReactorQ如Q?br /> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> //www.CodeHighlighter.com/<br /> <br /> --><span style="color: #000000;">ACE_Select_Reactor select_reactor;<br /> ACE_Reactor reactor (</span><span style="color: #000000;">&</span><span style="color: #000000;">select_reactor);</span></div> <br />     那么VC需要启?GR~译选项Q具体做法就是在目属性c/c++的语a一栏中启用RTTI信息卛_。在选择了ACE_Select_Reactor之后Q启动进E后在ProcessExplorer果然可以看到q程的TCP属性中建立了两个互q的TCPq接Q用以notify的实现?br /> <br /> <img src="//www.355548.live/images/blogjava_net/killme2008/select_reactor.jpg" alt="" border="0" /><br /> <br /> <br /> <br /><img src ="//www.355548.live/killme2008/aggbug/253089.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.355548.live/killme2008/" target="_blank">dennis</a> 2009-02-03 15:40 <a href="//www.355548.live/killme2008/archive/2009/02/03/253089.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ACE Reactor的Echo Server - 棒球比分大小怎么算|վ//www.355548.live/killme2008/archive/2009/02/03/253057.htmldennisdennisTue, 03 Feb 2009 03:59:00 GMT//www.355548.live/killme2008/archive/2009/02/03/253057.html//www.355548.live/killme2008/comments/253057.html//www.355548.live/killme2008/archive/2009/02/03/253057.html#Feedback1//www.355548.live/killme2008/comments/commentRss/253057.html//www.355548.live/killme2008/services/trackbacks/253057.html
  1 /************************************************************************ 
  2 * @file: echo.cpp                                                    
  3 * @author: dennis
  4 * @revise: dennis <killme2008@gmail.com> //www.355548.live/killme2008
  5 *          相对完整的echo serverQ可以接受多个客Lq接Qƈ且可以通过键入quit正常关闭
  6 
  7 ************************************************************************/
  8 
  9 #ifdef _DEBUG
 10 #pragma comment (lib,"aced.lib")
 11 #else
 12 #pragma comment (lib,"ace.lib")
 13 #endif
 14 
 15 #include "ace/Reactor.h"
 16 #include "ace/SOCK_Acceptor.h"
 17 #include "ace/os.h"
 18 #include "ace/Log_Msg.h"
 19 #include "ace/inet_addr.h"
 20 #include "ace/Thread_Manager.h"
 21 #include<iostream>
 22 #include<string>
 23 
 24 #define PORT_NO 8080
 25 typedef ACE_SOCK_Acceptor Acceptor;
 26 //forward declaration
 27 class Echo_Handler;
 28 
 29 class Echo_Handler:public ACE_Event_Handler
 30 {
 31 public:
 32     //construcor
 33     Echo_Handler()
 34     {
 35     }
 36     virtual ~Echo_Handler()
 37     {
 38     }
 39     //Called back to handle any input received
 40     int handle_input(ACE_HANDLE)
 41     {
 42         //receive the data
 43         ssize_t recvBytes = peer().recv(data,12);
 44         if(recvBytes <= 0)
 45         {
 46             ACE_DEBUG((LM_DEBUG,"%s\n","客户端断开q接"));
 47             return -1;
 48         }
 49         data[recvBytes] = 0;
 50 
 51         ACE_DEBUG((LM_DEBUG,"%s\n",data));
 52 
 53 
 54         if(ACE_OS::strcmp(data,"q"== 0)
 55         {
 56             ACE_DEBUG((LM_DEBUG,"%s\n","客户端退?/span>"));
 57             peer().close();
 58             return -1;
 59         }
 60         peer().send_n(data,recvBytes);
 61         // do something with the input received.
 62         // 
 63         // keep yourself registerd with the reator
 64         return 0;
 65     }
 66 
 67     int handle_close(ACE_HANDLE h,ACE_Reactor_Mask m)
 68     {
 69         delete this;
 70         return  0;
 71     }
 72 
 73     //Used by the reactor to determine the underlying handle
 74     ACE_HANDLE get_handle()  const 
 75     {
 76         return this->peer_.get_handle();
 77     }
 78 
 79     //Returns a reference to the underlying stream.
 80     ACE_SOCK_Stream& peer()
 81     {
 82         return this->peer_;
 83     }
 84 
 85 private:
 86     ACE_SOCK_Stream peer_;
 87     char data [12];
 88 };
 89 
 90 class Echo_Accept_Handler:public ACE_Event_Handler
 91 {
 92 public:
 93     //Constructor
 94     Echo_Accept_Handler(ACE_Addr &addr)
 95     {
 96         this->open(addr);
 97     }
 98     virtual ~Echo_Accept_Handler(){}
 99     //Open the peer_acceptor so it starts to "listen"
100     //for incoming clients
101     int open(ACE_Addr &addr)
102     {
103         if(peer_acceptor.open(addr)==-1)
104             ACE_ERROR_RETURN((LM_ERROR,"启动服务器错误\n"),1);
105         return 0;
106     }
107 
108     //Overload the handle input method
109     int handle_input(ACE_HANDLE handle)
110     {
111         //Client has requested connection to server.
112         //Create a handler to handle the connection
113         Echo_Handler *eh;
114         ACE_NEW_RETURN(eh,Echo_Handler,-1);
115         ACE_INET_Addr cliaddr;
116         //Accept the connection "into" the Event Handler
117         if(this->peer_acceptor.accept(eh->peer(),//stream
118             &cliaddr,//remote address
119             0,//timeout
120             1== -1)//restart if interrupted
121             ACE_DEBUG((LM_ERROR,"Error in connection \n"));
122 
123         ACE_DEBUG((LM_DEBUG,"q接已经建立,来自%s\n",cliaddr.get_host_addr()));
124 
125         //Register the input event handler for reading 
126         ACE_Reactor::instance()->register_handler(eh,ACE_Event_Handler::READ_MASK);
127         const char* msg = "按q键服务安全退出\r\n";
128         eh->peer().send_n(msg,strlen(msg)+1);
129         return 0;
130     }
131 
132     //Used by the reactor to determine the underlying handle
133     ACE_HANDLE get_handle(voidconst
134     {
135         return this->peer_acceptor.get_handle();
136     }
137     int handle_close(ACE_HANDLE h,ACE_Reactor_Mask m){
138         peer_acceptor.close();
139         delete this;
140         return 0;
141     }
142 
143 private:
144     Acceptor peer_acceptor;
145 };
146 class Quit_Handler:public ACE_Event_Handler
147 {
148 public:
149     Quit_Handler(ACE_Reactor* r):ACE_Event_Handler(r){}
150     virtual int handle_exception(ACE_HANDLE)
151     {
152         ACE_DEBUG((LM_DEBUG,"停止服务器中\n"));
153         reactor()->end_reactor_event_loop();
154         return -1;
155     }
156     int handle_close(ACE_HANDLE h,ACE_Reactor_Mask m)
157     {
158         delete this;
159         return 0;
160     }
161     virtual ~Quit_Handler(){}
162 };
163 static ACE_THR_FUNC_RETURN run_events (void *arg);
164 static ACE_THR_FUNC_RETURN controller (void *arg);
165 int ACE_TMAIN(int argc,char *argv[])
166 {
167 
168     ACE_Reactor* reactor=ACE_Reactor::instance();
169     if(ACE_Thread_Manager::instance()->spawn(run_events,reactor,THR_DETACHED | THR_SCOPE_SYSTEM)==-1)
170         return 1;
171     if(ACE_Thread_Manager::instance()->spawn(controller,reactor,THR_DETACHED | THR_SCOPE_SYSTEM)==-1)
172         return 1;
173     return ACE_Thread_Manager::instance()->wait();
174 }
175 
176 static ACE_THR_FUNC_RETURN run_events (void *arg)
177 {
178     ACE_Reactor* reactor=ACE_static_cast(ACE_Reactor*,arg);
179     ACE_INET_Addr addr(PORT_NO);
180 
181     Echo_Accept_Handler *eh=0;
182     ACE_NEW_RETURN(eh,Echo_Accept_Handler(addr),1);
183 
184     ACE_Reactor::instance()->owner(ACE_OS::thr_self());
185     reactor->register_handler(eh,ACE_Event_Handler::ACCEPT_MASK);
186     ACE_Reactor::instance()->run_reactor_event_loop();
187     return 0;
188 }
189 static ACE_THR_FUNC_RETURN controller (void *arg)
190 {
191     ACE_Reactor* reactor=ACE_static_cast(ACE_Reactor*,arg);
192     Quit_Handler *quit_handler=0;
193     ACE_NEW_RETURN(quit_handler,Quit_Handler(reactor),1);
194     for(;;)
195     {
196         std::string line;
197         std::getline(std::cin,line,'\n');
198         if(line=="quit"){
199             ACE_DEBUG((LM_DEBUG,"h停止服务器\n"));
200             reactor->notify(quit_handler);
201             break;
202         }
203     }
204     return 0;  
205 }
206 




]]>
{ganrao}