﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-&lt;table border="0" cellspacing="0" cellpadding="0" style="margin-left:5%;display:inline;height:30px;"&gt;&lt;tr&gt;&lt;td style="font-weight:bolder; font-size:16px; line-height:30px;"&gt;一年十二月&amp;nbsp&amp;nbsp谁主春秋&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-size:14px; line-height:30px;"&gt;关注：基础系统工程 密码学 人工智能&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;-随笔分类-Network</title><link>http://www.cppblog.com/qinqing1984/category/10072.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 30 Sep 2023 22:54:13 GMT</lastBuildDate><pubDate>Sat, 30 Sep 2023 22:54:13 GMT</pubDate><ttl>60</ttl><item><title>基于X509证书的身份认证思考小结</title><link>http://www.cppblog.com/qinqing1984/archive/2023/09/30/230117.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Sat, 30 Sep 2023 00:00:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2023/09/30/230117.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/230117.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2023/09/30/230117.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/230117.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/230117.html</trackback:ping><description><![CDATA[<div>
<div style="text-align: center;"><img src="http://www.cppblog.com/images/cppblog_com/qinqing1984/x509-three-auths-2.jpg" width="1232" height="638" alt="" /></div>
&nbsp; 有单向、双向、三向3种认证方式，前两者必须检查时间戳以防重放攻击，单向因为只有一个消息传递，如果仅靠一次性随机数是无法判断消息是否重放。双向有两个消息传递，一来一回，仅靠一次性随机数只能检测到发响应那方的重放。最后者则不必，可仅通过一次性随机数检测自己是否遭遇重放攻击，因为接收第二个消息的那方，通过判断第二个消息中随机数是否等于自己先前已发送第一个消息中的那个，若不等于则为重放，若等于则发第三个确认消息给对方，对方收到并判断确认消息中的随机数是否等于先前它已发送第二个消息中的随机数，若等于则说明第它收到的第一个消息的确是另一方发送的即非重放，否则为重放。因此三向认证可不必同步双方时钟。但正因为不强制检查时间戳而可能导致<span style="color: #ff00ff; font-size: 12pt;">中间人攻击</span>：假设通信双方为A、B，中间人为C，攻击步骤如下</div>
<div>&nbsp;<strong>1</strong>. C与B认证时，发送先前已截获的A到B请求消息给B</div>
<div>&nbsp;<strong>2</strong>. 截获并存储B到A的响应消息x，但不转发，开始与A认证</div>
<div>&nbsp;<strong>3</strong>. 收到A的请求消息后，解密x取出其中的随机数Rb作为响应给A消息中的随机数，用自己私钥签署整个消息后发给A</div>
<div>&nbsp;<strong>4</strong>. 收到并转发A的确认消息给B</div>
<div>以上完成后，C就能冒充A与B通信了。<span style="color: #ff6600;">一种简单的改进方法</span>是先用对方的公钥加密消息中的随机数，再用自己的私钥签署整个消息。关于网络协议的安全性分析，主流方法是形式化分析，可以借助相关工具来验证找出漏洞</div><img src ="http://www.cppblog.com/qinqing1984/aggbug/230117.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2023-09-30 08:00 <a href="http://www.cppblog.com/qinqing1984/archive/2023/09/30/230117.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用HiRedis实现自动重连Redis</title><link>http://www.cppblog.com/qinqing1984/archive/2021/02/25/217619.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Thu, 25 Feb 2021 07:51:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2021/02/25/217619.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/217619.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2021/02/25/217619.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/217619.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/217619.html</trackback:ping><description><![CDATA[<span style="font-size: 12pt;"><strong>主要思路</strong></span><br />
&nbsp;1. 首次连接时调用redisConnectWithTimeout或redisConnectUnixWithTimeout连接Redis服务端，若成功则保存返回的redisContext，假设为ctx<br />
&nbsp;2. 发送命令数据后获取响应，如果是pipeling模式则调用redisGetReply获取响应，再检查redisContext中的错误码，如果为网络出错或关闭，则不置位ctx <span style="color: #ff00ff;">REDIS_CONNECTED</span>标志<br />
&nbsp;3. 在下次发送数据时，先检查ctx否置位了<span style="color: #ff00ff;">REDIS_CONNECTED</span><span style="color: #000000;">标志</span>，若没有则调用redisReconnect重连Redis服务端<br />
<br />
<strong style="font-size: 12pt;">实现代码</strong><br style="font-size: 12pt;" />
<strong>&nbsp;自动连接</strong><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;margin:0 auto"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<span style="color: #993300;"><strong>redis_auto_connect</strong></span>(CBED_REDIS&nbsp;*redis)<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(NULL==redis-&gt;ctx){<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redisContext&nbsp;*ctx;<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(redis-&gt;type&nbsp;==&nbsp;CONN_TCP)<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctx&nbsp;=&nbsp;<span style="background-color: yellow;">redisConnectWithTimeout</span>(redis-&gt;conn.tcp.ip,&nbsp;redis-&gt;conn.tcp.port,&nbsp;redis-&gt;timeout_conn);<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span><br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctx&nbsp;=&nbsp;<span style="background-color: yellow;">redisConnectUnixWithTimeout</span>(redis-&gt;conn.unix.path,&nbsp;redis-&gt;timeout_conn);<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(NULL==ctx){<br />
<span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zlog_fatal(c_redis,&nbsp;"redis&nbsp;allocate&nbsp;context&nbsp;fail");<br />
<span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>(ctx-&gt;err){<br />
<span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zlog_fatal(c_redis,&nbsp;"redis&nbsp;connection&nbsp;%s:%d&nbsp;error:&nbsp;%s",&nbsp;<br />
<span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redis-&gt;type==CONN_TCP?redis-&gt;conn.tcp.ip:redis-&gt;conn.unix.path,&nbsp;<br />
<span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redis-&gt;type==CONN_TCP?redis-&gt;conn.tcp.port:0,&nbsp;ctx-&gt;errstr);<br />
<span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redisFree(ctx);<br />
<span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(REDIS_ERR==redisSetTimeout(ctx,&nbsp;redis-&gt;timeout_rw)){<br />
<span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zlog_fatal(c_redis,&nbsp;"redis&nbsp;set&nbsp;rw&nbsp;timeout&nbsp;error:&nbsp;%s",&nbsp;ctx-&gt;errstr);<br />
<span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redisFree(ctx);<br />
<span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redis-&gt;ctx&nbsp;=&nbsp;ctx;<br />
<span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(redis_auth(redis)){<br />
<span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redisFree(ctx);<br />
<span style="color: #008080; ">31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redis-&gt;ctx&nbsp;=&nbsp;NULL;<br />
<span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">35</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>(<span style="color: #ff0000;">!(redis-&gt;ctx-&gt;flags&nbsp;&amp;&nbsp;REDIS_CONNECTED)</span>){<br />
<span style="color: #008080; ">36</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;retry&nbsp;=&nbsp;redis-&gt;reconn_max,&nbsp;n&nbsp;=&nbsp;0;<br />
<span style="color: #008080; ">37</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">do</span>&nbsp;{<br />
<span style="color: #008080; ">38</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(REDIS_OK==<span style="background-color: yellow;">redisReconnect</span>(redis-&gt;ctx)){<br />
<span style="color: #008080; ">39</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;redis_auth(redis);<br />
<span style="color: #008080; ">40</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">41</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">42</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zlog_warn(c_redis,&nbsp;"redis&nbsp;reconnect&nbsp;%d&nbsp;error:&nbsp;%s",&nbsp;++n,&nbsp;redis-&gt;ctx-&gt;errstr);&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">43</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(redis-&gt;reconn_interval);&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">reconn_interval&nbsp;default&nbsp;is&nbsp;3&nbsp;seconds</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">44</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">45</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">while</span>(--retry&nbsp;&gt;&nbsp;0);<br />
<span style="color: #008080; ">46</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">47</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zlog_error(c_redis,&nbsp;"redis&nbsp;reconnect&nbsp;exceed&nbsp;max&nbsp;num&nbsp;%d",&nbsp;redis-&gt;reconn_max);<br />
<span style="color: #008080; ">48</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">49</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">50</span>&nbsp;<br />
<span style="color: #008080; ">51</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">52</span>&nbsp;}</div>
&nbsp;<br />
&nbsp;<strong>发送时检查错误码<br />
</strong>
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all;margin:0 auto"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<span style="color: #993300;"><strong>redis_bulk_get_reply</strong></span>(CBED_REDIS&nbsp;*redis)<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redisReply&nbsp;*r;<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;num&nbsp;=&nbsp;redis-&gt;cmd_num;<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redis-&gt;cmd_num&nbsp;=&nbsp;0;<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(;&nbsp;i&lt;num;&nbsp;++i){<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(REDIS_OK==redisGetReply(redis-&gt;ctx,&nbsp;(<span style="color: #0000FF; ">void</span>**)&amp;r)){<br />
<span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(r-&gt;type&nbsp;==&nbsp;REDIS_REPLY_ERROR){<br />
<span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zlog_error(c_redis,&nbsp;"redis&nbsp;get&nbsp;reply&nbsp;error:&nbsp;%.*s",&nbsp;r-&gt;len,&nbsp;r-&gt;str);<br />
<span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;freeReplyObject(r);<br />
<span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;freeReplyObject(r);<br />
<span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">else</span>{<br />
<span style="color: #008080; ">18</span>&nbsp;<span style="color: #ff00ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #ff0000;">if</span><span style="color: #ff0000;">(redis</span><span style="color: #ff0000;">-&gt;</span><span style="color: #ff0000;">ctx</span><span style="color: #ff0000;">-&gt;</span><span style="color: #ff0000;">err</span><span style="color: #ff0000;">==</span><span style="color: #ff0000;">REDIS_ERR_IO</span><span style="color: #ff0000;">||</span><span style="color: #ff0000;">redis</span><span style="color: #ff0000;">-&gt;</span><span style="color: #ff0000;">ctx</span><span style="color: #ff0000;">-&gt;</span><span style="color: #ff0000;">err</span><span style="color: #ff0000;">==</span><span style="color: #ff0000;">REDIS_ERR_EOF)</span><br />
<span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #000000; background-color: yellow;">redis</span><span style="color: #000000; background-color: yellow;">-&gt;</span><span style="color: #000000; background-color: yellow;">ctx</span><span style="color: #000000; background-color: yellow;">-&gt;</span><span style="color: #000000; background-color: yellow;">flags&nbsp;</span><span style="color: #000000; background-color: yellow;">&amp;=</span>&nbsp;<span style="color: #000000; background-color: yellow;">~</span><span style="color: #000000; background-color: yellow;">REDIS_CONNECTED;</span><br />
<span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zlog_fatal(c_redis,&nbsp;"redis&nbsp;get&nbsp;reply&nbsp;fail:&nbsp;%s",&nbsp;redis-&gt;ctx-&gt;errstr);<br />
<span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">24</span>&nbsp;<br />
<span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">26</span>&nbsp;}<br />
<span style="color: #008080; ">27</span>&nbsp;<br />
<span style="color: #008080; ">28</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<strong style="color: #993300;">redis_send</strong>(CBED_REDIS&nbsp;*redis,&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*data,&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;size,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;force)<br />
<span style="color: #008080; ">29</span>&nbsp;{<br />
<span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(<span style="color: #993300;">redis_auto_connect</span>(redis))<br />
<span style="color: #008080; ">31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">32</span>&nbsp;<br />
<span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i;<br />
<span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">35</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(redis-&gt;max_cmd_num&nbsp;&gt;&nbsp;1){&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">pipelining</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">36</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(i=0;&nbsp;i&lt;redis-&gt;queue_num;&nbsp;++i){<br />
<span style="color: #008080; ">37</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(REDIS_ERR&nbsp;==&nbsp;redisAppendCommand(redis-&gt;ctx,&nbsp;"RPUSH&nbsp;%s&nbsp;%b",&nbsp;redis-&gt;queue[i],&nbsp;data,&nbsp;size))&nbsp;{<br />
<span style="color: #008080; ">38</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zlog_fatal(c_redis,&nbsp;"redis&nbsp;append&nbsp;command&nbsp;rpush&nbsp;%s&nbsp;len&nbsp;%u&nbsp;fail:&nbsp;%s",&nbsp;redis-&gt;queue[i],&nbsp;size,&nbsp;redis-&gt;ctx-&gt;errstr);<br />
<span style="color: #008080; ">39</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">40</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">41</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">42</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++redis-&gt;cmd_num;<br />
<span style="color: #008080; ">43</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>((!force&nbsp;&amp;&amp;&nbsp;redis-&gt;cmd_num==redis-&gt;max_cmd_num)&nbsp;||&nbsp;force){<br />
<span style="color: #008080; ">44</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(<span style="color: #993300;">redis_bulk_get_reply</span>(redis))<br />
<span style="color: #008080; ">45</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">46</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">47</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">48</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">49</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">else</span>{<br />
<span style="color: #008080; ">50</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(i=0;&nbsp;i&lt;redis-&gt;queue_num;&nbsp;++i){<br />
<span style="color: #008080; ">51</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redisReply&nbsp;*r&nbsp;=&nbsp;redisCommand(redis-&gt;ctx,&nbsp;"RPUSH&nbsp;%s&nbsp;%b",&nbsp;redis-&gt;queue[i],&nbsp;data,&nbsp;size);<br />
<span style="color: #008080; ">52</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(NULL==r){<br />
<span style="color: #008080; ">53</span>&nbsp;<span style="color: #ff0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #ff0000;">if</span><span style="color: #ff0000;">(redis</span><span style="color: #ff0000;">-&gt;</span><span style="color: #ff0000;">ctx</span><span style="color: #ff0000;">-&gt;</span><span style="color: #ff0000;">err</span><span style="color: #ff0000;">==</span><span style="color: #ff0000;">REDIS_ERR_IO</span><span style="color: #ff0000;">||</span><span style="color: #ff0000;">redis</span><span style="color: #ff0000;">-&gt;</span><span style="color: #ff0000;">ctx</span><span style="color: #ff0000;">-&gt;</span><span style="color: #ff0000;">err</span><span style="color: #ff0000;">==</span><span style="color: #ff0000;">REDIS_ERR_EOF)</span><br />
<span style="color: #008080; ">54</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #000000; background-color: yellow;">redis</span><span style="color: #000000; background-color: yellow;">-&gt;</span><span style="color: #000000; background-color: yellow;">ctx</span><span style="color: #000000; background-color: yellow;">-&gt;</span><span style="color: #000000; background-color: yellow;">flags&nbsp;</span><span style="color: #000000; background-color: yellow;">&amp;=</span>&nbsp;<span style="color: #000000; background-color: yellow;">~</span><span style="color: #000000; background-color: yellow;">REDIS_CONNECTED;</span><br />
<span style="color: #008080; ">55</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zlog_fatal(c_redis,&nbsp;"redis&nbsp;command&nbsp;rpush&nbsp;%s&nbsp;len&nbsp;%u&nbsp;fail:&nbsp;%s",&nbsp;redis-&gt;queue[i],&nbsp;size,&nbsp;redis-&gt;ctx-&gt;errstr);<br />
<span style="color: #008080; ">56</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">57</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">58</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">59</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(r-&gt;type&nbsp;==&nbsp;REDIS_REPLY_ERROR){<br />
<span style="color: #008080; ">60</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zlog_error(c_redis,&nbsp;"redis&nbsp;reply&nbsp;rpush&nbsp;%s&nbsp;len&nbsp;%u&nbsp;error:&nbsp;%.*s",&nbsp;redis-&gt;queue[i],&nbsp;size,&nbsp;r-&gt;len,&nbsp;r-&gt;str);<br />
<span style="color: #008080; ">61</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;freeReplyObject(r);<br />
<span style="color: #008080; ">62</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">63</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">64</span>&nbsp;<br />
<span style="color: #008080; ">65</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;freeReplyObject(r);<br />
<span style="color: #008080; ">66</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">67</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">68</span>&nbsp;<br />
<span style="color: #008080; ">69</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">70</span>&nbsp;}</div><img src ="http://www.cppblog.com/qinqing1984/aggbug/217619.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2021-02-25 15:51 <a href="http://www.cppblog.com/qinqing1984/archive/2021/02/25/217619.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于ENet实现可靠UDP通信的同步模型</title><link>http://www.cppblog.com/qinqing1984/archive/2020/05/04/217279.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Mon, 04 May 2020 11:08:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2020/05/04/217279.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/217279.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2020/05/04/217279.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/217279.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/217279.html</trackback:ping><description><![CDATA[<span style="font-size: 13pt;"><strong>场景说明</strong></span><br />
&nbsp;&nbsp;&nbsp;选择ENet代替TCP用于弱网环境(通常丢包率高)的数据传输，提高可靠性及传输效率。为了说明怎样正确有效地应用ENet，本文按照TCP C/S同步通信的流程作了对应的接口封装实现，取库名为<span style="color: #ff0000;"><strong>rudp</strong></span>。<br />
<br />
<span style="font-size: 13pt;"><strong>接口对照<br />
</strong></span>&nbsp; &nbsp;左边为rudp库的API，右边为标准的Berkeley套接字API。rudp库所有API前缀为rudp，rudp_listen和rudp_accept仅用于服务端，rudp_connect和rudp_disconnect仅用于客户端；其它接口共用于两端，其中rudp_send调用rudp_sendmsg实现，rudp_recv调用rudp_recvmsg实现。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/qinqing1984/rudp_vs_standard_socket_api.png" alt="" /><br />
<strong style="font-size: 13pt;"><br />
具体实现</strong><br />
&nbsp;&nbsp;&nbsp;所有接口遵循Berkeley套接字接口的语义，为简单起见，错误描述输出到标准错误流。<br />
&nbsp; &nbsp;&#9670;&nbsp;<strong style="font-size: 12pt;">监听</strong>，成功返回0，失败返回-1<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 14px;padding-top: 4px;width: 98%;word-break:break-all">
<div><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<strong style="color: #993366; font-size: 12pt;">rudp_listen</strong>(<span style="color: #0000FF; ">const</span>&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*ip,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;port,&nbsp;ENetHost&nbsp;**host)<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENetAddress&nbsp;address;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(!strcmp(ip,&nbsp;"*"))<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ip&nbsp;=&nbsp;"0.0.0.0";<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(enet_address_set_host_ip(&amp;address,&nbsp;ip)){<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet_address_set_host_ip&nbsp;%s&nbsp;fail",&nbsp;ip);<br />
<span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;address.port&nbsp;=&nbsp;port;<br />
<span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(host);<br />
<span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*host&nbsp;=&nbsp;enet_host_create(&amp;address,&nbsp;1,&nbsp;1,&nbsp;0,&nbsp;0);<br />
<span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(NULL==*host){<br />
<span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet_host_create&nbsp;%s:%d&nbsp;fail",&nbsp;address.host,&nbsp;address.port);<br />
<span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">21</span>&nbsp;<br />
<span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;size&nbsp;=&nbsp;1024*1024*1024;<br />
<span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(enet_socket_set_option((*host)-&gt;socket,&nbsp;ENET_SOCKOPT_RCVBUF,&nbsp;size)){<br />
<span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet&nbsp;set&nbsp;server&nbsp;socket&nbsp;rcvbuf&nbsp;%d&nbsp;bytes&nbsp;fail",&nbsp;size);<br />
<span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">26</span>&nbsp;<br />
<span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">28</span>&nbsp;}</div>
</div>
<br />
&nbsp; &nbsp;&#9670;&nbsp;<strong style="font-size: 12pt;">接受连接</strong>，成功返回0，失败返回-1<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 14px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<strong style="font-size: 12pt; color: #993366;">rudp_accept</strong>(ENetHost&nbsp;*host,&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;timeout,&nbsp;ENetPeer&nbsp;**peer)<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;ret;<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENetEvent&nbsp;<span style="color: #0000FF; ">event</span>;<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;=&nbsp;enet_host_service(host,&nbsp;&amp;<span style="color: #0000FF; ">event</span>,&nbsp;timeout);<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(ret&nbsp;&gt;&nbsp;0){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(<span style="color: #0000FF; ">event</span>.type&nbsp;!=&nbsp;ENET_EVENT_TYPE_CONNECT){<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(<span style="color: #0000FF; ">event</span>.type&nbsp;==&nbsp;ENET_EVENT_TYPE_RECEIVE)<br />
<span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enet_packet_destroy(<span style="color: #0000FF; ">event</span>.packet);<br />
<span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet_host_service&nbsp;event&nbsp;type&nbsp;%d&nbsp;is&nbsp;not&nbsp;connect",&nbsp;<span style="color: #0000FF; ">event</span>.type);<br />
<span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(peer);<br />
<span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*peer&nbsp;=&nbsp;<span style="color: #0000FF; ">event</span>.peer;<br />
<span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>(0==ret){<br />
<span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet_host_service&nbsp;timeout&nbsp;%d",&nbsp;timeout);<br />
<span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">else</span>{<br />
<span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet_host_service&nbsp;fail");<br />
<span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">26</span>&nbsp;<br />
<span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">28</span>&nbsp;}</div>
&nbsp; &nbsp;<br />
&nbsp; &nbsp;&#9670;&nbsp;<strong style="font-size: 12pt;">建立连接</strong>，成功返回0，失败返回-1，conn_timeout是连接超时，rw_timeout是收发超时，单位为毫秒<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 14px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<strong style="color: #993366; font-size: 12pt;">rudp_connect</strong><span style="font-size: 12pt;">(</span><span style="color: #0000FF; ">const</span>&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*srv_ip,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;srv_port,&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;conn_timeout,&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;rw_timeout,&nbsp;ENetHost&nbsp;**host,&nbsp;ENetPeer&nbsp;**peer)<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(host);<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*host&nbsp;=&nbsp;enet_host_create(NULL,&nbsp;1,&nbsp;1,&nbsp;0,&nbsp;0);<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(NULL==*host){<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet_host_create&nbsp;fail");<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;fail;<br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(enet_socket_set_option((*host)-&gt;socket,&nbsp;ENET_SOCKOPT_RCVBUF,&nbsp;1024*1024*1024)){<br />
<span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet&nbsp;set&nbsp;server&nbsp;socket&nbsp;rcvbuf&nbsp;1M&nbsp;bytes&nbsp;fail");<br />
<span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENetAddress&nbsp;srv_addr;<br />
<span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(enet_address_set_host_ip(&amp;srv_addr,&nbsp;srv_ip)){<br />
<span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet_address_set_host_ip&nbsp;%s&nbsp;fail",&nbsp;srv_ip);<br />
<span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;fail;<br />
<span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;srv_addr.port&nbsp;=&nbsp;srv_port;<br />
<span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(peer);<br />
<span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*peer&nbsp;=&nbsp;enet_host_connect(*host,&nbsp;&amp;srv_addr,&nbsp;1,&nbsp;0);&nbsp;<br />
<span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(*peer==NULL){<br />
<span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet_host_connect&nbsp;%s:%d&nbsp;fail",&nbsp;srv_ip,&nbsp;srv_port);<br />
<span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;fail;<br />
<span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">26</span>&nbsp;<br />
<span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enet_peer_timeout(*peer,&nbsp;0,&nbsp;rw_timeout,&nbsp;rw_timeout);<br />
<span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;cnt&nbsp;=&nbsp;0;<br />
<span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENetEvent&nbsp;<span style="color: #0000FF; ">event</span>;<br />
<span style="color: #008080; ">31</span>&nbsp;<br />
<span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>(1){<br />
<span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;=&nbsp;enet_host_service(*host,&nbsp;&amp;<span style="color: #0000FF; ">event</span>,&nbsp;1);<br />
<span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(ret&nbsp;==&nbsp;0){&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">35</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(++cnt&nbsp;&gt;=&nbsp;conn_timeout){&nbsp;<br />
<span style="color: #008080; ">36</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet_host_service&nbsp;timeout&nbsp;%d",&nbsp;conn_timeout);<br />
<span style="color: #008080; ">37</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;fail;<br />
<span style="color: #008080; ">38</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">39</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">40</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>(ret&nbsp;&gt;&nbsp;0){<br />
<span style="color: #008080; ">41</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(<span style="color: #0000FF; ">event</span>.type&nbsp;!=&nbsp;ENET_EVENT_TYPE_CONNECT){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">42</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet_host_service&nbsp;event&nbsp;type&nbsp;%d&nbsp;is&nbsp;not&nbsp;connect",&nbsp;<span style="color: #0000FF; ">event</span>.type);<br />
<span style="color: #008080; ">43</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;fail;<br />
<span style="color: #008080; ">44</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">45</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">break</span>;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">connect&nbsp;successfully</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">46</span>&nbsp;<span style="color: #008000; "></span><br />
<span style="color: #008080; ">47</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">else</span>{<br />
<span style="color: #008080; ">48</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet_host_service&nbsp;fail");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">49</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;fail;<br />
<span style="color: #008080; ">50</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">51</span>&nbsp; &nbsp; &nbsp;}<br />
<span style="color: #008080; ">52</span>&nbsp;<br />
<span style="color: #008080; ">53</span>&nbsp;#ifdef&nbsp;_DEBUG<br />
<span style="color: #008080; ">54</span>&nbsp; &nbsp; &nbsp;<span style="color: #0000FF; ">char</span>&nbsp;local_ip[16],&nbsp;foreign_ip[16];<br />
<span style="color: #008080; ">55</span>&nbsp; &nbsp; &nbsp;ENetAddress&nbsp;local_addr;<br />
<span style="color: #008080; ">56</span>&nbsp;<br />
<span style="color: #008080; ">57</span>&nbsp; &nbsp; &nbsp;enet_socket_get_address((*host)-&gt;socket,&nbsp;&amp;local_addr);<br />
<span style="color: #008080; ">58</span>&nbsp; &nbsp; &nbsp;enet_address_get_host_ip(&amp;local_addr,&nbsp;local_ip,&nbsp;<span style="color: #0000FF; ">sizeof</span>(local_ip));<br /><font color="#008080">59</font>&nbsp; &nbsp; &nbsp;enet_address_get_host_ip(&amp;(*peer)-&gt;address,&nbsp;foreign_ip,&nbsp;<span style="color: #0000FF; ">sizeof</span>(foreign_ip));<br />
<span style="color: #008080; ">60</span>&nbsp; &nbsp; &nbsp;<br />
<span style="color: #008080; ">61</span>&nbsp; &nbsp; &nbsp;printf("%s:%d&nbsp;connected&nbsp;to&nbsp;%s:%d",&nbsp;local_ip,&nbsp;loca_addr.port,&nbsp;foreign_ip,&nbsp;(*peer)-&gt;address.port);<br />
<span style="color: #008080; ">62</span>&nbsp;<span style="color: #0000FF; ">#endif</span><br />
<span style="color: #008080; ">63</span>&nbsp;<br />
<span style="color: #008080; ">64</span>&nbsp; &nbsp; &nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">65</span>&nbsp; &nbsp; &nbsp;<br />
<span style="color: #008080; ">66</span>&nbsp;fail:<br />
<span style="color: #008080; ">67</span>&nbsp; &nbsp; &nbsp;<span style="color: #0000FF; ">if</span>(*host)&nbsp;enet_host_destroy(*host);&nbsp;<br />
<span style="color: #008080; ">68</span>&nbsp; &nbsp; &nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br /><font color="#008080">69</font> }<br />
</div>
&nbsp; &nbsp;<br />
&nbsp; &nbsp; &#9670;&nbsp;<strong style="font-size: 12pt;">断开连接</strong>，若成功则返回0，超时返回1，出错返回-1。先进行优雅关闭，如失败再强制关闭<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 14px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<strong style="color: #993366; font-size: 12pt;">rudp_disconnect</strong>(ENetHost&nbsp;*host,&nbsp;ENetPeer&nbsp;*peer)<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;ret;<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;#ifdef&nbsp;_DEBUG<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;local_ip[16],&nbsp;foreign_ip[16];<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENetAddress&nbsp;local_addr;<br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enet_socket_get_address(host-&gt;socket,&nbsp;&amp;local_addr);<br />
<span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enet_address_get_host_ip(&amp;local_addr,&nbsp;local_ip,&nbsp;<span style="color: #0000FF; ">sizeof</span>(local_ip));<br />
<span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enet_address_get_host_ip(&amp;peer-&gt;address,&nbsp;foreign_ip,&nbsp;<span style="color: #0000FF; ">sizeof</span>(foreign_ip));<br />
<span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("%s:%d&nbsp;is&nbsp;disconnected&nbsp;from&nbsp;%s:%d",&nbsp;local_ip,&nbsp;local_addr.port,&nbsp;foreign_ip,&nbsp;peer-&gt;address.port);<br />
<span style="color: #008080; ">14</span>&nbsp;<span style="color: #0000FF; ">#endif</span><br />
<span style="color: #008080; ">15</span>&nbsp;<br />
<span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENetEvent&nbsp;<span style="color: #0000FF; ">event</span>;<br />
<span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enet_peer_disconnect(peer,&nbsp;0);<br />
<span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>((ret&nbsp;=&nbsp;enet_host_service(host,&nbsp;&amp;<span style="color: #0000FF; ">event</span>,&nbsp;peer-&gt;roundTripTime))&nbsp;&gt;&nbsp;0){<br />
<span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">switch</span>&nbsp;(<span style="color: #0000FF; ">event</span>.type){<br />
<span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">case</span>&nbsp;ENET_EVENT_TYPE_RECEIVE:<br />
<span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enet_packet_destroy&nbsp;(<span style="color: #0000FF; ">event</span>.packet);<br />
<span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">break</span>;<br />
<span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">case</span>&nbsp;ENET_EVENT_TYPE_DISCONNECT:<br />
<span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;=&nbsp;0;<br />
<span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;disconn_ok;<br />
<span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">30</span>&nbsp;<br />
<span style="color: #008080; ">31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;=&nbsp;0==ret&nbsp;?&nbsp;1&nbsp;:&nbsp;-1;<br />
<span style="color: #008080; ">32</span>&nbsp;<br />
<span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet_host_service&nbsp;with&nbsp;timeout&nbsp;%d&nbsp;%s",&nbsp;peer-&gt;roundTripTime,&nbsp;1==ret?"timeout":"failure");<br />
<span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">35</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enet_peer_reset(conn-&gt;peer);<br />
<span style="color: #008080; ">36</span>&nbsp;<br />
<span style="color: #008080; ">37</span>&nbsp;disconn_ok:&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">38</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enet_host_destroy(host);<br />
<span style="color: #008080; ">39</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;ret;<br />
<span style="color: #008080; ">40</span>&nbsp;}</div>
<br />
&nbsp; &nbsp; &#9670;&nbsp;<strong style="font-size: 12pt;">发送数据</strong>，若成功则返回已发送数据的长度，否则返回-1<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 14px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<strong style="color: #993366; font-size: 12pt;">rudp_sendmsg</strong>(ENetHost&nbsp;*host,&nbsp;ENetPeer&nbsp;*peer,&nbsp;ENetPacket&nbsp;*packet)<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;ret;<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(enet_peer_send(peer,&nbsp;0,&nbsp;packet)){<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet&nbsp;send&nbsp;packet&nbsp;%lu&nbsp;bytes&nbsp;to&nbsp;peer&nbsp;fail",&nbsp;packet-&gt;dataLength);<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;<br />
<span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;=&nbsp;enet_host_service(host,&nbsp;NULL,&nbsp;peer-&gt;roundTripTime);<br />
<span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(ret&nbsp;&gt;=&nbsp;0){<br />
<span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(peer-&gt;state&nbsp;==&nbsp;<span style="color: #ff00ff;">ENET_PEER_STATE_ZOMBIE</span>){<br />
<span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet&nbsp;peer&nbsp;state&nbsp;is&nbsp;zombie");<br />
<span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;packet-&gt;dataLength;<br />
<span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">else</span>{<br />
<span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet&nbsp;host&nbsp;service&nbsp;%u&nbsp;millsecond&nbsp;failure",&nbsp;peer-&gt;roundTripTime);<br />
<span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">22</span>&nbsp;}<br />
<span style="color: #008080; ">23</span>&nbsp;<br />
<span style="color: #008080; ">24</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<strong style="color: #993366; font-size: 12pt;">rudp_send</strong>(ENetHost&nbsp;*host,&nbsp;ENetPeer&nbsp;*peer,&nbsp;<span style="color: #0000FF; ">const</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;*buf,&nbsp;size_t&nbsp;len)<br />
<span style="color: #008080; ">25</span>&nbsp;{<br />
<span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;ret;<br />
<span style="color: #008080; ">27</span>&nbsp;<br />
<span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENetPacket&nbsp;*packet&nbsp;=&nbsp;enet_packet_create(buf,&nbsp;len,&nbsp;<span style="color: #ff00ff;">ENET_PACKET_FLAG_RELIABLE</span>);<br />
<span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(NULL==packet){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet&nbsp;create&nbsp;packet&nbsp;%lu&nbsp;bytes&nbsp;fail",&nbsp;<span style="color: #0000FF; ">sizeof</span>(<span style="color: #0000FF; ">int</span>)+len);<br />
<span style="color: #008080; ">31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">33</span>&nbsp;<br />
<span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;<span style="color: #993366;">rudp_sendmsg</span>(host,&nbsp;peer,&nbsp;packet);<br />
<span style="color: #008080; ">35</span>&nbsp;}</div>
&nbsp; &nbsp;发送数据时需根据对端状态判断是否断线，并且packet标志设为可靠<br />
<br />
&nbsp;&nbsp;&nbsp;&#9670;&nbsp;<strong style="font-size: 12pt;">接收数据</strong>，若成功则返回已接收数据的长度，否则返回-1<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 14px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<strong style="font-size: 12pt; color: #993366;">rudp_recvmsg</strong>(ENetHost&nbsp;*host,&nbsp;ENetPeer&nbsp;*peer,&nbsp;ENetPacket&nbsp;**packet,&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;timeout)<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;ret;<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENetEvent&nbsp;<span style="color: #0000FF; ">event</span>;<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;=&nbsp;enet_host_service(host,&nbsp;&amp;<span style="color: #0000FF; ">event</span>,&nbsp;timeout);<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(ret&nbsp;&gt;&nbsp;0){<br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(<span style="color: #0000FF; ">event</span>.peer&nbsp;!=&nbsp;peer){<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet&nbsp;receive&nbsp;peer&nbsp;is&nbsp;not&nbsp;matched");<br />
<span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;fail;<br />
<span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(<span style="color: #0000FF; ">event</span>.type&nbsp;!=&nbsp;ENET_EVENT_TYPE_RECEIVE){<br />
<span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet&nbsp;receive&nbsp;event&nbsp;type&nbsp;%d&nbsp;is&nbsp;not&nbsp;ENET_EVENT_TYPE_RECEIVE",&nbsp;<span style="color: #0000FF; ">event</span>.type);<br />
<span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">goto</span>&nbsp;fail;<br />
<span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*packet&nbsp;=&nbsp;<span style="color: #0000FF; ">event</span>.packet;<br />
<span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;（*packet)-&gt;dataLength;<br />
<span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">20</span>&nbsp;fail:<br />
<span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enet_packet_destroy(<span style="color: #0000FF; ">event</span>.packet);<br />
<span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">else</span>&nbsp;{<br />
<span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet&nbsp;receive&nbsp;%u&nbsp;millsecond&nbsp;%s",&nbsp;timeout,&nbsp;ret?"failure":"timeout");<br />
<span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">28</span>&nbsp;}<br />
<span style="color: #008080; ">29</span>&nbsp;<br />
<span style="color: #008080; ">30</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<span style="color: #993366; font-size: 12pt;"><strong>rudp_recv</strong></span>(ENetHost&nbsp;*host,&nbsp;ENetPeer&nbsp;*peer,&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;*buf,&nbsp;size_t&nbsp;maxlen,&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;timeout)&nbsp;<br />
<span style="color: #008080; ">31</span>&nbsp;{<br />
<span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENetPacket&nbsp;*packet;<br />
<span style="color: #008080; ">33</span>&nbsp;<br />
<span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(-1==<span style="color: #993366;">rudp_recvmsg</span>(host,&nbsp;peer,&nbsp;&amp;packet,&nbsp;timeout))<br />
<span style="color: #008080; ">35</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">36</span>&nbsp;<br />
<span style="color: #008080; ">37</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(packet-&gt;dataLength&nbsp;&gt;&nbsp;maxlen)&nbsp;{<br />
<span style="color: #008080; ">38</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet&nbsp;packet&nbsp;data&nbsp;length&nbsp;%d&nbsp;is&nbsp;greater&nbsp;than&nbsp;maxlen&nbsp;%lu",&nbsp;packet-&gt;dataLength,&nbsp;maxlen);<br />
<span style="color: #008080; ">39</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">40</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">41</span>&nbsp;<br />
<span style="color: #008080; ">42</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memcpy(buf,&nbsp;packet-&gt;data,&nbsp;packet-&gt;dataLength);<br />
<span style="color: #008080; ">43</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enet_packet_destroy(packet);<br />
<span style="color: #008080; ">44</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">45</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;packet-&gt;dataLength;<br />
<span style="color: #008080; ">46</span>&nbsp;}</div>
&nbsp;&nbsp;&nbsp;<br />
&nbsp; &nbsp;&#9670;&nbsp;<strong style="font-size: 12pt;">等待所有确认</strong>，若成功返回0，超时返回1，失败返回-1<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 14px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<strong style="color: #993366; font-size: 12pt;">rudp_wait_allack</strong>(ENetHost&nbsp;*host,&nbsp;ENetPeer&nbsp;*peer,&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;timeout)<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;ret,&nbsp;cnt&nbsp;=&nbsp;0;<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>((ret&nbsp;=&nbsp;enet_host_service(host,&nbsp;NULL,&nbsp;1))&nbsp;&gt;=&nbsp;0){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(enet_peer_is_empty_sent_reliable_commands(peer,&nbsp;0,&nbsp;<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ENET_PROTOCOL_COMMAND_SEND_RELIABLE|ENET_PROTOCOL_COMMAND_SEND_FRAGMENT))<br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;<br />
<span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(peer-&gt;state&nbsp;==&nbsp;<span style="color: #ff00ff;">ENET_PEER_STATE_ZOMBIE</span>){<br />
<span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet&nbsp;peer&nbsp;state&nbsp;is&nbsp;zombie");<br />
<span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(0==ret&nbsp;&amp;&amp;&nbsp;++cnt&gt;=timeout){<br />
<span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;1;<br />
<span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;"enet&nbsp;host&nbsp;service&nbsp;fail");<br />
<span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />
<span style="color: #008080; ">22</span>&nbsp;}</div>
&nbsp; &nbsp; 等待已发送数据的所有确认时，需根据对端状态判断是否断线<br />
<br />
<strong style="font-size: 13pt;">示例流程</strong>&nbsp; &nbsp;<br />
&nbsp; &nbsp;左边为客户端，压缩并传输文件；右边为服务端，接收并解压存储文件。<br />
&nbsp; &nbsp;<br /><img src="http://www.cppblog.com/images/cppblog_com/qinqing1984/rudp_trans_file_flow.png" alt="" /><br />&nbsp; &nbsp;客户端【读文件块并压缩】这个环节，需要显式创建可靠packet，并将压缩后的块拷贝到其中<img src ="http://www.cppblog.com/qinqing1984/aggbug/217279.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2020-05-04 19:08 <a href="http://www.cppblog.com/qinqing1984/archive/2020/05/04/217279.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>总结网络路由走向诊断方法</title><link>http://www.cppblog.com/qinqing1984/archive/2017/12/29/215452.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Fri, 29 Dec 2017 09:24:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2017/12/29/215452.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/215452.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2017/12/29/215452.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/215452.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/215452.html</trackback:ping><description><![CDATA[<div>由于traceroute只能诊断UDP通信的包路由，不能确定TCP通信的实际路由（可能变换），因此编写了本文。为方便描述，下面的IP、MAC和端口均为示例，实际诊断中可更换为具体的值</div>
<div></div>
<div><strong style="font-size: 12pt;"><br />
1. 如何判断客户端到服务器的TCP包，是否经过了网关</strong></div>
<div>&nbsp; &nbsp; &nbsp;在客户端执行 <span style="color: #0000ff;">tcpdump -i eno16777728 ether dst b0:b9:8a:69:65:3e and host 192.168.0.26 and tcp port 80</span>&nbsp; 抓取经过网关且往返服务器的TCP端口为80的包</div>
<div>&nbsp; &nbsp; &nbsp;eno16777728 接口名称；ether 以太网链路，dst 目标（src表示源）；b0:b9:8a:69:65:3e 网关MAC地址；192.168.0.26 服务器IP地址，80 监听端口</div>
<div><br />
&nbsp; &nbsp;&nbsp;&nbsp;<strong>输出结果分析<br />
</strong>&nbsp; &nbsp; &nbsp; &nbsp;&#9679; 有输出，则表示经过了网关</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp;&#9679;&nbsp;有部分输出而TCP通信还在进行，则表示先前的包经过了网关，后来路由表项缓存被重定向更新，没经过网关了</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp;&#9679;&nbsp;不断输出，则表示一直经过网关</div>
<div><br />
<strong style="font-size: 12pt;">2. 如何判断路由表项缓存被重定向更新</strong></div>
<div>&nbsp; &nbsp; &nbsp;在客户端执行 <span style="color: #0000ff;">tcpdump -i eno16777728 src 192.168.1.1 and dst 192.168.1.45 and icmp</span>&nbsp; 抓取来自网关和到达客户端的所有icmp包</div>
<div>&nbsp; &nbsp; &nbsp;192.168.1.1 网关IP；192.168.1.45 客户端（出口）IP</div>
<br />
<div>&nbsp; &nbsp; &nbsp;<strong>输出结果分析</strong></div>
<div>&nbsp; &nbsp; &nbsp; &nbsp;&#9679;&nbsp;没有输出，则表示没有收到rerdirect包，路由表项缓存不变</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp;&#9679;&nbsp;有输出类似<span style="color: #ff0000;">ICMP redirect 192.168.0.26 to host 192.168.0.2</span><span style="color: red;">6</span>（前面一个IP表示到达服务器的直接路由IP，后一个表示服务器IP）</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp;&#9679; 则表示收到了ICMP重定向包，内核会更新路由表项及缓存网关为192.168.0.26，下次通信时就直接发往192.168.0.26了</div>
<div><br />
<span style="font-size: 12pt;"><strong>3. 如何控制接收ICMP重定向</strong></span></div>
<div>&nbsp; &nbsp; &nbsp; &#9679;&nbsp;<span style="color: #0000ff;">echo 0 | tee /proc/sys/net/ipv4/conf/*/accept_redirects</span>&nbsp; &nbsp; 禁止所有网卡接收，可避免路由表项缓存被修改</div>
<div>&nbsp; &nbsp; &nbsp; &#9679;&nbsp;<span style="color: #0000ff;">echo 1 | tee /proc/sys/net/ipv4/conf/*/accept_redirects</span>&nbsp; &nbsp; 启用所有网卡接收ICMP重定向消息</div>
<div><br />
<strong style="font-size: 12pt;">4. 查看、刷新路由表项缓存</strong></div>
<div>&nbsp; &nbsp; &nbsp; &#9679;&nbsp;<span style="color: #0000ff;">ip route get 192.168.0.26</span>&nbsp; &nbsp; 可以从输出中看到通住目标IP的实际路由</div>
<div>&nbsp; &nbsp; &nbsp; &#9679;&nbsp;<span style="color: #0000ff;">ip route flush cache</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;清空路由表项缓存，下次通信时内核会查main表（即命令route输出的表）以确定路由</div><img src ="http://www.cppblog.com/qinqing1984/aggbug/215452.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2017-12-29 17:24 <a href="http://www.cppblog.com/qinqing1984/archive/2017/12/29/215452.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入理解SSL/TLS技术内幕</title><link>http://www.cppblog.com/qinqing1984/archive/2016/12/15/214491.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Thu, 15 Dec 2016 09:16:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2016/12/15/214491.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/214491.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2016/12/15/214491.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/214491.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/214491.html</trackback:ping><description><![CDATA[<strong style="font-size: 12pt">前言</strong><br />
&#160;&#160;&#160;近期有机会，深入了SSL/TLS协议原理与细节，并分析了相关密码学内容，心得颇多，历经半月，终于写成了这份文档。<br />
&#160;&#160;&#160;本人水平尚有限，错误难免，欢迎指正，不胜感激。<br />
<br />
<strong style="font-size: 12pt">目录</strong><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/deep-ssl-tls-catalogue.png" /><strong><br />
<br />
</strong><strong style="font-size: 12pt">部分章节预览</strong><br />
<strong>&#160;&#160;&#160;第3章</strong><br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/ssl-tls-protocol-stack.png" /></div>
<br />
<br />
&#160;&#160;&#160;<strong>第5章第4节</strong><br />

<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/ssl-tls-block-cipher.png" /></div>
<br />
<br />
&#160;&#160;&#160;<strong>第11章第3节<br />
</strong>
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/ssl-tls-freak-attack.png" /></div>
<br />
<strong style="font-size: 12pt">全文</strong><br />
&#160;&#160;&#160;下载地址：<a href="/Files/qinqing1984/深入理解SSL-TLS技术内幕.zip">深入理解SSL/TLS技术内幕</a>   <img src ="http://www.cppblog.com/qinqing1984/aggbug/214491.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2016-12-15 17:16 <a href="http://www.cppblog.com/qinqing1984/archive/2016/12/15/214491.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一种拦截Linux原始套接字IO的方法</title><link>http://www.cppblog.com/qinqing1984/archive/2016/07/14/213936.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Thu, 14 Jul 2016 02:27:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2016/07/14/213936.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/213936.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2016/07/14/213936.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/213936.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/213936.html</trackback:ping><description><![CDATA[<strong style="font-size: 14pt;">描述</strong><br />
&nbsp;&nbsp;&nbsp;原始套接字具有广泛的用途，特别是用于自定义协议（标准协议TCP、UDP和ICMP等外）的数据收发。在Linux下拦截套接字IO的一般方法是拦截对应的套接字系统调用，对于发送为sendmsg和sendto，对于接收为recvmsg和recvfrom。这种方法虽然也能拦截原始套接字IO，但要先判断套接字的类型，如果为SOCK_RAW（原始套接字类型），那么进行拦截处理，这样一来由于每次IO都要判断套接字类型，性能就比较低了。因此为了直接针对原始套接字来拦截，提高性能，发明了本方法。<br />
&nbsp;&nbsp;&nbsp;本方法可用于防火墙或主机防护系统中，丢弃接收和发送的攻击或病毒数据包。<br />
<br />
<strong style="font-size: 14pt">
特点</strong><br />
&nbsp;&nbsp;&nbsp;运行在内核态，直接拦截所有进程的原始套接字IO，支持IPv4和IPv6。<br />
<br />
<p><strong style="font-size: 14pt">
</strong></p>
<hr />
<strong style="font-size: 14pt">
实现</strong><br />
&nbsp;&nbsp;&nbsp;<strong style="font-size: 12pt">原理</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在Linux内核网络子系统中，struct proto_ops结构提供了协议无关的套接字层到协议相关的传输层的转接，而IPv4协议族中内置的inet_sockraw_ops为它的一个实例，对应着原始套接字。因此先找到inet_sockraw_ops，再替换它的成员函数指针recvmsg和sendmsg，就可以实现拦截了。下面以IPv4为例（IPv6同理），说明几个流程。<br />
<br />
&nbsp;&nbsp;&nbsp;<strong style="font-size: 12pt">搜索inet_sockraw_ops</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该流程在挂钩IO前进行。由于inet_sockraw_ops为Linux内核未导出的内部符号，因此需要通过特别的方法找到它，该特别的方法基于这样的一个事实：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 1pt">&#9670;</span> 所有原始套接字接口均存放在以SOCK_RAW为索引的双向循环链表中，而inet_sockraw_ops就在该链表的末尾。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 1pt">&#9670;</span> 内核提供了注册套接字接口的API inet_register_protosw，对于原始套接字类型，该API将输入的套接字接口插入到链表头后面。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;算法如下<br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/search_inet_sockraw_ops.png" width="198" height="420" /></div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;注册p前或注销p后，链表如下<br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/reg_before_rawsock_list.png" width="450" height="83" /></div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;注册p后，链表如下<br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/reg_after_rawsock_list.png" width="673" height="82" /></div>
<br />
<strong style="font-size: 12pt">&nbsp;&nbsp;&nbsp;挂钩IO</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该流程在内核模块启动时进行。<br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/hook_rawsock_io.png" width="196" height="458" /></div>
<br />
&nbsp;&nbsp;&nbsp;<strong style="font-size: 12pt">卸钩IO</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该流程在内核模块退出时进行。<br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/unhook_rawsock_io.png" width="191" height="460" /></div>
<br />
<strong style="font-size: 14pt">
<hr />
运行部署</strong><br />
&nbsp;&nbsp;&nbsp;该方法实现在Linux内核模块中，为了防止其它内核模块可能也注册了原始套接字接口，因此需要在操作系统启动时优先加载。&nbsp;&nbsp;<img src ="http://www.cppblog.com/qinqing1984/aggbug/213936.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2016-07-14 10:27 <a href="http://www.cppblog.com/qinqing1984/archive/2016/07/14/213936.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一种P2P代理中TCP连接调度的方法</title><link>http://www.cppblog.com/qinqing1984/archive/2016/07/12/213924.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Tue, 12 Jul 2016 08:59:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2016/07/12/213924.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/213924.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2016/07/12/213924.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/213924.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/213924.html</trackback:ping><description><![CDATA[<strong style="font-size: 14pt;">描述</strong><br />
&nbsp;&nbsp;&nbsp;在P2P应用系统中，当需要与处于不同私网的对方可靠通信时，先尝试TCP打洞穿透，若穿透失败，再通过处于公网上的代理服务器（下文简称proxy）转发与对方通信，如下图所示&nbsp;&nbsp;
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/p2p_comm_arch.png" width="557" height="311" /></div>
&nbsp;&nbsp;&nbsp;终端A先连接并发消息msg1到proxy（连接为c1）；proxy再发消息msg2给P2P服务器，P2P服务器收到消息后通过已有的连接发消息msg3给终端B，B收到msg3后，连接并发消息msg4到proxy（连接为c2）。这4个消息格式由应用层协议决定，但必须遵守的规范如下：<br />
&nbsp;&nbsp;&nbsp;<span style="font-size: 6pt">&#9670;</span> msg1至少包含B的设备ID。<br />
&nbsp;&nbsp;&nbsp;<span style="font-size: 6pt">&#9670;</span> msg2至少包含B的设备ID和c1的连接ID。<br />
&nbsp;&nbsp;&nbsp;<span style="font-size: 6pt">&#9670;</span> msg3至少包含c1的连接ID和连接代理指示。<br />
&nbsp;&nbsp;&nbsp;<span style="font-size: 6pt">&#9670;</span> msg4至少包含B的设备ID和c1的连接ID。<br />
&nbsp;&nbsp;&nbsp;proxy为多线程架构，当接受到若干连接时，如果数据相互转发的两个连接（比如上图中的c1和c2）不在同一线程，由于一个连接写数据到另一连接的发送队列，而另一连接从发送队列读数据以发送，那么就要对另一连接的发送队列（或缓冲区）加锁，这样一来由于频繁的网络IO而频繁地加解锁，降低了转发效率，因此为了解决这一问题，就需要调度TCP连接到同一线程。 <br />
<br />
<hr />
<strong style="font-size: 14pt">特点</strong><br />
&nbsp;&nbsp;&nbsp;本方法能将数据转发的两边连接放在同一线程，从而避免了数据转发时的加锁，由于是一对一的连接匹配，因此也做到了每个线程中连接数的均衡。<br />
<br />
<hr />
<strong style="font-size: 14pt">实现</strong><br />
&nbsp;&nbsp;&nbsp;<strong style="font-size: 12pt">工作原理</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy的主线程负责绑定知名端口并监听连接，工作线程负责数据转发。当接受到一个连接时，按轮转法调度它到某个工作线程，在那个线程内接收分析应用层协议数据，以识别连接类型，即判断连接是来自数据请求方还是数据响应方，为统一描述，这里把前者特称为客户连接，后者为服务连接，连接所在的线程为宿主线程。如果是客户连接，那么先通知P2P服务器请求对应的客户端来连接代理，并等待匹配；如果是服务连接，那么就去匹配客户连接，在匹配过程中，如果服务连接和客户连接不在同一线程内，那么就会调度到客户连接的宿主线程，匹配成功后，就开始转发数据。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了加快查找，分2个hash表存放连接，客户连接放在客户连接hash表中，以连接ID为键值；服务连接放在服务连接hash表中，以设备ID为键值。<br />
<br />
&nbsp;&nbsp;&nbsp;<strong style="font-size: 12pt">TCP连接调度<br />
</strong>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;包括新连接的轮转、识别连接类型、匹配客户连接1、匹配客户连接2和关闭连接共5个流程，如下一一所述。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>新连接的轮转</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该流程工作在主线程，如下图所示<br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/new_conn_round_robin.png" /></div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;索引i初始为0，对于新来的连接，由于还不明确连接类型，所以先放入客户连接表中。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>识别连接类型</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该流程工作在工作线程，当接受到一个连接时开始执行，如下图所示
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/recognition_conn.png" /></div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当连接类型为服务连接时，从客户连接表转移到服务连接表。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>匹配客户连接1</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该流程工作在工作线程，当接受到一个服务连接时开始执行，如下图所示<br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/match_client_conn_1.png" /></div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>匹配客户连接2</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该流程工作在工作线程，当服务连接移到客户连接的宿主线程时开始执行，如下图所示<br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/match_client_conn_2.png" /></div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这里的流程和匹配客户连接流程1有些类似，看起来好像做了重复的判断操作，但这是必要的，因为在服务连接转移到另一线程这个瞬间内，客户连接有可能断开了，也有可能断开后又来了一个相同连接ID的其它客户连接，所以要重新去客户连接表查找一次，然后进行4个分支判断。&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>关闭连接</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该流程工作在工作线程内，当连接断开或空闲时执行。当一边读数据出错时，不能马上关闭另一边连接，得在另一边缓冲区数据发送完后才能关闭；当一边连接写数据出错时，可以马上关闭另一边连接，如下图所示<br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/p2p_close_conn.png" /></div><img src ="http://www.cppblog.com/qinqing1984/aggbug/213924.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2016-07-12 16:59 <a href="http://www.cppblog.com/qinqing1984/archive/2016/07/12/213924.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TCP分组丢失时的状态变迁</title><link>http://www.cppblog.com/qinqing1984/archive/2015/10/05/211950.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Sun, 04 Oct 2015 16:44:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2015/10/05/211950.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/211950.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2015/10/05/211950.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/211950.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/211950.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;本文根据RFC793协议规范和BSD 4.4的实现，总结了<span style="color: red;">TCP分组丢失时</span>的状态变迁，如下图所示：实线箭头表示客户端的状态变迁，线段虚线箭头表示服务端的状态变迁，圆点虚线箭头表示客户端或服务端的状态变迁；黑色文字表示正常时的行为，红色文字表示分组丢失时的行为。
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/tcp_lose_packet_state.PNG" /></div>
<br />
&nbsp;&nbsp;&nbsp;这里假设重传时分组依然会丢失，当在不同状态（CLOSED除外）分组丢失后，最终会关闭套接字而回到CLOSED状态。下面逐个分析各状态时的情景。<br />
<br />
<strong>SYN_SENT</strong><br />
&nbsp;&nbsp;&nbsp;连接阶段第1次握手，客户端发送的SYN分组丢失，因此超时收不到服务端的SYN+ACK而重传SYN，尝试几次后放弃，关闭套接字。<br />
<br />
<strong>SYN_RCVD</strong><br />
&nbsp;&nbsp;&nbsp;1）连接阶段第2次握手，服务端响应的SYN+ACK分组丢失，因此超时收不到客户端的ACK而重传SYN+ACK，尝试几次后放弃，发送RST并关闭套接字。<br />
&nbsp;&nbsp;&nbsp;2）连接阶段第3次握手，客户端发送的ACK分组丢失，因此服务端超时收不到ACK而重传SYN+ACK，尝试几次后放弃，发送RST并关闭套接字。<br />
&nbsp;&nbsp;&nbsp;3）同时打开第2次握手，本端响应的SYN+ACK分组丢失，因此对端超时收不到SYN+ACK而重传SYN、尝试几次后放弃、发送RST并关闭套接字，而此时本端收到RST。<br />
<br />
<strong>ESTABLISHED</strong><br />
&nbsp;&nbsp;&nbsp;1）连接阶段第3次握手，客户端发送ACK分组后，虽然丢失但会进入该状态（因为ACK不需要确认），但此时服务端还处于SYN_RCVD状态，因为超时收不到客户端的ACK而重传SYN+ACK、尝试几次后放弃、发送RST并关闭套接字，而此时客户端收到RST。<br />
&nbsp;&nbsp;&nbsp;2）数据传输阶段，本端发送的Data分组丢失，因此超时收不到对数据的确认而重传、尝试几次后放弃、发送RST并关闭套接字，而此时对端收到RST。<br />
<br />
<strong>FIN_WAIT_1</strong><br />
&nbsp;&nbsp;&nbsp;1）关闭阶段第1次握手，客户端发送的FIN分组丢失，因此超时收不到服务端的ACK而重传FIN，尝试几次后放弃，发送RST并关闭套接字。<br />
&nbsp;&nbsp;&nbsp;2）关闭阶段第2次握手，服务端响应的ACK分组丢失，因此客户端超时收不到ACK而重传FIN，尝试几次后放弃，发送RST并关闭套接字。<br />
&nbsp;<br />
<strong>FIN_WAIT_2</strong><br />
&nbsp;&nbsp;&nbsp;关闭阶段第3次握手，服务端发送的FIN分组丢失，因此超时收不到客户端的ACK而重传FIN、尝试几次后放弃、发送RST并关闭套接字，而此时客户端收到RST。<br />
&nbsp;<br />
<strong>CLOSING</strong><br />
&nbsp;&nbsp;&nbsp;同时关闭第2次握手，本端发送的ACK分组丢失，导致对端超时收不到ACK而重传FIN、尝试几次后放弃、发送RST并关闭套接字，而此时本端收到RST。 <br />
<br />
<strong>TIME_WAIT</strong><br />
&nbsp;&nbsp;&nbsp;关闭阶段第4次握手，客户端响应的ACK分组丢失，导致服务端超时收不到ACK而重传FIN、尝试几次后放弃、发送RST并关闭套接字，而此时客户端收到RST。 <br />
<br />
<strong>CLOSE_WAIT</strong><br />
&nbsp; &nbsp;关闭阶段第2次握手，服务端响应的ACK分组丢失，导致客户端超时收不到ACK而重传FIN、尝试几次后放弃、发送RST并关闭套接字，而此时服务端收到RST。<br />
<br />
<strong>LAST_ACK</strong><br />
&nbsp; &nbsp;关闭阶段第3次握手，服务端发送的FIN分组丢失，导致超时收不到客户端的ACK而重传FIN、尝试几次后放弃、发送RST并关闭套接字。
<img src ="http://www.cppblog.com/qinqing1984/aggbug/211950.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2015-10-05 00:44 <a href="http://www.cppblog.com/qinqing1984/archive/2015/10/05/211950.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux ICMP消息的产生与转换</title><link>http://www.cppblog.com/qinqing1984/archive/2015/05/18/210684.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Mon, 18 May 2015 11:52:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2015/05/18/210684.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/210684.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2015/05/18/210684.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/210684.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/210684.html</trackback:ping><description><![CDATA[&nbsp; &nbsp;ICMP在IP系统间传递差错和管理报文，是任何IP系统必须实现的组成部分。Linux 2.6.34中ICMP模块的实现在linux/icmp.h，net/icmp.h和ipv4/icmp.c中，导出了<span style="color: red">icmp_err_convert</span>数组和<span style="color: red">icmp_send</span>函数，供其它网络子系统使用。在其它网络子系统中，当检测到错误时，调用icmp_send产生并发送相应的ICMP差错消息到源主机；当源主机收到ICMP不可达差错消息，传递到原始套接字和传输层，而它们使用icmp_err_convert把对应的消息代码转换成套接字层比较容易理解的错误代码。在内核空间中可发送的ICMP消息包括查询应答和差错报文，下面总结了产生这两类消息的网络子系统（及函数）与错误转换。<br />
<br />
<hr />
<strong style="font-size: 12pt">应答消息</strong><br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/icmp_query_msg.png" /></div>
&nbsp;&nbsp;&nbsp;应答消息由ICMP模块的内部函数icmp_reply而非icmp_send发送。根据<a href="https://tools.ietf.org/html/rfc1122#page-45" target="_blank">RFC1122 3.2.2.9</a>规范，&nbsp;除非一个主机作为地址掩码代理，否则不能发送回复，这对应ICMP的icmp_address实现为空，因此上表没有列出地址掩码应答项（内核符号为ICMP_ADDRESSREPLY）。<br />
<br />
<strong style="font-size: 12pt"><a id="icmp_error_msg">差错消息</a></strong><br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/icmp_error_msg.png" /></div>
&nbsp;&nbsp;&nbsp;差错消息由中间路由器或目的主机产生，当数据报不能成功提交给目的主机时。从上表可见，在IP层的接收、本地处理、转发和输出各过程中，都可能产生差错消息；在传输层如果对应的端口没有打开，那么UDP会产生ICMP端口不可达差错，而<span style="color: red;">TCP则会使用自己的差错处理机制发送一个RST复位包，这也是上表没有列出TCP子系统的原因</span>。对于重定向差错，由ICMP模块的icmp_redirect调用ip_rt_redirect更新路由；其它差错则由icmp_unreach处理。<br />
<br />
<hr />
<strong style="font-size: 12pt">错误转换</strong><br />
<div align="center"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/qinqing1984/icmp_err_convert.png" /></div>
&nbsp;&nbsp;&nbsp;第2列为icmp_err_convert数组索引，第4列也就是调用socket API出错时返回的errno，最后1列为icmp_err_convert中的fatal成员取值，0表示非致命错误，1表示致命错误，需要报告给用户进程。错误转换会被RAW的raw_err、TCP的tcp_v4_err和UDP的udp_err用到，对于ICMP_DEST_UNREACH类型的差错，使用上表转换；ICMP_SOURCE_QUENCH类型的忽略不处理；ICMP_PARAMETERPROB类型的转换成<span style="color: red">EPROTO</span>（协议错误）；ICMP_TIME_EXCEEDED类型的转换成<span style="color: red">EHOSTUNREACH</span>。<br />
&nbsp;&nbsp;&nbsp;在这要注意，从ICMP_PORT_UNREACH到ECONNREFUSED的转换，不适用于TCP，原因已在<a href="#icmp_error_msg">上节</a>说明；而对于UDP的<span style="color: red">未连接</span>套接字，如果主机在线而端口没打开，调用sendto得不到ECONNREFUSED错误，但recvfrom会阻塞，这是因为虽然内核收到了ICMP差错，但没上报给应用进程。尽管如此，如果想得到ECONNREFUSED错误，那么可以写个ICMP守护进程，应用进程先把它的套接字描述符通过unix域套接口传递到ICMP守护进程，而守护进程使用raw socket来接收ICMP差错，再发给应用进程。<span style="color: red"><br />
</span><br />
<hr />
<strong style="font-size: 12pt">发送限速</strong><br />
&nbsp;&nbsp;&nbsp;不论一般差错消息还是重定向差错消息，发送限速针对的都是特定目标主机。<br />
&nbsp;&nbsp;&nbsp;<strong>一般限速</strong><br />
&nbsp;&nbsp;&nbsp;在使用icmp_send发送差错消息（PMTU消息除外）时，为减少网络拥塞而限制了发送的速率，限速由xrlim_allow函数实现，定义在ipv4/icmp.c中。<br />
<div align="center">
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px">
<div align="left"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080">&nbsp;1</span><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;</span><span style="color: red">XRLIM_BURST_FACTOR</span><span style="color: #000000">&nbsp;6</span><span style="color: #000000"><br />
</span><span style="color: #008080">&nbsp;2</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;</span><span style="color: #800000"><strong>xrlim_allow</strong>(</span><span style="color: #0000ff">struct</span><span style="color: #000000">&nbsp;dst_entry&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">dst,&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;timeout)<br />
</span><span style="color: #008080">&nbsp;3</span><span style="color: #000000"><img id="Codehighlighter1_81_394_Open_Image" onclick="this.style.display='none'; Codehighlighter1_81_394_Open_Text.style.display='none'; Codehighlighter1_81_394_Closed_Image.style.display='inline'; Codehighlighter1_81_394_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_81_394_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_81_394_Closed_Text.style.display='none'; Codehighlighter1_81_394_Open_Image.style.display='inline'; Codehighlighter1_81_394_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_81_394_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_81_394_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">&nbsp;4</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="color: #0000ff">long</span><span style="color: #000000">&nbsp;now,&nbsp;token&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;dst</span><span style="color: #000000">-&gt;</span><span style="color: #000000">rate_tokens;<br />
</span><span style="color: #008080">&nbsp;5</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;rc&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br />
</span><span style="color: #008080">&nbsp;6</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><br />
</span><span style="color: #008080">&nbsp;7</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;now&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;jiffies;<br />
</span><span style="color: #008080">&nbsp;8</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;token&nbsp;</span><span style="color: #000000">+=</span><span style="color: #000000">&nbsp;now&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;dst</span><span style="color: #000000">-&gt;</span><span style="color: #000000">rate_last;<br />
</span><span style="color: #008080">&nbsp;9</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;dst</span><span style="color: #000000">-&gt;</span><span style="color: #000000">rate_last&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;now;<br />
</span><span style="color: #008080">10</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(token&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: red">XRLIM_BURST_FACTOR&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;timeout)<br />
</span><span style="color: #008080">11</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;token&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;XRLIM_BURST_FACTOR&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;timeout;<br />
</span><span style="color: #008080">12</span><span style="color: #000000"><img id="Codehighlighter1_320_353_Open_Image" onclick="this.style.display='none'; Codehighlighter1_320_353_Open_Text.style.display='none'; Codehighlighter1_320_353_Closed_Image.style.display='inline'; Codehighlighter1_320_353_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_320_353_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_320_353_Closed_Text.style.display='none'; Codehighlighter1_320_353_Open_Image.style.display='inline'; Codehighlighter1_320_353_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(token&nbsp;</span><span style="color: #000000">&gt;=</span><span style="color: #000000">&nbsp;timeout)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_320_353_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_320_353_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">13</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;token&nbsp;</span><span style="color: #000000">-=</span><span style="color: #000000">&nbsp;timeout;<br />
</span><span style="color: #008080">14</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rc&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">1</span><span style="color: #000000">;<br />
</span><span style="color: #008080">15</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">16</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;dst</span><span style="color: #000000">-&gt;</span><span style="color: #000000">rate_tokens&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;token;<br />
</span><span style="color: #008080">17</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;rc;<br />
</span><span style="color: #008080">18</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span></div>
</div>
</div>
&nbsp;&nbsp;&nbsp;dst为目标路由缓存，timeout为允许发送的超时（单位为jiffies），dst-&gt;rate_tokens记录令牌的个数，当令牌个数不小于timeout时，则减少timeout并允许发送一个消息；反之则不能发送，需等到令牌个数累积到大于timeout时才能发送，但是不能无限大，否则就会导致在一个可能很短的timeout内，发送远多于6个的消息，引起ICMP风暴，所以这里限制了令牌的最大值为XRLIM_BURST_FACTOR*timeout即6倍的超时，也就是说在一个timeout内，最多能发送6个差错消息。&nbsp;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<strong>重定向限速</strong><br />
&nbsp;&nbsp;&nbsp;路由子系统使用ip_rt_send_redirect来发送重定向消息，定义在ipv4/route.c中，该函数内部调用icmp_send实现，在它的限速基础上，使用<span style="color: red;">指数回退算法</span>控制发送速率。<br />
<div align="center">
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px">
<div align="left"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080">&nbsp;1</span><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;</span><span style="color: #800000"><strong>ip_rt_send_redirect</strong></span><span style="color: #000000">(</span><span style="color: #0000ff">struct</span><span style="color: #000000">&nbsp;sk_buff&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">skb)<br />
</span><span style="color: #008080">&nbsp;2</span><span style="color: #000000"><img id="Codehighlighter1_46_1149_Open_Image" onclick="this.style.display='none'; Codehighlighter1_46_1149_Open_Text.style.display='none'; Codehighlighter1_46_1149_Closed_Image.style.display='inline'; Codehighlighter1_46_1149_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_46_1149_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_46_1149_Closed_Text.style.display='none'; Codehighlighter1_46_1149_Open_Image.style.display='inline'; Codehighlighter1_46_1149_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_46_1149_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_46_1149_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">&nbsp;3</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">struct</span><span style="color: #000000">&nbsp;rtable&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">rt&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;skb_rtable(skb);<br />
</span><span style="color: #008080">&nbsp;4</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp; &nbsp;&nbsp;</span></span>&nbsp; &nbsp;<img alt="" src="http://www.cppblog.com/Images/dot.gif" /></div>
<div align="left"><span><font color="#008080">&nbsp;5</font><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><br />
<font color="#008080">&nbsp;6</font><img id="Codehighlighter1_343_427_Open_Image" onclick="this.style.display='none'; Codehighlighter1_343_427_Open_Text.style.display='none'; Codehighlighter1_343_427_Closed_Image.style.display='inline'; Codehighlighter1_343_427_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_343_427_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_343_427_Closed_Text.style.display='none'; Codehighlighter1_343_427_Open_Image.style.display='inline'; Codehighlighter1_343_427_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;<span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_343_427_Closed_Text">/**/</span><span id="Codehighlighter1_343_427_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">&nbsp;No&nbsp;redirected&nbsp;packets&nbsp;during&nbsp;ip_rt_redirect_silence;<br />
</span><span style="color: #008080">&nbsp;7</span><span style="color: #008000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;reset&nbsp;the&nbsp;algorithm.<br />
</span><span style="color: #008080">&nbsp;8</span><span style="color: #008000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">&nbsp;9</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(time_after(jiffies,&nbsp;rt</span><span style="color: #000000">-&gt;</span><span style="color: #000000">u.dst.rate_last&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #ff0000">ip_rt_redirect_silence</span><span style="color: #000000">))<br />
</span><span style="color: #008080">10</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rt</span><span style="color: #000000">-&gt;</span><span style="color: #000000">u.dst.rate_tokens&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br />
</span><span style="color: #008080">11</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><br />
</span><span style="color: #008080">12</span><span style="color: #000000"><img id="Codehighlighter1_532_647_Open_Image" onclick="this.style.display='none'; Codehighlighter1_532_647_Open_Text.style.display='none'; Codehighlighter1_532_647_Closed_Image.style.display='inline'; Codehighlighter1_532_647_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_532_647_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_532_647_Closed_Text.style.display='none'; Codehighlighter1_532_647_Open_Image.style.display='inline'; Codehighlighter1_532_647_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_532_647_Closed_Text">/**/</span><span id="Codehighlighter1_532_647_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">&nbsp;Too&nbsp;many&nbsp;ignored&nbsp;redirects;&nbsp;do&nbsp;not&nbsp;send&nbsp;anything<br />
</span><span style="color: #008080">13</span><span style="color: #008000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;set&nbsp;u.dst.rate_last&nbsp;to&nbsp;the&nbsp;last&nbsp;seen&nbsp;redirected&nbsp;packet.<br />
</span><span style="color: #008080">14</span><span style="color: #008000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">15</span><span style="color: #000000"><img id="Codehighlighter1_702_748_Open_Image" onclick="this.style.display='none'; Codehighlighter1_702_748_Open_Text.style.display='none'; Codehighlighter1_702_748_Closed_Image.style.display='inline'; Codehighlighter1_702_748_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_702_748_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_702_748_Closed_Text.style.display='none'; Codehighlighter1_702_748_Open_Image.style.display='inline'; Codehighlighter1_702_748_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(rt</span><span style="color: #000000">-&gt;</span><span style="color: #000000">u.dst.rate_tokens&nbsp;</span><span style="color: #000000">&gt;=</span><span style="color: #000000">&nbsp;</span><span style="color: #ff0000">ip_rt_redirect_number</span><span style="color: #000000">)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_702_748_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_702_748_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">16</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rt</span><span style="color: #000000">-&gt;</span><span style="color: #000000">u.dst.rate_last&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;jiffies;<br />
</span><span style="color: #008080">17</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">;<br />
</span><span style="color: #008080">18</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">19</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><br />
</span><span style="color: #008080">20</span><span style="color: #000000"><img id="Codehighlighter1_752_827_Open_Image" onclick="this.style.display='none'; Codehighlighter1_752_827_Open_Text.style.display='none'; Codehighlighter1_752_827_Closed_Image.style.display='inline'; Codehighlighter1_752_827_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_752_827_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_752_827_Closed_Text.style.display='none'; Codehighlighter1_752_827_Open_Image.style.display='inline'; Codehighlighter1_752_827_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_752_827_Closed_Text">/**/</span><span id="Codehighlighter1_752_827_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">&nbsp;Check&nbsp;for&nbsp;load&nbsp;limit;&nbsp;set&nbsp;rate_last&nbsp;to&nbsp;the&nbsp;latest&nbsp;sent<br />
</span><span style="color: #008080">21</span><span style="color: #008000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;redirect.<br />
</span><span style="color: #008080">22</span><span style="color: #008000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">23</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(rt</span><span style="color: #000000">-&gt;</span><span style="color: #000000">u.dst.rate_tokens&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">||&nbsp;</span><span style="color: #000000">time_after(jiffies,&nbsp;</span><span style="color: #000000">(rt</span><span style="color: #000000">-&gt;</span><span style="color: #000000">u.dst.rate_last&nbsp;</span><span style="color: #000000">+&nbsp;</span><span style="color: #000000">(</span><span style="color: #ff0000">ip_rt_redirect_load&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;rt</span><span style="color: #000000">-&gt;</span><span style="color: #000000">u.dst.rate_tokens))))&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_974_1147_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_974_1147_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">24</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #ff0000">&nbsp;icmp_sen</span><span style="color: #ff0000">d</span><span style="color: #000000">(skb,&nbsp;ICMP_REDIRECT,&nbsp;ICMP_REDIR_HOST,&nbsp;rt</span><span style="color: #000000">-&gt;</span><span style="color: #000000">rt_gateway);<br />
</span><span style="color: #008080">25</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rt</span><span style="color: #000000">-&gt;</span><span style="color: #000000">u.dst.rate_last&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;jiffies;<br />
</span><span style="color: #008080">26</span><span style="color: #000000"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">++</span><span style="color: #000000">rt</span><span style="color: #000000">-&gt;</span><span style="color: #000000">u.dst.rate_tokens;</span><span style="color: #000000"><br />
</span><span style="color: #000000"><font color="#008080">27</font><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span style="color: #000000"><br />
</span><font color="#008080">28</font><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #000000"><br />
</span><font color="#008080">29</font><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></div>
</div>
</div>
&nbsp;&nbsp;&nbsp;重定向差错使用ip_rt_redirect_silence（默认为(HZ/50)&lt;&lt;10）、ip_rt_redirect_number（默认为9）和ip_rt_redirect_load（默认为HZ/50）3个量来控制发送的速率；rt-&gt;u.dst.rate_last记录上次发送的时间，rt-&gt;u.dst.rate_tokens累计发送总数，最大值为ip_rt_redirect_number；当两次发送的时间间隔超过ip_rt_redirect_silence或ip_rt_redirect_load&lt;&lt;rt-&gt;u.dst.rate_tokens，并且发送总数不超过ip_rt_redirect_number时，才允许发送一个，这样一来，在ip_rt_redirect_silence间隔内，每次发送的超时呈2的指数增长，达到了变减速发送的效果，直到总数达到ip_rt_redirect_number时停止发送，这是因为源主机可能忽略了重定向消息所以停止发送；当ip_rt_redirect_silence时间过后，又允许发送了，这是因为认为源主机没有更新路由所以又需要发送。<img src ="http://www.cppblog.com/qinqing1984/aggbug/210684.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2015-05-18 19:52 <a href="http://www.cppblog.com/qinqing1984/archive/2015/05/18/210684.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux套接字与虚拟文件系统（2）：操作和销毁</title><link>http://www.cppblog.com/qinqing1984/archive/2015/05/03/210522.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Sun, 03 May 2015 08:55:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2015/05/03/210522.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/210522.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2015/05/03/210522.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/210522.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/210522.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;&nbsp;接上篇初始化与创建，本篇阐述Socket操作和销毁两部分的实现。Socket操作&nbsp;&nbsp;&nbsp;系统调用read(v)、write(v)是用户空间读写socket的一种方法，为了弄清楚它们是怎么通过VFS将请求转发到特定协议的实现，下面以read为例（write同理），并假定文件描述符对应的是IPv4 TCP类型的socket...&nbsp;&nbsp;<a href='http://www.cppblog.com/qinqing1984/archive/2015/05/03/210522.html'>阅读全文</a><img src ="http://www.cppblog.com/qinqing1984/aggbug/210522.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2015-05-03 16:55 <a href="http://www.cppblog.com/qinqing1984/archive/2015/05/03/210522.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux套接字与虚拟文件系统（1）：初始化和创建</title><link>http://www.cppblog.com/qinqing1984/archive/2015/05/03/210521.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Sun, 03 May 2015 08:31:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2015/05/03/210521.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/210521.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2015/05/03/210521.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/210521.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/210521.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 引言&nbsp;&nbsp;&nbsp;在Unix的世界里，万物皆文件，通过虚拟文件系统VFS，程序可以用标准的Unix系统调用对不同的文件系统，甚至不同介质上的文件系统进行读写操作。对于网络套接字socket也是如此，除了专属的Berkeley Sockets API，还支持一些标准的文件IO系统调用如read(v)、write(v)和close等。那么为什么socket也支持文件IO系统调...&nbsp;&nbsp;<a href='http://www.cppblog.com/qinqing1984/archive/2015/05/03/210521.html'>阅读全文</a><img src ="http://www.cppblog.com/qinqing1984/aggbug/210521.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2015-05-03 16:31 <a href="http://www.cppblog.com/qinqing1984/archive/2015/05/03/210521.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HTTP URI编解码</title><link>http://www.cppblog.com/qinqing1984/archive/2015/02/10/191972.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Tue, 10 Feb 2015 10:40:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2015/02/10/191972.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/191972.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2015/02/10/191972.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/191972.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/191972.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 字符集合&nbsp;&nbsp;&nbsp;&nbsp;依据RFC3986 2规范，HTTP URI中允许出现的US-ASCII字符的子集，可以分成保留、未保留及转义这几类，每类的全部字符列表如下&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#9679; 保留: &nbsp;: / ? # [ ] @ ! $ &amp; '( ) * + ,; =共18个，一般...&nbsp;&nbsp;<a href='http://www.cppblog.com/qinqing1984/archive/2015/02/10/191972.html'>阅读全文</a><img src ="http://www.cppblog.com/qinqing1984/aggbug/191972.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2015-02-10 18:40 <a href="http://www.cppblog.com/qinqing1984/archive/2015/02/10/191972.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于OpenSSL实现的安全连接</title><link>http://www.cppblog.com/qinqing1984/archive/2014/04/11/206536.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Fri, 11 Apr 2014 09:26:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2014/04/11/206536.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/206536.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2014/04/11/206536.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/206536.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/206536.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; &nbsp;Web服务器为了支持https访问，通常会使用第三方库openssl实现，而且为了高性能采用异步事件驱动模型，因此连接套接字被设为非阻塞类型，本文在nginx ssl模块的基础上，简化提取它的核心框架，使用面向对象的方式描述，从握手、读写和关闭3个方面进行了分析，由于这3个操作都是异步的，因此操作失败后要调用SSL_get_error来获取错误码，有如下4种情况。&n...&nbsp;&nbsp;<a href='http://www.cppblog.com/qinqing1984/archive/2014/04/11/206536.html'>阅读全文</a><img src ="http://www.cppblog.com/qinqing1984/aggbug/206536.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2014-04-11 17:26 <a href="http://www.cppblog.com/qinqing1984/archive/2014/04/11/206536.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TCP/IP FAQ （2）：插口层和应用层</title><link>http://www.cppblog.com/qinqing1984/archive/2013/09/03/202876.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Tue, 03 Sep 2013 07:52:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2013/09/03/202876.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/202876.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2013/09/03/202876.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/202876.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/202876.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;继上篇<a href="http://www.cppblog.com/qinqing1984/archive/2013/08/25/202734.html" target="_blank">TCP/IP FAQ（1）</a>，本篇涵盖了域和协议、IP编址、插口、原始IP、unix域方面的问题与解答。<br />
<span style="color: #ff6600; font-size: 12pt"><br />
【Domain &amp; Protocol】</span><br />
<span style="color: #008000"><strong>1. 什么是域，它和协议有什么关系?</strong></span><br />
&nbsp;&nbsp;&nbsp;域可以理解为一种容纳协议的空间，它的存在便于了协议的分类；域和协议是集合与元素的关系，一个域中的每个协议使用同类地址，并且每种地址只被一个域使用，一个域能由协议族或地址族常量唯一标识。<br />
<span style="color: #008000"><strong>2. TCP/IP中有哪些域及其协议？</strong></span><br />
&nbsp;&nbsp;&nbsp;internet、iso、route、ccitt、imp、network systems和unix，其中internet域含有ip,icmp,igmp,tcp和udp五种协议，unix域用于ipc通信。<br />
<span style="color: #008000"><strong>3. 哪些地方会用到域？</strong></span><br />
&nbsp; &nbsp;一个网络层协议必须分用输入数据报，并交给相应的传输层协议，由于域包含了协议族，因此必须从对应的域中找到合适的协议去处理。例如IP对应的域为internet，这个域对应的协议族为inetsw，当收到IP数据报时，就从inetsw中找到对应的传输层协议去输入处理。<br />
<br />
<span style="color: #ff6600; font-size: 12pt">【IP Addressing】</span><br />
<span style="color: #008000"><strong>1. IP地址有哪几类？</strong></span><br />
&nbsp;&nbsp;&nbsp;分为5类，A、B和C类用于单播；D类用于多播；E类用于实验。<br />
<span style="color: #008000"><strong>2. sockaddr和sockaddr_in有什么区别联系？</strong></span><br />
&nbsp;&nbsp;&nbsp;sockaddr是一种通用的用于接口编址信息的结构，它将硬件与协议的地址细节相对于接口层隐藏起来，成员依次为sa_len、sa_family和sa_data，而sockaddr_in成员依次为sin_len、sin_family、sin_port、sin_addr和sin_zero。它们的前两个成员其实是一样的，只是命名不同，而sockaddr_in中的sin_port标识传输层的端口，sin_addr标识IP层的地址，所以它是Internet协议的专用接口编址结构，sin_zero仅为填充用，因为sockaddr_in长度不应小于sockaddr。<br />
<span style="color: #008000"><strong>3. 插口编址结构允许的最大长度是多少？</strong></span><br />
&nbsp;&nbsp;&nbsp;sockaddr最后一个成员是可扩展的，这是C语言的通用技术，因为其第一个成员为u_char类型，所以最大长度是255。<br />
<span style="color: #008000"><strong>4. 一个接口可以配置多个IP地址，是怎么实现的？</strong></span><br />
&nbsp;&nbsp;&nbsp;ifaddr表示通用的接口地址，ifnet表示接口，它有个类型为ifaddr*的if_addrlist成员，表示当前接口上的地址链表。in_ifaddr表示Internet协议专用的接口地址，而IP属于Internet协议，因此用in_ifaddr表示，所有的IP地址组成一个类型为in_ifaddr*的链表。当增加一个IP地址时，就需要插入这两个链表中；当删除一个IP地址时，就需要从它们当中移除。<br />
<span style="color: #008000"><strong>5. 为什么配置IP主机地址和网络掩码可以是独立的？</strong></span><br />
&nbsp;&nbsp;&nbsp;因为它们使用不同的命令实现，前者用SIOCSIFADDR，后者用SIOCSIFNETMASK。当配置IP主机地址时，如果没有指明网络掩码，那么网络掩码被设置成默认的。<br />
<span style="color: #008000"><strong>6. 为什么访问IP接口地址使用的是UDP插口而不是原始IP插口？</strong></span><br />
&nbsp;&nbsp;&nbsp;只有超级用户用程才能创建原始IP插口，而通过UDP插口，任何用户进程都能查看接口配置。<br />
<br />
<span style="color: #ff6600; font-size: 12pt">【Socket】</span><br />
<span style="color: #008000"><strong>1. 为什么会存在插口层？</strong></span><br />
&nbsp; &nbsp;从概念上讲，tcp/ip协议栈划分为链路、网络、传输和应用4层；但从实现上讲，在应用层和其下层中间，引入了一个插口层，作为进程和内核通信的桥梁，主要功能是将进程发送的与协议有关的请求映射到产生插口时指定的与协议有关的实现，从而屏蔽了不同协议处理的细节。<br />
<span style="color: #008000"><strong>2. 为什么服务器进程总是要调用bind，客户进程能调用它吗？</strong></span><br />
&nbsp; &nbsp;bind将一个本地地址同一个插口相关联，客户进程需要同一个已知地址建立连接或发送数据报到已知地址，如果不调用bind，服务器进程就无法在某个已知地址上接受TCP连接或接收UDP数据报。客户进程也能调用bind，这样便可以由应用程序而非内核来选择一个本地地址，其结果是只能接收目的地址为被绑定地址的数据包，但通常不必调用bind，因为内核会自动决定外出地址和临时端口。<br />
<span style="color: #008000"><strong>3. 对于tcp和udp协议的插口，调用connect有什么区别联系？</strong></span><br />
&nbsp; &nbsp;共同点是设定插口的外部地址(插口的地址存储在相关的协议控制块中)，不同点如下<br />
&nbsp; &nbsp;1）tcp：与远端系统进行3次握手交互，如果插口是非阻塞的且连接正在进行中，那么返回EINPROGRESS，下次再调用则返回EALREADY；如果连接成功，无论是否阻塞，那么下次再调用会返回EISCONN；如果连接失败，那么下次再调用，则重新开始三次握手。<br />
&nbsp; &nbsp;2）udp：没有3次握手交互，直接设定外部地址，无论插口是否阻塞，调用会立即返回，多次调用则会替换老的外部地址。发送数据必须使用write或目的地址为空的sendto，若sendto目的地址非空，则返回EISCONN。如果没有事先调用connect，那么调用目的地址为空的sendto则会返回ENOTCONN。<br />
<span style="color: #008000"><strong>4. 什么情况下调用close会阻塞？</strong></span><br />
&nbsp; &nbsp;连接已建立且设置了SO_LINGER选项并延时值非零的阻塞插口。<br />
<span style="color: #008000"><strong>5. 插口IO有哪些系统调用？</strong></span><br />
&nbsp; &nbsp;发送有write、writev、sendto和sendmsg，接收有read、readv、recvfrom和recvmsg。注意，send和recv是库函数而非系统调用，前者调用sendto实现，后者调用recvfrom实现。<br />
<span style="color: #008000"><strong>6. write、writev、read、readv与sendto、sendmsg、recvfrom、recvmsg有什么不同？</strong></span><br />
&nbsp; &nbsp;1）前面4个适合于任何描述符，而后面4个只能用于插口。<br />
&nbsp; &nbsp;2）前面4个不支持标志，而后面4个支持。<br />
&nbsp; &nbsp;3）前面前2个不支持目的地址、后2个不支持源地址，而后面前2个支持目的地址、后2个支持源地址。<br />
&nbsp; &nbsp;4）前面4个不支持控制信息，而后面第2个和第4个支持。<br />
<span style="color: #008000"><strong>7. 如何断开已连接的udp插口，允许调用sendto向其它主机发送数据？</strong></span><br />
&nbsp; &nbsp; 由于系统并没有提供形如disconnect的断连API，但connect内部实现是先断连，再调用对应协议的PRU_CONNECT请求处理，因此向connect传递无效的外部地址结构(如IP=0.0.0.0，Port=0)，虽然这样会导致结果失败，但先前的断连成功，对应pcb的外部地址被设为INADDR_ANY，所以调用sendto就不会返回EISCONN。<br />
<br />
<span style="color: #ff6600; font-size: 12pt">【Raw IP】</span><br />
<span style="color: #008000"><strong>1. 怎么使用原始IP，它有哪些用途及应用？</strong></span><br />
&nbsp;&nbsp;&nbsp;创建SOCK_RAW类型的原始插口，就能使用原始IP机制，它有下列用途：<br />
&nbsp; &nbsp;1）发送和接收ICMP和IGMP报文，如ping程序和多播路由守护程序。<br />
&nbsp; &nbsp;2）构造自己的IP首部，如路由跟踪程序。<br />
&nbsp; &nbsp;3）设计基于IP的新的传输层协议，如gated程序。<br />
<span style="color: #008000"><strong>2. 协议值为PROTOCOL_RAW(255)的原始插口能收到什么类型的IP数据报？</strong></span><br />
&nbsp;&nbsp;&nbsp;由于255是非零的保留值，这样的IP数据报在网络中不会存在，原始IP输入处理协议比较测试失败，因此收不到任何类型的IP数据报。<br />
<span style="color: #008000"><strong>3. 协议值为0的原始插口能收到什么类型的IP数据报？</strong></span><br />
&nbsp;&nbsp;&nbsp;由于协议值为0，原始IP输入处理忽略了协议比较测试，因此能收到任何类型的IP数据报。<br />
<span style="color: #008000"><strong>4. 如何处理收到的IP数据报？</strong></span><br />
&nbsp;&nbsp;&nbsp;遍历Internet PCB表，依次从协议值、本地地址和外部地址三项来比较IP数据报和每个PCB，将IP数据报复制追加到所有匹配的PCB对应的插口缓存中，并唤醒等待的进程。<br />
<span style="color: #008000"><strong>5. 如何发送数据？</strong></span><br />
&nbsp;&nbsp;&nbsp;先填充IP首部，如果未设置IP_HDRINCL选项，那么由内核填充，否则由应用程序在发送前填充，再交给IP协议输出处理。<br />
<span style="color: #008000"><strong>6. 内核何时会调用原始输入？</strong></span><br />
&nbsp;&nbsp;&nbsp;当收到的协议类型为除IPPROTO_TCP、IPPROTO_UDP、IPPROTO_ICMP和IPPROTO_IGMP外的IP数据报时调用。<br />
<br />
<span style="color: #ff6600; font-size: 12pt">【Unix domain】</span><br />
<span style="color: #008000"><strong>1. 使用unix域的原因有哪些？</strong></span><br />
&nbsp;&nbsp;&nbsp;1）当通信双方在同一主机上时，使用unix域插口的速度比tcp和udp插口要快很多。<br />
&nbsp;&nbsp;&nbsp;2）支持同一主机进程间传递描述符。<br />
<span style="color: #008000"><strong>2. unix域和internet域有什么不同？</strong></span><br />
&nbsp;&nbsp;&nbsp;1）编址结构不同：前者是sockaddr_un，与文件系统路径名关联，而后者是sockaddr_in，与IP地址和端口关联。<br />
&nbsp;&nbsp;&nbsp;2）协议控制块不同：前者是unpcb，没有全局的pcb链表，而后者是inpcb，有全局的pcb双向循环链表。<br />
<span style="color: #008000"><strong>3. 如果一个unix域服务器在bind后unlink了被绑定的路径名，会发生什么情况？</strong></span><br />
<div>&nbsp;&nbsp;&nbsp;因为connect内部实现查找路径名失败，所以连接失败，但listen会成功，因为bind会创建新的vnode和pcb关联，且PRU_LISTEN请求实现只检查vnode是否为空。<br />
<span style="color: #008000"><strong>4. 如果一个unix域服务器在终止时没有unlink被绑定的路径名，会发生什么情况？</strong></span><br />
&nbsp;&nbsp;&nbsp;因为connect内部实现虽能找到路径名但找不到相关的插口，所以连接被拒绝。<br />
<span style="color: #008000"><strong>5. 系统调用socketpair和pipe有什么区别联系？</strong></span><br />
&nbsp;&nbsp;&nbsp;共同点是使用unix域，即socket调用第1参数为AF_UNIX，不同点如下<br />
&nbsp;&nbsp;&nbsp;1）前者是双工的，因为两个插口标志都为读写，且它们的pcb相互指向对方；后者是单工的，因为一个插口标志为只读，另一个为只写，写插口的pcb指向读插口的pcb。<br />
&nbsp;&nbsp;&nbsp;2）前者支持数据报和流式插口，后者仅支持流式插口。<br />
<span style="color: #008000"><strong>6. unix域是怎么实现传递描述符的？</strong></span><br />
&nbsp;&nbsp;&nbsp;描述符存储在控制信息cmsghdr内，cms_level=SOL_SOCKET且cms_type=SCM_RIGHTS，unix域的发送请求实现将描述符转换为file指针，这个过程叫内部化，接收请求实现把file指针转换为最小的没有使用的描述符，这个过程叫外部化。 </div><img src ="http://www.cppblog.com/qinqing1984/aggbug/202876.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2013-09-03 15:52 <a href="http://www.cppblog.com/qinqing1984/archive/2013/09/03/202876.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TCP/IP FAQ （1）：链路层、网络层和传输层</title><link>http://www.cppblog.com/qinqing1984/archive/2013/08/25/202734.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Sun, 25 Aug 2013 02:50:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2013/08/25/202734.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/202734.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2013/08/25/202734.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/202734.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/202734.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;TCP/IP FAQ系列，以经典的4.4BSD-Lite实现为准，参考《TCP/IP协议详解》3卷 ，加入个人的思考理解，理清主干，不深究细枝末节，皆在总结基本原理和实现。本篇涵盖了数据链路层、ARP、RARP、IP、ICMP、TCP、UDP方面的问题与解答。<br />
<br />
<span style="color: #ff6600; font-size: 12pt;">【Data Link】</span><br />
<span style="color: #008000;"><strong>1. 环回接口地址必须是127.0.0.1吗？</strong></span><br />
&nbsp;&nbsp;&nbsp;形如127.x.x.x的A类IP都可作为环回接口的地址，但常用的是127.0.0.1。<br />
<span style="color: #008000;"><strong>2. 环回接口为什么没有输入处理？</strong></span><br />
&nbsp;&nbsp;&nbsp;发送到环回接口的数据报实质上被送到网络层的输入队列中，因此数据报没有离开网络，也就不可能从链路上接收到目标地址为环回接口地址的数据帧，所以不存在输入处理。<br />
<span style="color: #008000;"><strong>3. SLIP、环回和以太网接口，三者有何不同？</strong></span><br />
&nbsp; &nbsp;SLIP和环回接口没有链路层首部和硬件地址，环回接口没有输入处理，而以太网接口都有。<br />
<span style="color: #008000;"><strong>4. SLIP和以太网接口如何分用输入帧，环回接口如何分用输出分组？</strong></span><br />
&nbsp; &nbsp;SLIP将帧直接放进IP输入队列中，以太网接口则根据帧类型字段放到对应的协议输入队列中，环回接口则按目的地址族放到对应的输入队列中。<br />
<span style="color: #008000;"><strong>5. 接口和地址有什么关联？</strong></span><br />
&nbsp; &nbsp;一个接口的编址信息包括主机地址、广播地址和网络掩码，当内核初始化时，每个接口分配一个链路层地址，可以配置有多个相同或不同的网络层地址，例如2个IP地址，或者1个IP地址、1个OSI地址。<br />
<br />
<span style="color: #ff6600; font-size: 12pt;">【ARP &amp; RARP】<br />
</span><span style="color: #008000;"><strong>1. 何时发送ARP请求，何时应答ARP请求？</strong></span><br />
&nbsp; &nbsp;当单播发送IP数据并且查询ARP高速缓存失败时，就会广播一个询问目的主机硬件地址的ARP请求；当接收到ARP请求的主机就是该请求所要查找的目的主机或目的主机的ARP代理服务器时，就会单播一个ARP应答。<br />
<span style="color: #008000;"><strong>2. 为什么两者的以太网帧类型不同？</strong></span><br />
&nbsp;&nbsp;&nbsp;ARP值为0x0806，RARP为0x8035，其实对于发送方来说，利用ARP的op字段可以区分RARP，但对于接收方，由于ARP实现在内核中，而RARP一般实现为服务器，所以为了更易区分，就单独用另一个值标识。<br />
<span style="color: #008000;"><strong>3. 设计RARP服务器有哪些问题？</strong></span><br />
&nbsp;&nbsp;&nbsp;一是怎么发送以太网帧以响应请求，这与系统相关。二是当存在多个服务器时，同时发送响应帧会造成以太网冲突，这可以通过分主从服务器和随机延时来优化避免。<br />
<span style="color: #008000;"><strong>4. ARP在等待应答时，它会如何处理发往给定目的的多个报文？</strong></span><br />
&nbsp;&nbsp;&nbsp;在大多数的实现中，在等待一个ARP应答时，只将最后一个报文发给特定目的主机。Host Requirements RFC要求实现中必须防止这种类型的ARP洪泛，建议最高速率是每秒一次。<br />
<span style="color: #008000;"><strong>5. 免费ARP有什么作用？</strong></span><br />
&nbsp;&nbsp;&nbsp;一般的ARP请求用于查询目标硬件地址，并等待应答。而免费的ARP发出请求并不一定期望应答，这可以有两方面的作用：<br />
&nbsp;&nbsp;&nbsp;1）一个主机可以确定是否存在相同IP地址的另一主机<br />
&nbsp; &nbsp;2）当本机硬件地址改变时，通知其它主机更新ARP高速缓存。<br />
<span style="color: #008000;"><strong>6. ARP如何映射一个IP多播地址？</strong></span><br />
&nbsp; &nbsp;先获取IP多播地址的低23位，再与常量0x01005e7f0000按位或，结果就是对应的多播硬件地址。<br />
<br />
<span style="color: #ff6600; font-size: 12pt;">【IP】</span><br />
<span style="color: #008000;"><strong>1. 何时何地分片？</strong></span><br />
&nbsp;&nbsp;&nbsp;当数据报长度大于链路接口MTU且DF=0时，开始分片，分片可发生在源主机，也可发生在中途路由器。若需要分片但DF=1，则向源主机发送ICMP不可达差错。<br />
<span style="color: #008000;"><strong>2. 如何分片？</strong></span><br />
&nbsp; &nbsp;<span style="font-size: 14px;">1）</span><span>计算每个分片的数据长度(不含IP首部)，除后一个分片外，其它分片数据长度为8字节的倍数。</span>
<div>&nbsp; &nbsp;2）除复制对应数据外，还复制原始分组的首部及(部分)选项到新的每个分片中，更新新分片首部的头部长度、总长度、MF标志和偏移量。如果原始分组已经是分片，那么MF=1，否则最后一个分片MF=0，其余MF=1。<br />
<span style="color: #008000;"><strong>3. 何时何地重装？</strong></span><br />
&nbsp; &nbsp;由于分片可以有不同的路由，而且中途路由器可能再次分片，因此只有目标主机才能重装所有分片。当接收端第一次收到一个MF或偏移量非零的分组时，则该分组就是一个必须被重装的分片，于是开始重装。</div>
<span style="color: #008000;"><strong>4. 如何重装？</strong></span><br />
&nbsp; &nbsp;1）使用4元组{源地址，目标地址，协议，16位标识}为唯一标识查找当前分片所属的数据报(分片表)，如果没有找到，则创建分片表，按偏移量将当前分片插入到分片表，并启动重装定时器。<br />
&nbsp;&nbsp;&nbsp;2）如果重装定时器超时后，还没有组装好一个完整的IP数据报，此时如果已经收到第一个分片，则向源主机返回ICMP超时差错，最后丢弃收到的所有分片；否则，提交数据给适当的传输层处理。<br />
<span style="color: #008000;"><strong>5. 哪些分组能被转发，何时转发？</strong></span><br />
&nbsp; &nbsp;到达非最终目的地系统的分组，且当系统配置为可转发或分组包含源路由时，才能被转发，但下列类型的分组除外：1）链路层广播 2）环回分组 3）网络0和E类目标地址 4）D类目标地址。<br />
<br />
<span style="color: #ff6600; font-size: 12pt;">【ICMP】</span><br />
<span style="color: #008000;"><strong>1. ICMP报文有哪些类型，何时何地生成这些报文？</strong></span><br />
&nbsp; &nbsp;包括请求、应答、差错和重定向4种，其中前两者可统一为查询类。请求当需要查询的时候由进程生成，应答由当内核收到请求报文时生成，当主机发出的数据报无法成功地提交给目的主机时，目的主机或中间路由器的IP或传输协议生成差错报文，并返回给原来的系统。<br />
<span style="color: #008000;"><strong>2. 内核怎么处理收到的ICMP报文？</strong></span><br />
&nbsp; &nbsp;ICMP是一种传输层协议，其协议号为1，当IP层收到一个ICMP报文时，分用交给ICMP协议输入处理，ICMP协议输入根据其类型分别处理：1）请求---生成适当的应答报文 2）差错---提交给适当的传输层协议处理 3）应答---提交给等待ICMP报文的进程 4）重定向---更新路由表，并提交给等待的进程。<br />
<span style="color: #008000;"><strong>3. 怎么发送ICMP报文？</strong></span><br />
&nbsp; &nbsp;构造ICMP报文--&gt;计算ICMP检验和--&gt;封装到IP数据报中--&gt;提交给IP协议输出处理，对于用户进程，须使用原始IP机制才能发送。<br />
<span style="color: #008000;"><strong>4. 哪些情况不会产生ICMP差错报文，为什么？</strong></span><br />
&nbsp; &nbsp;1）ICMP差错报文：违反此条可能导致差错引起差错，无休止循环下去。<br />
&nbsp; &nbsp;2）源地址不是单播地址的IP数据报：违反此条导致差错可能同时发到多个主机。<br />
&nbsp; &nbsp;3）目的地址是广播或多播地址的IP数据报：违反此条导致多个主机可能同时响应。<br />
&nbsp; &nbsp;4）作为链路层广播的数据报：违反此条导致多个主机可能同时响应。<br />
&nbsp; &nbsp;5）不是IP分片的第一片：违反此条可能导致产生多个ICMP差错，每个分片一个。<br />
&nbsp; &nbsp;由此可见，违反以上几条都会引起网络风暴。<br />
<br />
<span style="color: #ff6600; font-size: 12pt;">【TCP &amp; UDP】</span><br />
<span style="color: #008000;"><strong>1. 为什么TCP首部存在首部长度字段，而UDP却没有？</strong></span><br />
&nbsp;&nbsp;&nbsp;TCP首部存在选项，如mss,timestame,nop和wscale等。<br />
<span style="color: #008000;"><strong>2. 为什么这两种协议首部前面都是源和目的端口？</strong></span><br />
&nbsp;&nbsp;&nbsp;当TCP收到一个ICMP差错时，必须检查两个端口号以决定差错对应于哪个连接；只有当UDP套接口连接到对端时，用户进程才会收到ICMP差错，例如当服务器未运行时，返回的ICMP端口不可达消息。<br />
<span style="color: #008000;"><strong>3. 当收到TCP或UDP数据包时，怎么提交给应用层？</strong></span><br />
&nbsp;&nbsp;&nbsp;插口由进程调用socket或accept创建，关联到对应的PCB(协议控制块)上，通配匹配数由本地和外部IP地址确定，有3种取值：0--本地和外部IP都不为*、1--本地或外部IP有一个为*和2--本地和外部IP都为*。与UDP不同的是，TCP还有自己的PCB。<br />
&nbsp; &nbsp;1）TCP：先扫描Internet PCB，查找最小通配匹配数的插口，如果没找到，那么响应RST包；再查看对应的TCP PCB，若不存在则响应RST包，否则若TCP 状态为关闭，则丢弃；最后交付给找到的对应插口。<br />
&nbsp; &nbsp;2）UDP：这里要分2种情况，对于目的地为广播或多播地址的IP数据报，交付给所有匹配的插口；对于目的地为单播的IP数据报，扫描Internet PCB，查找具有最小通配匹配数的插口，如果没有找到，则向源主机发送ICMP端口不可达差错。如果有多个插口有相同的最小通配匹配数，那么具体由哪个插口接收依赖于不同的实现。<br />
<span style="color: #008000;"><strong>4. 计算首部检验和时，为什么要引入伪首部？</strong></span><br />
&nbsp; &nbsp;这是因为考虑到IP层的可能差错，TCP和UDP需要验证数据包是否被递送到正确的协议和目的主机。<br />
<span style="color: #008000;"><strong>5. UDP何时会计算检验和，如何区分是否使用了检验和？</strong></span><br />
&nbsp; &nbsp;UDP的检验和是可选的，当系统没有禁止(udpcksum非零)时，发送方会计算检验和，接收方还须输入分组检验和非零时才会计算检验和。如果检验和字段非零，那么就使用了，反之没有。<br />
<span style="color: #008000;"><strong>6. 在TCP状态迁移中，哪些状态在什么情况下可直接转到CLOSED状态？</strong></span><br />
&nbsp; &nbsp;SYN_SENT在连接定时器超时后，FIN_WAIT_2在FIN_WAIT_2定时器超时后。<br />
<span style="color: #008000;"><strong>7. 为什么TCP需要持续(persist)定时器、FIN_WAIT_2定时器和2MSL定时器？</strong></span><br />
&nbsp; &nbsp;1）因为连接对端发送的窗口通告为ACK报文，而ACK是不会确认的，允许TCP继续发送数据的窗口更新可能会丢失，所以需要设定persist定时器，在超时后发送1字节的数据，判定对端接收窗口是否已打开。<br />
&nbsp; &nbsp;2）因为在正常情况下，当连接主动关闭时，会由FIN_WAIT_1状态进入FIN_WAIT_2状态等待接收对端的FIN报文，但对方可能一直不发送FIN，所以需要FIN_WAIT_2定时器避免连接永远滞留在FIN_WAI_2状态。<br />
&nbsp; &nbsp;3）因为当连接主动关闭进入TIME_WAIT状态后，将等待2个MSL时间，在这段时间内，TCP可以重发丢失的ACK，丢弃来自新连接替身的迟到的报文段以防止被曲解，所以需要2MSL定时器，超时后关闭连接。<br />
<span style="color: #008000;"><strong>8. 当TCP发送数据，调用ip_output返回ENOBUFS差错时，可能会发生什么情况？</strong></span><br />
&nbsp; &nbsp;当提交给网络层因为内存不足发送失败时，数据包被丢弃。如果丢弃的是数据报文，重传定时器超时后数据将被重传；如果丢弃的是纯ACK报文，对端收不到ACK时会重传对应的数据报文；如果丢弃的是RST报文，当对端重传导致发送RST报文的数据报文时，将再次生成RST报文。<br />
<span style="color: #008000;"><strong>9. TCP何时发送ACK报文？</strong></span><br />
&nbsp; &nbsp;对于数据、SYN和FIN报文，发送ACK，但对于纯ACK和RST报文，不会发送；另外当遇以下情况时，则立即发送。<br />
&nbsp;&nbsp;&nbsp;1）200ms延时ACK定时器超时；2）收到失序的报文段；3）三次握手收到了SYN；4）收到了FIN。<br />
<span style="color: #008000;"><strong>10. TCP何时发送RST报文？</strong></span><br />
&nbsp; &nbsp;1）当收到报文段，但没有找到对应的internet pcb或tcp pcb。<br />
&nbsp;&nbsp;&nbsp;2）当连接处于LISTEN状态时，收到了ACK报文段。<br />
&nbsp;&nbsp;&nbsp;3）当连接处于SYS_SENT状态时，收到了错误的ACK报文段(ack小于等于iss或大于snd_max)。<br />
&nbsp;&nbsp;&nbsp;4）当连接被动关闭时(状态大于CLOSE_WAIT)，收到了数据。<br />
&nbsp;&nbsp;&nbsp;5）当连接处于SYN_RCVD状态时，收到了错误的ACK报文段(ack小于snd_una或大于snd_max)。<img src ="http://www.cppblog.com/qinqing1984/aggbug/202734.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2013-08-25 10:50 <a href="http://www.cppblog.com/qinqing1984/archive/2013/08/25/202734.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>运用状态机异步接收变长包</title><link>http://www.cppblog.com/qinqing1984/archive/2012/09/20/191396.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Thu, 20 Sep 2012 07:48:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2012/09/20/191396.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/191396.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2012/09/20/191396.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/191396.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/191396.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 情景分析&nbsp;&nbsp;&nbsp;在网络编程中，通常异步比同步处理更为复杂，但由于异步的事件通知机制，避免了同步方式中的忙等待，提高了吞吐量，因此效率较高，在高性能应用开发中，经常被用到。而在处理异步相关的问题时，状态机模式是一种典型的有效方法，这在libevent、memcached、nginx等开源软件(库)中多次被使用而得到见证。据此，为抛砖引玉，本文展示了使用此方法异步接收变...&nbsp;&nbsp;<a href='http://www.cppblog.com/qinqing1984/archive/2012/09/20/191396.html'>阅读全文</a><img src ="http://www.cppblog.com/qinqing1984/aggbug/191396.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2012-09-20 15:48 <a href="http://www.cppblog.com/qinqing1984/archive/2012/09/20/191396.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一种简单的跨平台套接字管道</title><link>http://www.cppblog.com/qinqing1984/archive/2012/06/17/179103.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Sat, 16 Jun 2012 19:02:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2012/06/17/179103.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/179103.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2012/06/17/179103.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/179103.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/179103.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; &nbsp;&nbsp;socket pair，也称套接字管道，主要用来实现进程内或进程间的一对一的全双工或半双工通信，在IO复用模型（如select,poll,epoll等）中起到通知中断退出循环的作用，在类UNIX系统中已经有现成的实现，API为socketpair，但在Windows系统中没有，因此本文主要讲述Windows平台下soketpair的实现及应用，支持IPv4和I...&nbsp;&nbsp;<a href='http://www.cppblog.com/qinqing1984/archive/2012/06/17/179103.html'>阅读全文</a><img src ="http://www.cppblog.com/qinqing1984/aggbug/179103.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2012-06-17 03:02 <a href="http://www.cppblog.com/qinqing1984/archive/2012/06/17/179103.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>