{"id":38611,"date":"2025-05-20T19:31:04","date_gmt":"2025-05-20T11:31:04","guid":{"rendered":"https:\/\/www.wsisp.com\/helps\/38611.html"},"modified":"2025-05-20T19:31:04","modified_gmt":"2025-05-20T11:31:04","slug":"%e3%80%90%e5%85%a8%e5%b1%80%e6%95%99%e5%ad%a6%e3%80%91%e6%89%8b%e6%8a%8a%e6%89%8b%e6%95%99%e4%bd%a0%e5%81%9a%e4%b8%80%e4%b8%aamuduo%e6%9c%8d%e5%8a%a1%e5%99%a8","status":"publish","type":"post","link":"https:\/\/www.wsisp.com\/helps\/38611.html","title":{"rendered":"\u3010\u5168\u5c40\u6559\u5b66\u3011\u624b\u628a\u624b\u6559\u4f60\u505a\u4e00\u4e2amuduo\u670d\u52a1\u5668"},"content":{"rendered":"<p id=\"main-toc\">\u76ee\u5f55<\/p>\n<p id=\"1.%E5%87%86%E5%A4%87%E7%9F%A5%E8%AF%86-toc\" style=\"margin-left:0px\">1.\u51c6\u5907\u77e5\u8bc6<\/p>\n<p id=\"1.1%E6%97%B6%E9%97%B4%E8%BD%AE-toc\" style=\"margin-left:40px\">1.1\u65f6\u95f4\u8f6e<\/p>\n<p id=\"1.2%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F-toc\" style=\"margin-left:40px\">1.2\u6b63\u5219\u8868\u8fbe\u5f0f<\/p>\n<p id=\"1.3%20%E9%80%9A%E7%94%A8%E7%B1%BB%E5%9E%8BAny%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">1.3 \u901a\u7528\u7c7b\u578bAny\u7c7b\u578b\u7684\u5b9e\u73b0<\/p>\n<p id=\"2.Server%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%A8%A1%E5%9D%97%E5%AE%9E%E7%8E%B0%EF%BC%9A-toc\" style=\"margin-left:0px\">2.Server\u670d\u52a1\u5668\u6a21\u5757\u5b9e\u73b0&#xff1a;<\/p>\n<p id=\"2.1%20%E7%BC%93%E5%86%B2%E5%8C%BABuffer%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">2.1 \u7f13\u51b2\u533aBuffer\u7c7b\u7684\u5b9e\u73b0<\/p>\n<p id=\"2.2%20%E6%97%A5%E5%BF%97%E5%AE%8F%E7%9A%84%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">2.2 \u65e5\u5fd7\u5b8f\u7684\u5b9e\u73b0<\/p>\n<p id=\"%C2%A02.3%20%E5%A5%97%E6%8E%A5%E5%AD%97%E6%A8%A1%E5%9D%97%E7%9A%84%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">\u00a02.3 \u5957\u63a5\u5b57\u6a21\u5757\u7684\u5b9e\u73b0<\/p>\n<p id=\"2.4%C2%A0%E4%BA%8B%E4%BB%B6%E7%AE%A1%E7%90%86Channel%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">2.4\u00a0\u4e8b\u4ef6\u7ba1\u7406Channel\u7c7b\u7684\u5b9e\u73b0<\/p>\n<p id=\"2.5%C2%A0%E6%8F%8F%E8%BF%B0%E7%AC%A6%E4%BA%8B%E4%BB%B6%E7%9B%91%E6%8E%A7Poller%E7%B1%BB%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">2.5\u00a0\u63cf\u8ff0\u7b26\u4e8b\u4ef6\u76d1\u63a7Poller\u7c7b\u5b9e\u73b0<\/p>\n<p id=\"2.6%20%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1%E7%AE%A1%E7%90%86TimerWheel%E7%B1%BB%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">2.6 \u5b9a\u65f6\u4efb\u52a1\u7ba1\u7406TimerWheel\u7c7b\u5b9e\u73b0<\/p>\n<p id=\"2.7%C2%A0Reactor-EventLoop%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%B1%BB%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">2.7\u00a0Reactor-EventLoop\u7ebf\u7a0b\u6c60\u7c7b\u5b9e\u73b0<\/p>\n<p id=\"%C2%A02.8%20%E7%94%A8%E4%BA%8E%E7%AE%A1%E7%90%86%E5%8D%95%E4%B8%AA%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF%E7%BA%BF%E7%A8%8BLoopThread%E7%B1%BB-toc\" style=\"margin-left:40px\">\u00a02.8 \u7528\u4e8e\u7ba1\u7406\u5355\u4e2a\u4e8b\u4ef6\u5faa\u73af\u7ebf\u7a0bLoopThread\u7c7b<\/p>\n<p id=\"2.9%C2%A0%C2%A0%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E4%B8%BB%E8%A6%81%E9%80%BB%E8%BE%91LoopThreadPool%E7%B1%BB-toc\" style=\"margin-left:40px\">2.9\u00a0\u00a0\u7ebf\u7a0b\u6c60\u7684\u4e3b\u8981\u903b\u8f91LoopThreadPool\u7c7b<\/p>\n<p id=\"%C2%A02.10%20Any%E7%B1%BB%E4%BB%A3%E7%A0%81%E7%9A%84%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">\u00a02.10 Any\u7c7b\u4ee3\u7801\u7684\u5b9e\u73b0<\/p>\n<p id=\"2.11%20%E9%80%9A%E4%BF%A1%E8%BF%9E%E6%8E%A5%E7%AE%A1%E7%90%86Connection%E7%B1%BB%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">2.11 \u901a\u4fe1\u8fde\u63a5\u7ba1\u7406Connection\u7c7b\u5b9e\u73b0<\/p>\n<p id=\"%C2%A02.12%20%E7%9B%91%E5%90%AC%E6%8F%8F%E8%BF%B0%E7%AC%A6%E7%AE%A1%E7%90%86Acceptor%E6%A8%A1%E5%9D%97-toc\" style=\"margin-left:40px\">\u00a02.12 \u76d1\u542c\u63cf\u8ff0\u7b26\u7ba1\u7406Acceptor\u6a21\u5757<\/p>\n<p id=\"2.13%20%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%B1%BBTcpServer%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">2.13 \u670d\u52a1\u5668\u7c7bTcpServer\u7c7b\u7684\u5b9e\u73b0<\/p>\n<p id=\"3.HTTP%E5%8D%8F%E8%AE%AE%E6%94%AF%E6%8C%81%E6%A8%A1%E5%9D%97%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:0px\">3.HTTP\u534f\u8bae\u652f\u6301\u6a21\u5757\u5b9e\u73b0<\/p>\n<p id=\"3.1%20Util%E5%AE%9E%E7%94%A8%E5%B7%A5%E5%85%B7%E7%B1%BB%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">3.1 Util\u5b9e\u7528\u5de5\u5177\u7c7b\u5b9e\u73b0<\/p>\n<p id=\"3.2%20HttpRequest%20%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">3.2 HttpRequest \u7c7b\u7684\u5b9e\u73b0<\/p>\n<p id=\"3.3%20HttpResponse%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">3.3 HttpResponse\u7c7b\u7684\u5b9e\u73b0<\/p>\n<p id=\"3.4%20HttpContext%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">3.4 HttpContext\u7c7b\u7684\u5b9e\u73b0<\/p>\n<p id=\"3.5%20HttpServer%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0-toc\" style=\"margin-left:40px\">3.5 HttpServer\u7c7b\u7684\u5b9e\u73b0<\/p>\n<p id=\"4.%E7%BB%93%E8%AF%AD-toc\" style=\"margin-left:0px\">4.\u7ed3\u8bed<\/p>\n<hr id=\"hr-toc\" \/>\n<\/p>\n<h2 id=\"1.%E5%87%86%E5%A4%87%E7%9F%A5%E8%AF%86\">1.\u51c6\u5907\u77e5\u8bc6<\/h2>\n<h3 id=\"1.1%E6%97%B6%E9%97%B4%E8%BD%AE\" style=\"background-color:transparent\">1.1\u65f6\u95f4\u8f6e<\/h3>\n<p>\u5982\u4e0b\u56fe&#xff0c;\u8fd9\u5c31\u662f\u65f6\u95f4\u8f6e\u7684\u56fe\u50cf&#xff0c;\u63a5\u4e0b\u6765\u6211\u6765\u89e3\u91ca\u4e00\u4e0b\u8fd9\u4e2a\u65f6\u95f4\u8f6e\u7684\u539f\u7406<\/p>\n<p class=\"img-center\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" height=\"400\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2025\/05\/20250520113103-682c67f78f176.png\" width=\"496\" \/><\/p>\n<p>\u00a0\u4e2d\u95f4\u7684\u6307\u9488\u6211\u4eec\u79f0\u4e3a_tick&#xff0c;\u7528\u6765\u8868\u793a\u73b0\u5728\u6307\u9488\u6307\u5411\u7684\u4f4d\u7f6e&#xff0c;\u6307\u9488\u6307\u5411\u8fd9\u4e2a\u4f4d\u7f6e\u7684\u65f6\u5019&#xff0c;\u5c31\u53bb\u68c0\u67e5\u8fd9\u4e2a\u4f4d\u7f6e\u4e0a\u9762\u662f\u5426\u6709\u5bf9\u5e94\u4efb\u52a1\u5230\u4e86\u65f6\u95f4&#xff0c;\u5982\u679c\u65f6\u95f4\u5df2\u5230&#xff0c;\u90a3\u4e48\u5c31\u79fb\u9664\u8fd9\u4e2a\u4efb\u52a1&#xff0c;\u5e76\u4e14\u6267\u884c\u8fd9\u4e2a\u5bf9\u5e94\u7684\u4efb\u52a1\u3002<\/p>\n<p>\u5982\u4f55\u5b9e\u73b0&#xff1f;<\/p>\n<p>\u9996\u5148\u6211\u4eec\u5b9e\u73b0\u4e00\u4e2aTimerTask\u7684\u7c7b&#xff0c;\u8fd9\u4e2a\u7c7b\u5c31\u662f\u7528\u6765\u5305\u542b\u5177\u4f53\u7684\u4efb\u52a1&#xff0c;\u8d85\u65f6\u65f6\u95f4\u7b49\u7b49&#xff0c;\u4ee5\u4fbf\u8fd9\u4e2a\u4efb\u52a1\u65f6\u95f4\u5230\u4e86\u7684\u65f6\u5019\u6267\u884c\u5bf9\u5e94\u7684\u4efb\u52a1<\/p>\n<p>\u5148\u5305\u88c5\u4efb\u52a1\u51fd\u6570<\/p>\n<p>using TaskFunc &#061; std::function&lt;void()&gt;;<br \/>\nusing ReleaseFunc &#061; std::function&lt;void()&gt;; <\/p>\n<p>\u5305\u542b\u7684\u79c1\u6709\u6210\u5458<\/p>\n<p>uint64_t _id;         \/\/ \u5b9a\u65f6\u5668\u4efb\u52a1\u5bf9\u8c61id<br \/>\nuint32_t _timeout;    \/\/ \u5b9a\u65f6\u4efb\u52a1\u7684\u8d85\u65f6\u65f6\u95f4<br \/>\nbool _canceled;       \/\/ false-\u8868\u793a\u6ca1\u6709\u88ab\u53d6\u6d88<br \/>\nTaskFunc _task_cb;    \/\/ \u5b9a\u65f6\u5668\u5bf9\u8c61\u8981\u6267\u884c\u7684\u5b9a\u65f6\u4efb\u52a1<br \/>\nReleaseFunc _release; \/\/ \u7528\u4e8e\u5220\u9664TimerWheel\u4e2d\u4fdd\u5b58\u7684\u5b9a\u65f6\u5668\u5bf9\u8c61\u4fe1\u606f <\/p>\n<p>\u5305\u542b\u7684\u516c\u6709\u6210\u5458\u6709\u8bbe\u7f6e\u662f\u5426\u53d6\u6d88\u4efb\u52a1\u3001\u8bbe\u7f6e\u91ca\u653e\u65f6\u7528\u6765\u5220\u9664\u5b9a\u65f6\u5668\u5bf9\u8c61\u4fe1\u606f\u7684\u51fd\u6570\u3001\u8bbe\u7f6e\u8d85\u65f6\u65f6\u95f4<\/p>\n<p>void Cancel()<br \/>\n{<br \/>\n    _canceled &#061; true;<br \/>\n}<\/p>\n<p>void SetRelease(const ReleaseFunc&amp; cb)<br \/>\n{<br \/>\n    _release &#061; cb;<br \/>\n}<\/p>\n<p>uint32_t DelayTime()<br \/>\n{<br \/>\n    return _timeout;<br \/>\n} <\/p>\n<p>TimerTask\u7684\u6574\u4f53\u4ee3\u7801\u5982\u4e0b&#xff1a;<\/p>\n<p>class TimerTask<br \/>\n{<br \/>\nprivate:<br \/>\n    uint64_t _id;         \/\/ \u5b9a\u65f6\u5668\u4efb\u52a1\u5bf9\u8c61id<br \/>\n    uint32_t _timeout;    \/\/ \u5b9a\u65f6\u4efb\u52a1\u7684\u8d85\u65f6\u65f6\u95f4<br \/>\n    bool _canceled;       \/\/ false-\u8868\u793a\u6ca1\u6709\u88ab\u53d6\u6d88<br \/>\n    TaskFunc _task_cb;    \/\/ \u5b9a\u65f6\u5668\u5bf9\u8c61\u8981\u6267\u884c\u7684\u5b9a\u65f6\u4efb\u52a1<br \/>\n    ReleaseFunc _release; \/\/ \u7528\u4e8e\u5220\u9664TimerWheel\u4e2d\u4fdd\u5b58\u7684\u5b9a\u65f6\u5668\u5bf9\u8c61\u4fe1\u606f<br \/>\npublic:<br \/>\n    TimerTask(uint64_t id, uint32_t delay, const TaskFunc &amp;cb)<br \/>\n        : _id(id), _timeout(delay), _task_cb(cb), _canceled(false)<br \/>\n    {<br \/>\n    }<\/p>\n<p>    ~TimerTask()<br \/>\n    {<br \/>\n        if(_canceled &#061;&#061; false)_task_cb();<br \/>\n        _release();<br \/>\n    }<\/p>\n<p>    void Cancel()<br \/>\n    {<br \/>\n        _canceled &#061; true;<br \/>\n    }<\/p>\n<p>    void SetRelease(const ReleaseFunc&amp; cb)<br \/>\n    {<br \/>\n        _release &#061; cb;<br \/>\n    }<\/p>\n<p>    uint32_t DelayTime()<br \/>\n    {<br \/>\n        return _timeout;<br \/>\n    }<br \/>\n}; <\/p>\n<p>\u63a5\u4e0b\u6765\u5c31\u662f\u65f6\u95f4\u8f6e\u7684\u4e3b\u4f53&#xff0c;\u65f6\u95f4\u8f6e_wheel\u6211\u4eec\u4f7f\u7528\u4e00\u4e2avector\u6765\u5b9e\u73b0&#xff0c;_tick\u6307\u9488\u904d\u5386\u5b8c\u4e00\u904d\u6570\u7ec4\u4e4b\u540e\u4ece\u5934\u5f00\u59cb\u904d\u5386\u6570\u7ec4&#xff0c;\u6570\u7ec4\u7684\u6bcf\u4e00\u4e2a\u4f4d\u7f6e\u4e2d&#xff0c;\u4e5f\u5b58\u653e\u7740\u4e00\u4e2a\u6570\u7ec4&#xff0c;\u8fd9\u4e2a\u6570\u7ec4\u4e2d\u5b58\u653e\u4efb\u52a1\u3002<\/p>\n<p>using WeakTask &#061; std::weak_ptr&lt;TimerTask&gt;;<br \/>\nusing PtrTask &#061; std::shared_ptr&lt;TimerTask&gt;;<br \/>\nint _tick;     \/\/ \u5f53\u524d\u7684\u79d2\u9488&#xff0c;\u8d70\u5230\u54ea\u91cc\u91ca\u653e\u54ea\u91cc<br \/>\nint _capacity; \/\/ \u8868\u76d8\u6700\u5927\u6570\u91cf&#xff0c;\u5176\u5b9e\u5c31\u662f\u6700\u5927\u5ef6\u8fdf\u65f6\u95f4<br \/>\nstd::vector&lt;std::vector&lt;PtrTask&gt;&gt; _wheel;<br \/>\nstd::unordered_map&lt;uint64_t, WeakTask&gt; _timers; \/\/\u4f7f\u7528\u4efb\u52a1ID\u627e\u5230\u5bf9\u5e94\u7684weak_ptr <\/p>\n<p>\u8fd9\u91cc\u89e3\u91ca\u4e00\u4e0b\u4e3a\u4ec0\u4e48\u8981\u4f7f\u7528weak_ptr\u6765\u4f5c\u4e3a\u5bf9\u5e94TimerTask\u7684\u6307\u9488&#xff0c;\u56e0\u4e3aweak_ptr\u4e0d\u4f1a\u589e\u52a0\u5176\u5f15\u7528\u8ba1\u6570&#xff0c;\u4e0d\u5f71\u54cdshared_ptr\u4e2d\u7684\u5f15\u7528\u8ba1\u6570\u4e3a0\u65f6\u5bf9TimerTask\u7684\u6b63\u5e38\u91ca\u653e<\/p>\n<p>\u628aTimerTask\u4ece_timers\u4e2d\u79fb\u9664<\/p>\n<p>void RemoveTimer(uint16_t id)<br \/>\n{<br \/>\n    auto it &#061; _timers.find(id);<br \/>\n    if(it !&#061; _timers.end())<br \/>\n    {<br \/>\n        _timers.erase(it);<br \/>\n    }<br \/>\n} <\/p>\n<p>\u6dfb\u52a0\u5b9a\u65f6\u4efb\u52a1<\/p>\n<p>void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc&amp; cb)<br \/>\n{<br \/>\n    \/\/ \u521b\u5efa\u4e00\u4e2a\u65b0\u7684<br \/>\n    PtrTask pt(new TimerTask(id, delay, cb));<br \/>\n    \/\/ \u8bbe\u7f6e\u91ca\u653e\u51fd\u6570<br \/>\n    pt-&gt;SetRelease(std::bind(&amp;TimerWheel::RemoveTimer, this, id));<br \/>\n    \/\/ \u5f53\u524d\u6307\u9488\u7684\u4f4d\u7f6e \u52a0\u4e0a \u8d85\u65f6\u65f6\u95f4 \u9664 \u65f6\u95f4\u8f6e\u7684\u5bb9\u91cf\u5f97\u5230\u63d2\u5165\u4f4d\u7f6e<br \/>\n    int pos &#061; (_tick &#043; delay) % _capacity;<br \/>\n    _wheel[pos].push_back(pt);<br \/>\n    \/\/ \u628a\u4efb\u52a1\u653e\u5165\u54c8\u5e0c\u8868\u4e2d<br \/>\n    _timers[id] &#061; WeakTask(pt);<br \/>\n} <\/p>\n<p>\u5237\u65b0\/\u5ef6\u8fdf\u5b9a\u65f6\u4efb\u52a1&#xff0c;\u8fd9\u91cc\u9700\u8981\u8bf4\u660e\u7684\u662f&#xff0c;\u8fd9\u91cc\u4f7f\u7528\u7684lock()&#xff0c;\u662f\u53ef\u4ee5\u628aweak_ptr\u63d0\u5347\u4e3ashared_ptr \u5f3a\u667a\u80fd\u6307\u9488&#xff0c;\u518d\u6dfb\u52a0\u4e00\u4e2aTimerTask\u8fdb\u53bb&#xff0c;\u76f8\u5f53\u4e8e\u628ashared_ptr\u7684\u5f15\u7528\u8ba1\u6570\u589e\u52a01&#xff0c;\u53d8\u76f8\u5730\u8d77\u5230\u4e86\u5237\u65b0\/\u5ef6\u8fdf\u5b9a\u65f6\u4efb\u52a1\u7684\u4f5c\u7528<\/p>\n<p>void TimerRefresh(uint64_t id)\/\/\u5237\u65b0\/\u5ef6\u8fdf\u5b9a\u65f6\u4efb\u52a1<br \/>\n{<br \/>\n    \/\/\u901a\u8fc7\u4fdd\u5b58\u7684\u5b9a\u65f6\u5668\u5bf9\u8c61\u7684weakptr\u6784\u9020\u4e00\u4e2ashared_ptr\u51fa\u6765&#xff0c;\u6dfb\u52a0\u5230\u8f6e\u5b50\u4e2d<br \/>\n    auto it &#061; _timers.find(id);<br \/>\n    if(it &#061;&#061; _timers.end())<br \/>\n    {<br \/>\n        \/\/\u6ca1\u6709\u627e\u5230\u5b9a\u65f6\u4efb\u52a1<br \/>\n        return;<br \/>\n    }<br \/>\n    PtrTask pt &#061; it-&gt;second.lock();\/\/lock\u83b7\u53d6weakptr\u7ba1\u7406\u7684\u5bf9\u8c61\u5bf9\u5e94\u7684shared_ptr;<br \/>\n    int delay &#061; pt-&gt;DelayTime();<br \/>\n    int pos &#061; (_tick &#043; delay) % _capacity;<br \/>\n    _wheel[pos].push_back(pt);<br \/>\n} <\/p>\n<p>\u53d6\u6d88\u5b9a\u65f6\u4efb\u52a1<\/p>\n<p>void TimerCancel(uint64_t id)<br \/>\n{<br \/>\n    auto it &#061; _timers.find(id);<br \/>\n    if(it &#061;&#061; _timers.end())<br \/>\n    {<br \/>\n        \/\/\u6ca1\u6709\u627e\u5230\u5b9a\u65f6\u4efb\u52a1<br \/>\n        return;<br \/>\n    }<br \/>\n    PtrTask pt &#061; it-&gt;second.lock();<br \/>\n    if(pt) pt-&gt;Cancel();<br \/>\n} <\/p>\n<p>\u6267\u884c\u5b9a\u65f6\u4efb\u52a1<\/p>\n<p>void RunTimeTask()<br \/>\n{<br \/>\n    _tick &#061; (_tick &#043; 1) % _capacity;<br \/>\n    _wheel[_tick].clear();<br \/>\n} <\/p>\n<p>\u603b\u4f53\u7684\u65f6\u95f4\u8f6e\u4ee3\u7801<\/p>\n<p>class TimerWheel<br \/>\n{<br \/>\nprivate:<br \/>\n    using WeakTask &#061; std::weak_ptr&lt;TimerTask&gt;;<br \/>\n    using PtrTask &#061; std::shared_ptr&lt;TimerTask&gt;;<br \/>\n    int _tick;     \/\/ \u5f53\u524d\u7684\u79d2\u9488&#xff0c;\u8d70\u5230\u54ea\u91cc\u91ca\u653e\u54ea\u91cc<br \/>\n    int _capacity; \/\/ \u8868\u76d8\u6700\u5927\u6570\u91cf&#xff0c;\u5176\u5b9e\u5c31\u662f\u6700\u5927\u5ef6\u8fdf\u65f6\u95f4<br \/>\n    std::vector&lt;std::vector&lt;PtrTask&gt;&gt; _wheel;<br \/>\n    std::unordered_map&lt;uint64_t, WeakTask&gt; _timers; \/\/\u4f7f\u7528\u4efb\u52a1ID\u627e\u5230\u5bf9\u5e94\u7684weak_ptr<br \/>\nprivate:<br \/>\n    void RemoveTimer(uint16_t id)<br \/>\n    {<br \/>\n        auto it &#061; _timers.find(id);<br \/>\n        if(it !&#061; _timers.end())<br \/>\n        {<br \/>\n            _timers.erase(it);<br \/>\n        }<br \/>\n    }<br \/>\npublic:<br \/>\n    TimerWheel()<br \/>\n        : _capacity(60),<br \/>\n          _tick(0),<br \/>\n          _wheel(_capacity)<br \/>\n    {<br \/>\n    }<br \/>\n    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc&amp; cb) \/\/\u6dfb\u52a0\u5b9a\u65f6\u4efb\u52a1<br \/>\n    {<br \/>\n        PtrTask pt(new TimerTask(id, delay, cb));<br \/>\n        pt-&gt;SetRelease(std::bind(&amp;TimerWheel::RemoveTimer, this, id));<br \/>\n        int pos &#061; (_tick &#043; delay) % _capacity;<br \/>\n        _wheel[pos].push_back(pt);<br \/>\n        _timers[id] &#061; WeakTask(pt);<br \/>\n    }<br \/>\n    void TimerRefresh(uint64_t id)\/\/\u5237\u65b0\/\u5ef6\u8fdf\u5b9a\u65f6\u4efb\u52a1<br \/>\n    {<br \/>\n        \/\/\u901a\u8fc7\u4fdd\u5b58\u7684\u5b9a\u65f6\u5668\u5bf9\u8c61\u7684weakptr\u6784\u9020\u4e00\u4e2ashared_ptr\u51fa\u6765&#xff0c;\u6dfb\u52a0\u5230\u8f6e\u5b50\u4e2d<br \/>\n        auto it &#061; _timers.find(id);<br \/>\n        if(it &#061;&#061; _timers.end())<br \/>\n        {<br \/>\n            \/\/\u6ca1\u6709\u627e\u5230\u5b9a\u65f6\u4efb\u52a1<br \/>\n            return;<br \/>\n        }<br \/>\n        PtrTask pt &#061; it-&gt;second.lock();\/\/lock\u83b7\u53d6weakptr\u7ba1\u7406\u7684\u5bf9\u8c61\u5bf9\u5e94\u7684shared_ptr;<br \/>\n        int delay &#061; pt-&gt;DelayTime();<br \/>\n        int pos &#061; (_tick &#043; delay) % _capacity;<br \/>\n        _wheel[pos].push_back(pt);<br \/>\n    }<br \/>\n    void TimerCancel(uint64_t id)<br \/>\n    {<br \/>\n        auto it &#061; _timers.find(id);<br \/>\n        if(it &#061;&#061; _timers.end())<br \/>\n        {<br \/>\n            \/\/\u6ca1\u6709\u627e\u5230\u5b9a\u65f6\u4efb\u52a1<br \/>\n            return;<br \/>\n        }<br \/>\n        PtrTask pt &#061; it-&gt;second.lock();<br \/>\n        if(pt) pt-&gt;Cancel();<br \/>\n    }<br \/>\n    \/\/\u8fd9\u4e2a\u51fd\u6570\u6bcf\u79d2\u88ab\u6267\u884c\u4e00\u6b21&#xff0c;\u76f8\u5f53\u4e8e\u79d2\u9488\u5411\u540e\u8d70\u4e86\u4e00\u6b65<br \/>\n    void RunTimeTask()<br \/>\n    {<br \/>\n        _tick &#061; (_tick &#043; 1) % _capacity;<br \/>\n        _wheel[_tick].clear();<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"1.2%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F\" style=\"background-color:transparent\">1.2\u6b63\u5219\u8868\u8fbe\u5f0f<\/h3>\n<p>\u9996\u5148&#xff0c;\u5fc5\u4e0d\u53ef\u5c11\u7684&#xff0c;\u662f\u5bf9http\u8bf7\u6c42\u884c\u7684\u89e3\u6790&#xff0c;\u4f46\u662f&#xff0c;\u5982\u679c\u76f4\u63a5\u624b\u6495\u8bf7\u6c42\u884c&#xff0c;\u628a\u8bf7\u6c42\u884c\u5206\u4e3a\u591a\u4e2a\u90e8\u5206&#xff0c;\u672a\u514d\u6709\u4e9b\u9ebb\u70e6&#xff0c;\u6240\u4ee5\u6211\u4eec\u9009\u62e9\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u6765\u89e3\u6790\u8bf7\u6c42\u884c&#xff0c;\u66f4\u4e3a\u7cbe\u786e\u9ad8\u6548&#xff0c;<\/p>\n<p>\u9996\u5148\u6211\u4eec\u9700\u8981\u77e5\u9053HTTP\u8bf7\u6c42\u884c\u7684\u57fa\u672c\u7ed3\u6784<\/p>\n<p>&lt;HTTP\u65b9\u6cd5&gt; &lt;\u8bf7\u6c42\u76ee\u6807&gt; &lt;HTTP\u7248\u672c&gt;<\/p>\n<p>\u00a0HTTP\u65b9\u6cd5\u5305\u62ecGET\u3001POST\u3001PUT\u3001DELETE\u7b49\u65b9\u6cd5<\/p>\n<p>\u8bf7\u6c42\u76ee\u6807\u5c31\u662f\u7528\u6237\u60f3\u8981\u8bf7\u6c42\u8d44\u6e90\u7684\u5bf9\u5e94\u8def\u5f84<\/p>\n<p>\u4e0b\u9762\u662f\u4e00\u4e2aHTTP\u8bf7\u6c42\u884c\u7684\u4f8b\u5b50&#xff1a;<\/p>\n<p>GET \/helloworld\/index?user&#061;diluodexingzi&amp;pass&#061;123456 HTTP\/1.1\\\\r\\\\n<\/p>\n<p>\u00a0\u9996\u5148\u6211\u4eec\u9700\u8981\u5339\u914dHTTP\u65b9\u6cd5&#xff0c;\u5982\u4e0b&#xff1a;<\/p>\n<p>(GET|HEAD|POST|PUT|DELETE)\u00a0<\/p>\n<p>| \u4ee3\u8868\u6216\u7684\u610f\u601d&#xff0c;\u8868\u793a\u4ece\u8fd9\u51e0\u4e2a\u5e38\u89c1\u7684HTTP\u65b9\u6cd5\u4e2d\u9009\u62e9\u4e00\u4e2a<\/p>\n<p>\u63a5\u4e0b\u6765\u6211\u4eec\u9700\u8981\u6765\u5339\u914d\u8d44\u6e90\u8def\u5f84<\/p>\n<p>\u00a0([^?]*)<\/p>\n<p>[^?]\u8868\u793a\u5339\u914d\u7684\u662f\u975e?\u7684\u5b57\u7b26&#xff0c;\u52a0\u4e0a\u540e\u9762\u7684*\u5c31\u8868\u793a\u5339\u914d\u975e&#xff1f;\u5b57\u7b260\u6b21\u6216\u591a\u6b21<\/p>\n<p>\u00a0\u540e\u9762\u7684user&#061;diluodexingzi&amp;pass&#061;123456\u662f\u6211\u4eec\u4e0d\u9700\u8981\u83b7\u53d6\u7684&#xff0c;\u53ea\u5339\u914d\u4f46\u662f\u4e0d\u6355\u83b7<\/p>\n<p>(?:\\\\\\\\?(.*))?<\/p>\n<p>(?:pattern)\u8868\u793a\u5339\u914dpattern\u4f46\u662f\u4e0d\u83b7\u53d6\u5339\u914d\u7ed3\u679c<\/p>\n<p>\\\\\\\\? \u8868\u793a\u539f\u59cb\u7684?\u5b57\u7b26&#xff0c;\u8fd9\u91cc\u8868\u793a\u4ee5?\u5b57\u7b26\u4f5c\u4e3a\u8d77\u59cb<\/p>\n<p>.*\u4ee3\u8868\u63d0\u53d6\u9664\\\\n\u4e4b\u5916\u7684\u4efb\u610f\u5b57\u7b260\u6b21\u6216\u591a\u6b21<\/p>\n<p>\u6700\u540e\u7684?\u8868\u793a\u5339\u914d\u524d\u9762\u7684\u8868\u8fbe\u5f0f0\u6b21\u6216\u8005\u4e00\u6b21&#xff0c;\u6709\u7684\u8bf7\u6c42\u662f\u6ca1\u6709\u67e5\u8be2\u5b57\u7b26\u4e32\u7684<\/p>\n<p>\u00a0\u6700\u540e\u6765\u5339\u914dHTTP\u7248\u672c<\/p>\n<p>(HTTP\/1\\\\\\\\.[01])(?:\\\\n|\\\\r\\\\n)?<\/p>\n<p>HTTP\/1 \u8868\u793a\u4ee5HTTP\/1\u5f00\u59cb\u7684\u5b57\u7b26\u4e32<\/p>\n<p>\\\\\\\\. \u8868\u793a\u5339\u914d . \u539f\u59cb\u5b57\u7b26<\/p>\n<p>[01]\u8868\u793a\u5339\u914d\u5b57\u7b26\u4e320\u6216\u80051\u5b57\u7b26<\/p>\n<p>(?:\\\\r\\\\n) \u8868\u793a\u5339\u914d\u4e00\u4e2a\\\\r\\\\n\u6216\u8005\\\\n\u5b57\u7b26&#xff0c;\u4f46\u662f\u4e0d\u6355\u6349\u8fd9\u4e2a\u5185\u5bb9<\/p>\n<p>\u603b\u7684\u6765\u8bf4\u5c31\u662f\u5339\u914d\u4ee5HTTP\/1.\u5f00\u59cb&#xff0c;\u540e\u9762\u8ddf\u4e86\u4e00\u4e2a0\u62161\u7684\u5b57\u7b26&#xff0c;\u4e14\u6700\u7ec8\u4ee5\\\\n\u6216\u8005\\\\r\\\\n\u4f5c\u4e3a\u7ed3\u5c3e\u7684\u5b57\u7b26\u4e32<\/p>\n<h3 id=\"1.3%20%E9%80%9A%E7%94%A8%E7%B1%BB%E5%9E%8BAny%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%AE%9E%E7%8E%B0\" style=\"background-color:transparent\">1.3 \u901a\u7528\u7c7b\u578bAny\u7c7b\u578b\u7684\u5b9e\u73b0<\/h3>\n<p>\u6bcf\u4e00\u4e2aConnection\u5bf9\u8fde\u63a5\u8fdb\u884c\u7ba1\u7406&#xff0c;\u6700\u7ec8\u90fd\u4e0d\u53ef\u907f\u514d\u9700\u8981\u6d89\u53ca\u5230\u5e94\u7528\u5c42\u534f\u8bae\u7684\u5904\u7406&#xff0c;\u56e0\u6b64\u5728Connection\u4e2d\u9700\u8981\u8bbe\u7f6e\u534f\u8bae\u5904\u7406\u7684\u4e0a\u4e0b\u6587\u6765\u63a7\u5236\u5904\u7406\u8282\u594f\u3002\u4f46\u662f\u5e94\u7528\u5c42\u534f\u8bae\u5343\u5343\u4e07&#xff0c;\u4e3a\u4e86\u964d\u4f4e\u8026\u5408\u5ea6&#xff0c;\u8fd9\u4e2a\u534f\u8bae\u63a5\u6536\u89e3\u6790\u4e0a\u4e0b\u6587\u5c31\u4e0d\u80fd\u6709\u660e\u663e\u7684\u534f\u8bae\u503e\u5411&#xff0c;\u5b83\u53ef\u4ee5\u662f\u4efb\u610f\u534f\u8bae\u7684\u4e0a\u4e0b\u6587\u4fe1\u606f\u56e0\u6b64\u5c31\u9700\u8981\u4e00\u4e2a\u901a\u7528\u7684\u7c7b\u578b\u6765\u4fdd\u5b58\u5404\u79cd\u4e0d\u540c\u7684\u6570\u636e\u7ed3\u6784\u3002<\/p>\n<p>\u4e3a\u4e86\u589e\u52a0\u4ee3\u7801\u7684\u53ef\u79fb\u690d\u6027&#xff0c;\u6211\u4eec\u51cf\u5c11\u5bf9\u7b2c\u4e09\u65b9\u5e93\u7684\u4f9d\u8d56&#xff0c;\u51b3\u5b9a\u81ea\u5df1\u6765\u5b9e\u73b0\u3002<\/p>\n<p>Any\u7c7b\u80af\u5b9a\u4e0d\u80fd\u662f\u4e00\u4e2a\u6a21\u7248\u7c7b&#xff0c;\u5426\u5219\u7f16\u8bd1\u7684\u65f6\u5019Any&lt;int&gt; a&#xff0c;Any&lt;float&gt; b&#xff0c;\u9700\u8981\u4f20\u5165\u7c7b\u578b\u4f5c\u4e3a\u6a21\u7248\u53c2\u6570&#xff0c;\u4e5f\u5c31\u662f\u8bf4\u5728\u4f7f\u7528\u7684\u65f6\u5019\u5c31\u8981\u786e\u5b9a\u5176\u7c7b\u578b\u3002  \u8fd9\u662f\u4e0d\u53ef\u4ee5\u7684&#xff0c;\u56e0\u4e3a\u4fdd\u5b58\u5728Content\u4e2d\u7684\u534f\u8bae\u4e0a\u4e0b\u6587&#xff0c;\u6211\u4eec\u5728\u5b9a\u4e49any\u5bf9\u8c61\u7684\u65f6\u5019\u662f\u4e0d\u77e5\u9053\u4ed6\u4eec\u7684\u534f\u8bae\u7c7b\u578b\u7684&#xff0c;\u56e0\u6b64\u65e0\u6cd5\u4f20\u9012\u7c7b\u578b\u4f5c\u4e3a\u6a21\u7248\u53c2\u6570  \u56e0\u6b64\u8003\u8651Any\u5185\u90e8\u8bbe\u8ba1\u4e00\u4e2a\u6a21\u7248\u5bb9\u5668holder\u7c7b&#xff0c;\u53ef\u4ee5\u4fdd\u5b58\u5404\u79cd\u7c7b\u578b\u6570\u636e  \u800c\u56e0\u4e3a\u5728Any\u7c7b\u4e2d\u65e0\u6cd5\u5b9a\u4e49\u8fd9\u4e2aholder\u5bf9\u8c61\u6216\u6307\u9488&#xff0c;\u56e0\u4e3aAny\u4e5f\u4e0d\u77e5\u9053\u8fd9\u4e2a\u7c7b\u8981\u4fdd\u5b58\u4ec0\u4e48\u7c7b\u578b\u7684\u6570\u636e&#xff0c;\u56e0\u6b64\u65e0\u6cd5\u4f20\u9012\u7c7b\u578b\u53c2\u6570  \u6240\u4ee5\u3002\u5b9a\u4e49\u4e00\u4e2a\u57fa\u7c7bplaceholder&#xff0c;\u8ba9holder\u7ee7\u627f\u4e8eplaceholder&#xff0c;\u800cAny\u7c7b\u4fdd\u5b58\u7236\u7c7b\u6307\u9488\u5373\u53ef  \u5f53\u9700\u8981\u4fdd\u5b58\u6570\u636e\u65f6&#xff0c;\u5219new\u4e00\u4e2a\u5e26\u6709\u6a21\u7248\u53c2\u6570\u7684\u5b50\u7c7bholder\u5bf9\u8c61\u53bb\u4fdd\u5b58\u6570\u636e\u3002\u7136\u540e\u8ba9Any\u7c7b\u4e2d\u7684\u7236\u7c7b\u6307\u9488&#xff0c;\u6307\u5411\u8fd9\u4e2a\u5b50\u7c7b\u5bf9\u8c61\u5c31\u53ef\u4ee5\u4e86<\/p>\n<p>Any\u7c7b\u7684\u5177\u4f53\u5b9e\u73b0&#xff1a;<\/p>\n<p>class Any<br \/>\n{<br \/>\nprivate:<br \/>\n    class holder<br \/>\n    {<br \/>\n    public:<br \/>\n        virtual ~holder()<br \/>\n        {}<br \/>\n        \/\/ \u6570\u636e\u7c7b\u578b<br \/>\n        virtual const std::type_info&amp; type() &#061; 0;<br \/>\n        \/\/ \u514b\u9686\u51fa\u65b0\u7684\u5bf9\u8c61<br \/>\n        virtual holder* clone() &#061; 0;<br \/>\n    };<br \/>\n    template&lt;class T&gt;<br \/>\n    class placeholder: public holder<br \/>\n    {<br \/>\n    public:<br \/>\n        placeholder(const T&amp; val): _val(val){}<br \/>\n        \/\/ \u83b7\u53d6\u5b50\u7c7b\u5bf9\u8c61\u4fdd\u5b58\u7684\u6570\u636e\u7c7b\u578b<br \/>\n        virtual const std::type_info&amp; type()<br \/>\n        {<br \/>\n            return typeid(T);<br \/>\n        }<br \/>\n        \/\/ \u9488\u5bf9\u51fa\u5f53\u524d\u7684\u5bf9\u8c61\u81ea\u8eab&#xff0c;\u514b\u9686\u51fa\u4e00\u4e2a\u65b0\u7684\u5bf9\u8c61<br \/>\n        virtual holder* clone()<br \/>\n        {<br \/>\n            return new placeholder(_val);<br \/>\n        }<br \/>\n    public:<br \/>\n        T _val;<br \/>\n    };<br \/>\n    holder* _content;<br \/>\n    public:<br \/>\n        Any():_content(NULL){}<br \/>\n        template&lt;class T&gt;<br \/>\n        Any(const T&amp; val):_content(new placeholder&lt;T&gt;(val)){}<br \/>\n        Any(const Any&amp; other):_content(other._content ? other._content-&gt;clone() : NULL) {}<br \/>\n        ~Any(){ delete _content;}<\/p>\n<p>        Any &amp;swap(Any&amp; other)<br \/>\n        {<br \/>\n            std::swap(_content, other._content);<br \/>\n            return *this;<br \/>\n        }   <\/p>\n<p>        template&lt;class T&gt;<br \/>\n        \/\/\u8fd4\u56de\u5b50\u7c7b\u5bf9\u8c61\u4fdd\u5b58\u7684\u6570\u636e\u7684\u6307\u9488<br \/>\n        T* get()<br \/>\n        {<br \/>\n            \/\/ \u60f3\u8981\u83b7\u53d6\u7684\u6570\u636e\u7c7b\u578b&#xff0c;\u5fc5\u987b\u548c\u4fdd\u5b58\u7684\u6570\u636e\u7c7b\u578b\u4e00\u81f4<br \/>\n            \/\/if(typeid(T) !&#061; _content-&gt;type()) return NULL;<br \/>\n            assert(typeid(T) &#061;&#061; _content-&gt;type());<br \/>\n            return &amp;((placeholder&lt;T&gt;*)_content)-&gt;_val;<br \/>\n        }<br \/>\n        \/\/\u8d4b\u503c\u8fd0\u7b97\u7b26\u91cd\u8f7d\u51fd\u6570<br \/>\n        template&lt;class T&gt;<br \/>\n        Any&amp; operator&#061;(const T&amp; val)<br \/>\n        {<br \/>\n            \/\/\u4e3aval\u6784\u9020\u4e00\u4e2a\u4e34\u65f6\u7684\u901a\u7528\u5bb9\u5668&#xff0c;\u7136\u540e\u4e0e\u5f53\u524d\u5bb9\u5668\u81ea\u8eab\u8fdb\u884c\u6307\u9488\u4ea4\u6362<br \/>\n            \/\/\u4e34\u65f6\u5bf9\u8c61\u91ca\u653e\u7684\u65f6\u5019&#xff0c;\u539f\u5148\u4fdd\u5b58\u7684\u6570\u636e\u4e5f\u5c31\u88ab\u91ca\u653e\u4e86<br \/>\n            Any(val).swap(*this);<br \/>\n            return *this;<br \/>\n        }<br \/>\n        Any&amp; operator&#061;(const Any&amp; other)<br \/>\n        {<br \/>\n            Any(other).swap(*this);<br \/>\n            return *this;<br \/>\n        }<br \/>\n}; <\/p>\n<h2 id=\"2.Server%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%A8%A1%E5%9D%97%E5%AE%9E%E7%8E%B0%EF%BC%9A\">2.Server\u670d\u52a1\u5668\u6a21\u5757\u5b9e\u73b0&#xff1a;<\/h2>\n<h3 id=\"2.1%20%E7%BC%93%E5%86%B2%E5%8C%BABuffer%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0\">2.1 \u7f13\u51b2\u533aBuffer\u7c7b\u7684\u5b9e\u73b0<\/h3>\n<p>Buffer\u7c7b\u7528\u4e8e\u5b9e\u73b0\u7528\u6237\u6001\u7f13\u51b2\u533a&#xff0c;\u63d0\u4f9b\u6570\u636e\u7f13\u51b2&#xff0c;\u53d6\u51fa\u7684\u529f\u80fd<\/p>\n<p>\u9996\u5148Buffer\u8fd9\u4e2a\u7c7b\u6709\u4e09\u4e2a\u79c1\u6709\u6210\u5458\u53d8\u91cf&#xff0c;\u5206\u522b\u662f_buffer&#xff0c;_reader_idx&#xff0c;_writer_idx\u3002\u8fd9\u4e09\u4e2a\u79c1\u6709\u6210\u5458\u5206\u522b\u4ee3\u8868\u7f13\u51b2\u533a&#xff0c;\u8bfb\u504f\u79fb\u548c\u5199\u504f\u79fb\u3002\u9700\u8981\u89e3\u91ca\u7684\u662f\u8bfb\u504f\u79fb\u662f\u6307\u8bfb\u5230\u7684\u4f4d\u7f6e&#xff0c;\u5199\u504f\u79fb\u662f\u6307\u5df2\u7ecf\u5199\u8fdb\u7f13\u51b2\u533a\u4e2d\u7684\u4f4d\u7f6e<\/p>\n<p>\u79c1\u6709\u6210\u5458\u53d8\u91cf\u7684\u4ee3\u7801\u5982\u4e0b&#xff1a;<\/p>\n<p>\/\/ \u4f7f\u7528vector\u8fdb\u884c\u5185\u5b58\u7a7a\u95f4\u7ba1\u7406<br \/>\nstd::vector&lt;char&gt; _buffer;<br \/>\nuint64_t _reader_idx; \/\/ \u8bfb\u504f\u79fb<br \/>\nuint64_t _writer_idx; \/\/ \u5199\u504f\u79fb <\/p>\n<p>\u9996\u5148\u6211\u4eec\u9700\u8981\u6709\u4e2a\u51fd\u6570\u80fd\u8fd4\u56de\u8fd9\u4e2a_buffer\u7684\u8d77\u59cb\u5730\u5740<\/p>\n<p>char* Begin()<br \/>\n{<br \/>\n    return &amp;*_buffer.begin();<br \/>\n} <\/p>\n<p>_buffer.begin()\u8fd4\u56de\u7684\u662f\u8fed\u4ee3\u5668\u7684\u521d\u59cb\u4f4d\u7f6e&#xff0c;\u6211\u4eec\u9700\u8981\u5bf9\u8fed\u4ee3\u5668\u8fdb\u884c\u89e3\u5f15\u7528\u7136\u540e\u53d6\u5730\u5740\u624d\u80fd\u83b7\u5f97char*\u7684\u5730\u5740\u3002<\/p>\n<p>\u7136\u540e\u6211\u4eec\u4e5f\u9700\u8981\u83b7\u5f97\u5f53\u524d\u5199\u5165\u8d77\u59cb\u5730\u5740\u548c\u5f53\u524d\u8bfb\u53d6\u8d77\u59cb\u5730\u5740<\/p>\n<p>\/\/ \u83b7\u53d6\u5f53\u524d\u5199\u5165\u8d77\u59cb\u5730\u5740<br \/>\nchar *WritePosition()<br \/>\n{<br \/>\n    \/\/_buffer\u7684\u7a7a\u95f4\u8d77\u59cb\u5730\u5740&#xff0c;\u52a0\u4e0a\u5199\u504f\u79fb\u91cf<br \/>\n    return Begin() &#043; _writer_idx;<br \/>\n}<br \/>\n\/\/ \u83b7\u53d6\u5f53\u524d\u8bfb\u53d6\u8d77\u59cb\u5730\u5740<br \/>\nchar *ReadPosition()<br \/>\n{<br \/>\n    return Begin() &#043; _reader_idx;<br \/>\n} <\/p>\n<p>\u83b7\u5f97\u7f13\u51b2\u533a\u672b\u5c3e\u548c\u8d77\u59cb\u7a7a\u95f4\u7684\u5927\u5c0f<\/p>\n<p>\/\/ \u83b7\u53d6\u7f13\u51b2\u533a\u672b\u5c3e\u7a7a\u95f2\u7a7a\u95f4\u5927\u5c0f&#8211;\u5199\u504f\u79fb\u4e4b\u540e\u7684\u7a7a\u95f2\u7a7a\u95f4<br \/>\nuint64_t TailIdleSize()<br \/>\n{<br \/>\n    return _buffer.size() &#8211; _writer_idx;<br \/>\n}<br \/>\n\/\/ \u83b7\u53d6\u7f13\u51b2\u533a\u8d77\u59cb\u7a7a\u95f2\u7a7a\u95f4\u5927\u5c0f&#8211;\u8bfb\u504f\u79fb\u4e4b\u524d\u7684\u7a7a\u95f2\u7a7a\u95f4<br \/>\nuint64_t HeadIdleSize()<br \/>\n{<br \/>\n    return _reader_idx;<br \/>\n} <\/p>\n<p>\u53ef\u8bfb\u6570\u636e\u7684\u5927\u5c0f\u5373\u662f\u5199\u504f\u79fb\u51cf\u53bb\u8bfb\u504f\u79fb<\/p>\n<p>\/\/ \u83b7\u53d6\u53ef\u8bfb\u6570\u636e\u5927\u5c0f<br \/>\nuint64_t ReadAbleSize()<br \/>\n{<br \/>\n    return _writer_idx &#8211; _reader_idx;<br \/>\n} <\/p>\n<p>\u8bfb\u5b8c\u6570\u636e\u6216\u8005\u5199\u5b8c\u6570\u636e\u90fd\u9700\u8981\u5c06\u8bfb\u504f\u79fb\u548c\u5199\u504f\u79fb\u5411\u540e\u79fb\u52a8<\/p>\n<p>\/\/ \u5c06\u8bfb\u504f\u79fb\u5411\u540e\u79fb\u52a8<br \/>\nvoid MoveReadOffset(uint64_t len)<br \/>\n{<br \/>\n    if (len &#061;&#061; 0)<br \/>\n        return;<br \/>\n    \/\/ \u5411\u540e\u79fb\u52a8\u7684\u5927\u5c0f&#xff0c;\u5fc5\u987b\u5c0f\u4e8e\u53ef\u8bfb\u6570\u636e\u7684\u5927\u5c0f<br \/>\n    assert(len &lt;&#061; ReadAbleSize());<br \/>\n    _reader_idx &#043;&#061; len;<br \/>\n}<br \/>\n\/\/ \u5c06\u5199\u504f\u79fb\u5411\u540e\u79fb\u52a8<br \/>\nvoid MoveWriteOffset(uint64_t len)<br \/>\n{<br \/>\n    \/\/ \u5411\u540e\u79fb\u52a8\u7684\u5927\u5c0f&#xff0c;\u5fc5\u987b\u5c0f\u4e8e\u5f53\u524d\u540e\u8fb9\u7684\u7a7a\u95f2\u7a7a\u95f4\u5927\u5c0f<br \/>\n    assert(len &lt;&#061; TailIdleSize());<br \/>\n    _writer_idx &#043;&#061; len;<br \/>\n} <\/p>\n<p>\u7136\u540e&#xff0c;\u6211\u4eec\u4e5f\u9700\u8981\u786e\u4fdd\u53ef\u5199\u7684\u7a7a\u95f4\u8db3\u591f&#xff0c;\u5982\u679c\u7a7a\u95f4\u591f\u5c31\u76f4\u63a5\u79fb\u52a8\u6570\u636e\u3002<\/p>\n<p>\u95ee\u9898\u6765\u4e86&#xff0c;\u5982\u4f55\u79fb\u52a8\u6570\u636e&#xff1f;<\/p>\n<p>\u5f88\u7b80\u5355&#xff0c;\u5373\u628a\u5728\u8bfb\u504f\u79fb\u548c\u5199\u504f\u79fb\u4e4b\u95f4\u7684\u6570\u636e\u90fd\u79fb\u52a8\u5230_buffer\u7684\u8d77\u59cb\u4f4d\u7f6e&#xff0c;\u8fd9\u91cc\u9700\u8981\u7528\u5230std::copy\u51fd\u6570&#xff0c;\u4e0b\u9762\u662f\u6211\u4eec\u9700\u8981\u7528\u5230\u7684copy\u51fd\u6570\u7684\u5b9a\u4e49<\/p>\n<p>inline char *std::copy&lt;char *, char *&gt;(char *__first, char *__last, char *__result)<\/p>\n<p>\u7b2c\u4e00\u4e2a\u548c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u5206\u522b\u8868\u793a\u6570\u636e\u7684\u8d77\u59cb\u4f4d\u7f6e\u548c\u7ed3\u675f\u4f4d\u7f6e&#xff0c;\u7b2c\u4e09\u4e2a\u53c2\u6570\u5219\u8868\u793a\u62f7\u8d1d\u5230\u7684\u4f4d\u7f6e<\/p>\n<p>\u5982\u679c\u5373\u4f7f\u79fb\u52a8\u6570\u636e&#xff0c;\u7a7a\u95f4\u8fd8\u662f\u4e0d\u591f&#xff0c;\u6211\u4eec\u5c31\u9700\u8981\u6269\u5bb9&#xff0c;\u4f7f\u7528\u5230\u7684\u51fd\u6570\u662fresize\u00a0<\/p>\n<p>\u4e0b\u9762\u662f\u8be6\u7ec6\u4ee3\u7801<\/p>\n<p>\/\/ \u786e\u4fdd\u53ef\u5199\u7a7a\u95f4\u8db3\u591f(\u8db3\u591f\u5c31\u79fb\u52a8\u6570\u636e&#xff0c;\u5426\u5219\u5c31\u6269\u5bb9)<br \/>\nvoid EnsureWriteSpace(uint64_t len)<br \/>\n{<br \/>\n    \/\/ \u5982\u679c\u672b\u5c3e\u7a7a\u95f2\u7a7a\u95f4\u5927\u5c0f\u8db3\u591f&#xff0c;\u76f4\u63a5\u8fd4\u56de<br \/>\n    if (TailIdleSize() &gt;&#061; len)<br \/>\n    {<br \/>\n        return;<br \/>\n    }<br \/>\n    \/\/ \u672b\u5c3e\u7a7a\u95f2\u7a7a\u95f4\u4e0d\u591f&#xff0c;\u5219\u5224\u65ad\u52a0\u4e0a\u8d77\u59cb\u4f4d\u7f6e\u7684\u7a7a\u95f2\u7a7a\u95f4\u5927\u5c0f\u662f\u5426\u8db3\u591f&#xff0c;\u591f\u4e86\u5c31\u5c06\u6570\u636e\u79fb\u52a8\u5230\u8d77\u59cb\u4f4d\u7f6e<br \/>\n    if (len &lt;&#061; TailIdleSize() &#043; HeadIdleSize())<br \/>\n    {<br \/>\n        \/\/ \u5c06\u6570\u636e\u79fb\u52a8\u5230\u8d77\u59cb\u4f4d\u7f6e<br \/>\n        uint64_t rsz &#061; ReadAbleSize();<br \/>\n        \/\/ \u628a\u53ef\u8bfb\u6570\u636e\u62f7\u8d1d\u5230\u8d77\u59cb\u4f4d\u7f6e<br \/>\n        std::copy(ReadPosition(), ReadPosition() &#043; rsz, Begin());<br \/>\n        _reader_idx &#061; 0;   \/\/ \u5c06\u8bfb\u504f\u79fb\u5f520<br \/>\n        _writer_idx &#061; rsz; \/\/ \u5c06\u5199\u4f4d\u7f6e\u7f6e\u4e3a\u53ef\u8bfb\u6570\u636e\u5927\u5c0f&#xff0c;\u56e0\u4e3a\u5f53\u524d\u7684\u53ef\u8bfb\u6570\u636e\u5927\u5c0f\u5c31\u662f\u5199\u504f\u79fb\u91cf<br \/>\n    }<br \/>\n    else<br \/>\n    {<br \/>\n        \/\/ \u603b\u4f53\u7a7a\u95f4\u4e0d\u591f&#xff0c;\u5219\u9700\u8981\u6269\u5bb9&#xff0c;\u4e0d\u79fb\u52a8\u6570\u636e&#xff0c;\u76f4\u63a5\u7ed9\u5199\u504f\u79fb\u4e4b\u540e\u6269\u5bb9\u8db3\u591f\u7a7a\u95f4\u5373\u53ef<br \/>\n        DBG_LOG(&#034;RESIZE %ld&#034;, _writer_idx &#043; len);<br \/>\n        _buffer.resize(_writer_idx &#043; len);<br \/>\n    }<br \/>\n} <\/p>\n<p>\u8981\u5199\u5165\u6570\u636e\u8fdb\u53bb&#xff0c;\u9700\u8981\u4e24\u6b65&#xff0c;\u5373\u4fdd\u8bc1\u6709\u8db3\u591f\u7a7a\u95f4\u548c\u62f7\u8d1d\u6570\u636e\u8fdb\u5165_buffer\u3002<\/p>\n<p>\/\/ \u5199\u5165\u6570\u636e<br \/>\nvoid Write(const void *data, uint64_t len)<br \/>\n{<br \/>\n    \/\/ 1.\u4fdd\u8bc1\u6709\u8db3\u591f\u7a7a\u95f4<br \/>\n    if (len &#061;&#061; 0)<br \/>\n        return;<br \/>\n    EnsureWriteSpace(len);<br \/>\n    const char *d &#061; (const char *)data;<br \/>\n    \/\/ 2.\u62f7\u8d1d\u6570\u636e\u8fdb\u53bb<br \/>\n    std::copy(d, d &#043; len, WritePosition());<br \/>\n} <\/p>\n<p>\u63a5\u4e0b\u6765\u7684\u51e0\u4e2a\u51fd\u6570\u90fd\u662f\u57fa\u4e8eWrite\u51fd\u6570\u7684\u62d3\u5c55\u96c6\u6210&#xff0c;\u5305\u62ec\u5199\u5165string\u3001Buffer\u7c7b\u578b\u7684\u6570\u636e<\/p>\n<p>void WriteAndPush(const void *data, uint64_t len)<br \/>\n{<br \/>\n    Write(data, len);<br \/>\n    MoveWriteOffset(len);<br \/>\n}<br \/>\nvoid WriteString(const std::string &amp;data)<br \/>\n{<br \/>\n    return Write(data.c_str(), data.size());<br \/>\n}<br \/>\nvoid WriteStringAndPush(const std::string &amp;data)<br \/>\n{<br \/>\n    WriteString(data);<br \/>\n    \/\/ std::cout &lt;&lt; WritePosition() &lt;&lt; std::endl;<br \/>\n    MoveWriteOffset(data.size());<br \/>\n    \/\/ std::cout &lt;&lt; ReadAbleSize() &lt;&lt; std::endl;<br \/>\n}<br \/>\nvoid WriteBuffer(Buffer &amp;data)<br \/>\n{<br \/>\n    return Write(data.ReadPosition(), data.ReadAbleSize());<br \/>\n}<br \/>\nvoid WriteBufferAndPush(Buffer &amp;data)<br \/>\n{<br \/>\n    WriteBuffer(data);<br \/>\n    MoveWriteOffset(data.ReadAbleSize());<br \/>\n} <\/p>\n<p>\u63a5\u4e0b\u6765\u7684\u662fRead\u51fd\u6570&#xff0c;\u5305\u542b\u4e24\u4e2a\u53c2\u6570\u5206\u522b\u662f\u628a\u6570\u636e\u8bfb\u5230\u90a3\u4e2a\u4f4d\u7f6e&#xff0c;\u548c\u8bfb\u53d6\u7684\u957f\u5ea6<\/p>\n<p>\/\/ \u8bfb\u53d6\u6570\u636e<br \/>\nvoid Read(void *buf, uint64_t len)<br \/>\n{<br \/>\n    assert(len &lt;&#061; ReadAbleSize());<br \/>\n    \/\/ std::cout &lt;&lt; ReadPosition() &lt;&lt; std::endl;<br \/>\n    std::copy(ReadPosition(), ReadPosition() &#043; len, (char *)buf);<br \/>\n} <\/p>\n<p>\u540c\u6837&#xff0c;\u4e0b\u9762\u7684\u51fd\u6570\u4e5f\u662f\u57fa\u4e8eRead\u51fd\u6570\u7684\u62d3\u5c55\u96c6\u6210<\/p>\n<p>void ReadAndPop(void *buf, uint64_t len)<br \/>\n{<br \/>\n    Read(buf, len);<br \/>\n    MoveReadOffset(len);<br \/>\n}<br \/>\n\/\/ \u628a\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u5f53\u505astring\u8bfb\u53d6<br \/>\nstd::string ReadAsString(uint64_t len)<br \/>\n{<br \/>\n    assert(len &lt;&#061; ReadAbleSize());<br \/>\n    std::string str;<br \/>\n    str.resize(len);<br \/>\n    Read(&amp;str[0], len);<br \/>\n    return str;<br \/>\n}<br \/>\nstd::string ReadAsStringAndPop(uint64_t len)<br \/>\n{<br \/>\n    assert(len &lt;&#061; ReadAbleSize());<br \/>\n    std::string str &#061; ReadAsString(len);<br \/>\n    MoveReadOffset(len);<br \/>\n    return str;<br \/>\n} <\/p>\n<p>\u5728\u8bfb\u53d6\u7684\u65f6\u5019&#xff0c;\u4f8b\u5982\u8bfb\u53d6Http\u534f\u8bae&#xff0c;\u5c31\u9700\u8981\u4e00\u884c\u4e00\u884c\u7684\u8bfb&#xff0c;\u8fd9\u65f6\u5019\u5c31\u9700\u8981\u8bfb\u53d6\u5230\u6bcf\u4e00\u884c\u7684\\\\r\\\\n&#xff0c;\u6240\u4ee5\u5c31\u6709\u4e86FindCRLF\u51fd\u6570\u4f7f\u7528\u5230\u7684\u662fcstring\u4e2d\u7684memchr\u51fd\u6570<\/p>\n<p>void *memchr(const void *buf, int c, size_t count);<\/p>\n<p>buf&#xff1a;\u6307\u5411\u5f85\u641c\u7d22\u5185\u5b58\u5757\u7684\u6307\u9488<\/p>\n<p>c&#xff1a;\u8981\u67e5\u627e\u7684\u5b57\u7b26<\/p>\n<p>count&#xff1a;\u8981\u641c\u7d22\u7684\u5b57\u8282\u6570<\/p>\n<p>\u7531\u4e8e\u6211\u4eec\u9700\u8981\u7684\u662fchar* \u7684\u8fd4\u56de\u503c&#xff0c;\u6240\u4ee5\u9700\u8981\u5f3a\u5236\u8f6c\u6362\u4e00\u4e0b<\/p>\n<p>char *FindCRLF()<br \/>\n{<br \/>\n    char *res &#061; (char *)memchr(ReadPosition(), &#039;\\\\n&#039;, ReadAbleSize());<br \/>\n    return res;<br \/>\n}<br \/>\n\/*\u901a\u5e38\u83b7\u53d6\u4e00\u884c\u6570\u636e&#xff0c;\u8fd9\u79cd\u60c5\u51b5\u9488\u5bf9\u662fHTTP\u534f\u8bae*\/<br \/>\nstd::string GetLine()<br \/>\n{<br \/>\n    char *pos &#061; FindCRLF();<br \/>\n    if (pos &#061;&#061; NULL)<br \/>\n    {<br \/>\n        return &#034;&#034;;<br \/>\n    }<br \/>\n    \/\/ &#043;1 \u662f\u4e3a\u4e86\u628a\u6362\u884c\u5b57\u7b26\u4e5f\u53d6\u51fa\u6765<br \/>\n    return ReadAsString(pos &#8211; ReadPosition() &#043; 1);<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662f\u8fd9\u4e2aBuffer\u7c7b\u7684\u6574\u4f53\u4ee3\u7801<\/p>\n<p>#define BUFFER_DEFAULT_SIZE 1024<br \/>\nclass Buffer<br \/>\n{<br \/>\nprivate:<br \/>\n    \/\/ \u4f7f\u7528vector\u8fdb\u884c\u5185\u5b58\u7a7a\u95f4\u7ba1\u7406<br \/>\n    std::vector&lt;char&gt; _buffer;<br \/>\n    uint64_t _reader_idx; \/\/ \u8bfb\u504f\u79fb<br \/>\n    uint64_t _writer_idx; \/\/ \u5199\u504f\u79fb<br \/>\npublic:<br \/>\n    Buffer() : _reader_idx(0), _writer_idx(0), _buffer(BUFFER_DEFAULT_SIZE) {}<br \/>\n    char *Begin() { return &amp;*_buffer.begin(); }<br \/>\n    void TestPrint()<br \/>\n    {<br \/>\n        for (auto e : _buffer)<br \/>\n        {<br \/>\n            std::cout &lt;&lt; e;<br \/>\n        }<br \/>\n    }<br \/>\n    \/\/ \u83b7\u53d6\u5f53\u524d\u5199\u5165\u8d77\u59cb\u5730\u5740<br \/>\n    char *WritePosition()<br \/>\n    {<br \/>\n        \/\/_buffer\u7684\u7a7a\u95f4\u8d77\u59cb\u5730\u5740&#xff0c;\u52a0\u4e0a\u5199\u504f\u79fb\u91cf<br \/>\n        return Begin() &#043; _writer_idx;<br \/>\n    }<br \/>\n    \/\/ \u83b7\u53d6\u5f53\u524d\u8bfb\u53d6\u8d77\u59cb\u5730\u5740<br \/>\n    char *ReadPosition()<br \/>\n    {<br \/>\n        return Begin() &#043; _reader_idx;<br \/>\n    }<br \/>\n    \/\/ \u83b7\u53d6\u7f13\u51b2\u533a\u672b\u5c3e\u7a7a\u95f2\u7a7a\u95f4\u5927\u5c0f&#8211;\u5199\u504f\u79fb\u4e4b\u540e\u7684\u7a7a\u95f2\u7a7a\u95f4<br \/>\n    uint64_t TailIdleSize()<br \/>\n    {<br \/>\n        return _buffer.size() &#8211; _writer_idx;<br \/>\n    }<br \/>\n    \/\/ \u83b7\u53d6\u7f13\u51b2\u533a\u8d77\u59cb\u7a7a\u95f2\u7a7a\u95f4\u5927\u5c0f&#8211;\u8bfb\u504f\u79fb\u4e4b\u524d\u7684\u7a7a\u95f2\u7a7a\u95f4<br \/>\n    uint64_t HeadIdleSize()<br \/>\n    {<br \/>\n        return _reader_idx;<br \/>\n    }<br \/>\n    \/\/ \u83b7\u53d6\u53ef\u8bfb\u6570\u636e\u5927\u5c0f<br \/>\n    uint64_t ReadAbleSize()<br \/>\n    {<br \/>\n        return _writer_idx &#8211; _reader_idx;<br \/>\n    }<br \/>\n    \/\/ \u5c06\u8bfb\u504f\u79fb\u5411\u540e\u79fb\u52a8<br \/>\n    void MoveReadOffset(uint64_t len)<br \/>\n    {<br \/>\n        if (len &#061;&#061; 0)<br \/>\n            return;<br \/>\n        \/\/ \u5411\u540e\u79fb\u52a8\u7684\u5927\u5c0f&#xff0c;\u5fc5\u987b\u5c0f\u4e8e\u53ef\u8bfb\u6570\u636e\u7684\u5927\u5c0f<br \/>\n        assert(len &lt;&#061; ReadAbleSize());<br \/>\n        _reader_idx &#043;&#061; len;<br \/>\n    }<br \/>\n    \/\/ \u5c06\u5199\u504f\u79fb\u5411\u540e\u79fb\u52a8<br \/>\n    void MoveWriteOffset(uint64_t len)<br \/>\n    {<br \/>\n        \/\/ \u5411\u540e\u79fb\u52a8\u7684\u5927\u5c0f&#xff0c;\u5fc5\u987b\u5c0f\u4e8e\u5f53\u524d\u540e\u8fb9\u7684\u7a7a\u95f2\u7a7a\u95f4\u5927\u5c0f<br \/>\n        assert(len &lt;&#061; TailIdleSize());<br \/>\n        _writer_idx &#043;&#061; len;<br \/>\n    }<br \/>\n    \/\/ \u786e\u4fdd\u53ef\u5199\u7a7a\u95f4\u8db3\u591f(\u8db3\u591f\u5c31\u79fb\u52a8\u6570\u636e&#xff0c;\u5426\u5219\u5c31\u6269\u5bb9)<br \/>\n    void EnsureWriteSpace(uint64_t len)<br \/>\n    {<br \/>\n        \/\/ \u5982\u679c\u672b\u5c3e\u7a7a\u95f2\u7a7a\u95f4\u5927\u5c0f\u8db3\u591f&#xff0c;\u76f4\u63a5\u8fd4\u56de<br \/>\n        if (TailIdleSize() &gt;&#061; len)<br \/>\n        {<br \/>\n            return;<br \/>\n        }<br \/>\n        \/\/ \u672b\u5c3e\u7a7a\u95f2\u7a7a\u95f4\u4e0d\u591f&#xff0c;\u5219\u5224\u65ad\u52a0\u4e0a\u8d77\u59cb\u4f4d\u7f6e\u7684\u7a7a\u95f2\u7a7a\u95f4\u5927\u5c0f\u662f\u5426\u8db3\u591f&#xff0c;\u591f\u4e86\u5c31\u5c06\u6570\u636e\u79fb\u52a8\u5230\u8d77\u59cb\u4f4d\u7f6e<br \/>\n        if (len &lt;&#061; TailIdleSize() &#043; HeadIdleSize())<br \/>\n        {<br \/>\n            \/\/ \u5c06\u6570\u636e\u79fb\u52a8\u5230\u8d77\u59cb\u4f4d\u7f6e<br \/>\n            uint64_t rsz &#061; ReadAbleSize();<br \/>\n            \/\/ \u628a\u53ef\u8bfb\u6570\u636e\u62f7\u8d1d\u5230\u8d77\u59cb\u4f4d\u7f6e<br \/>\n            std::copy(ReadPosition(), ReadPosition() &#043; rsz, Begin());<br \/>\n            _reader_idx &#061; 0;   \/\/ \u5c06\u8bfb\u504f\u79fb\u5f520<br \/>\n            _writer_idx &#061; rsz; \/\/ \u5c06\u5199\u4f4d\u7f6e\u7f6e\u4e3a\u53ef\u8bfb\u6570\u636e\u5927\u5c0f&#xff0c;\u56e0\u4e3a\u5f53\u524d\u7684\u53ef\u8bfb\u6570\u636e\u5927\u5c0f\u5c31\u662f\u5199\u504f\u79fb\u91cf<br \/>\n        }<br \/>\n        else<br \/>\n        {<br \/>\n            \/\/ \u603b\u4f53\u7a7a\u95f4\u4e0d\u591f&#xff0c;\u5219\u9700\u8981\u6269\u5bb9&#xff0c;\u4e0d\u79fb\u52a8\u6570\u636e&#xff0c;\u76f4\u63a5\u7ed9\u5199\u504f\u79fb\u4e4b\u540e\u6269\u5bb9\u8db3\u591f\u7a7a\u95f4\u5373\u53ef<br \/>\n            DBG_LOG(&#034;RESIZE %ld&#034;, _writer_idx &#043; len);<br \/>\n            _buffer.resize(_writer_idx &#043; len);<br \/>\n        }<br \/>\n    }<br \/>\n    \/\/ \u5199\u5165\u6570\u636e<br \/>\n    void Write(const void *data, uint64_t len)<br \/>\n    {<br \/>\n        \/\/ 1.\u4fdd\u8bc1\u6709\u8db3\u591f\u7a7a\u95f4<br \/>\n        if (len &#061;&#061; 0)<br \/>\n            return;<br \/>\n        EnsureWriteSpace(len);<br \/>\n        const char *d &#061; (const char *)data;<br \/>\n        \/\/ 2.\u62f7\u8d1d\u6570\u636e\u8fdb\u53bb<br \/>\n        std::copy(d, d &#043; len, WritePosition());<br \/>\n    }<br \/>\n    void WriteAndPush(const void *data, uint64_t len)<br \/>\n    {<br \/>\n        Write(data, len);<br \/>\n        MoveWriteOffset(len);<br \/>\n    }<br \/>\n    void WriteString(const std::string &amp;data)<br \/>\n    {<br \/>\n        return Write(data.c_str(), data.size());<br \/>\n    }<br \/>\n    void WriteStringAndPush(const std::string &amp;data)<br \/>\n    {<br \/>\n        WriteString(data);<br \/>\n        \/\/ std::cout &lt;&lt; WritePosition() &lt;&lt; std::endl;<br \/>\n        MoveWriteOffset(data.size());<br \/>\n        \/\/ std::cout &lt;&lt; ReadAbleSize() &lt;&lt; std::endl;<br \/>\n    }<br \/>\n    void WriteBuffer(Buffer &amp;data)<br \/>\n    {<br \/>\n        return Write(data.ReadPosition(), data.ReadAbleSize());<br \/>\n    }<br \/>\n    void WriteBufferAndPush(Buffer &amp;data)<br \/>\n    {<br \/>\n        WriteBuffer(data);<br \/>\n        MoveWriteOffset(data.ReadAbleSize());<br \/>\n    }<br \/>\n    \/\/ \u8bfb\u53d6\u6570\u636e<br \/>\n    void Read(void *buf, uint64_t len)<br \/>\n    {<br \/>\n        assert(len &lt;&#061; ReadAbleSize());<br \/>\n        \/\/ std::cout &lt;&lt; ReadPosition() &lt;&lt; std::endl;<br \/>\n        std::copy(ReadPosition(), ReadPosition() &#043; len, (char *)buf);<br \/>\n    }<br \/>\n    void ReadAndPop(void *buf, uint64_t len)<br \/>\n    {<br \/>\n        Read(buf, len);<br \/>\n        MoveReadOffset(len);<br \/>\n    }<br \/>\n    \/\/ \u628a\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u5f53\u505astring\u8bfb\u53d6<br \/>\n    std::string ReadAsString(uint64_t len)<br \/>\n    {<br \/>\n        assert(len &lt;&#061; ReadAbleSize());<br \/>\n        std::string str;<br \/>\n        str.resize(len);<br \/>\n        Read(&amp;str[0], len);<br \/>\n        return str;<br \/>\n    }<br \/>\n    std::string ReadAsStringAndPop(uint64_t len)<br \/>\n    {<br \/>\n        assert(len &lt;&#061; ReadAbleSize());<br \/>\n        std::string str &#061; ReadAsString(len);<br \/>\n        MoveReadOffset(len);<br \/>\n        return str;<br \/>\n    }<br \/>\n    char *FindCRLF()<br \/>\n    {<br \/>\n        char *res &#061; (char *)memchr(ReadPosition(), &#039;\\\\n&#039;, ReadAbleSize());<br \/>\n        return res;<br \/>\n    }<br \/>\n    \/*\u901a\u5e38\u83b7\u53d6\u4e00\u884c\u6570\u636e&#xff0c;\u8fd9\u79cd\u60c5\u51b5\u9488\u5bf9\u662fHTTP\u534f\u8bae*\/<br \/>\n    std::string GetLine()<br \/>\n    {<br \/>\n        char *pos &#061; FindCRLF();<br \/>\n        if (pos &#061;&#061; NULL)<br \/>\n        {<br \/>\n            return &#034;&#034;;<br \/>\n        }<br \/>\n        \/\/ &#043;1 \u662f\u4e3a\u4e86\u628a\u6362\u884c\u5b57\u7b26\u4e5f\u53d6\u51fa\u6765<br \/>\n        return ReadAsString(pos &#8211; ReadPosition() &#043; 1);<br \/>\n    }<br \/>\n    std::string GetLineAndPop()<br \/>\n    {<br \/>\n        std::string str &#061; GetLine();<br \/>\n        MoveReadOffset(str.size());<br \/>\n        return str;<br \/>\n    }<br \/>\n    \/\/ \u6e05\u7a7a\u7f13\u51b2\u533a<br \/>\n    void Clear()<br \/>\n    {<br \/>\n        \/\/ \u53ea\u9700\u8981\u5c06\u504f\u79fb\u91cf\u5f52\u96f6<br \/>\n        _reader_idx &#061; 0;<br \/>\n        _writer_idx &#061; 0;<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"2.2%20%E6%97%A5%E5%BF%97%E5%AE%8F%E7%9A%84%E5%AE%9E%E7%8E%B0\">2.2 \u65e5\u5fd7\u5b8f\u7684\u5b9e\u73b0<\/h3>\n<p>\u4f5c\u4e3a\u4e00\u540d\u5408\u683c\u7684\u7a0b\u5e8f\u5458&#xff0c;\u65e5\u5fd7\u5b8f\u662f\u4e0d\u53ef\u6216\u7f3a\u7684&#xff0c;\u6211\u4eec\u5c06\u5728\u8fd9\u91cc\u5199\u4e00\u4e2a\u7b80\u5355\u7684\u65e5\u5fd7\u5b8f<\/p>\n<p>\u9996\u5148\u6211\u4eec\u7684\u65e5\u5fd7\u5e94\u8be5\u5305\u542b\u65e5\u5fd7\u7b49\u7ea7&#xff0c;\u65b9\u4fbf\u6211\u4eec\u8c03\u8bd5&#xff0c;\u8fd9\u91cc\u6211\u4eec\u7ed9\u51fa\u4e86\u4e09\u79cd\u7b49\u7ea7\u7684\u65e5\u5fd7\u7b49\u7ea7<\/p>\n<p>INF&#xff0c;DBG&#xff0c;ERR&#xff0c;\u5206\u522b\u8bbe\u7f6e\u4e3a0 1 2 \u7136\u540e1\u4ee5\u4e0a\u7684\u65e5\u5fd7\u7b49\u7ea7\u5c06\u6253\u5370\u51fa\u5177\u4f53\u7684\u65e5\u5fd7\u4fe1\u606f<\/p>\n<p>\u6211\u4eec\u4e5f\u60f3\u65e5\u5fd7\u80fd\u6253\u5370\u51fa\u73b0\u5728\u7684\u65f6\u95f4&#xff0c;\u9700\u8981\u4f7f\u7528\u5230ctime\u8fd9\u4e2a\u5934\u6587\u4ef6<\/p>\n<p>\u91cc\u9762\u6709\u4e00\u4e2atm\u7ed3\u6784\u4f53&#xff0c;\u5b9a\u4e49\u5982\u4e0b&#xff1a;<\/p>\n<p>struct tm<\/p>\n<p>{<\/p>\n<p>\u00a0 int tm_sec; \u00a0 \u00a0 \u00a0 \u00a0\/* Seconds. [0-60] (1 leap second) *\/<\/p>\n<p>\u00a0 int tm_min; \u00a0 \u00a0 \u00a0 \u00a0\/* Minutes. [0-59] *\/<\/p>\n<p>\u00a0 int tm_hour; \u00a0 \u00a0 \u00a0 \/* Hours. \u00a0 [0-23] *\/<\/p>\n<p>\u00a0 int tm_mday; \u00a0 \u00a0 \u00a0 \/* Day. \u00a0 \u00a0 [1-31] *\/<\/p>\n<p>\u00a0 int tm_mon; \u00a0 \u00a0 \u00a0 \u00a0\/* Month. \u00a0 [0-11] *\/<\/p>\n<p>\u00a0 int tm_year; \u00a0 \u00a0 \u00a0 \/* Year \u00a0&#8211; 1900. \u00a0*\/<\/p>\n<p>\u00a0 int tm_wday; \u00a0 \u00a0 \u00a0 \/* Day of week. \u00a0 [0-6] *\/<\/p>\n<p>\u00a0 int tm_yday; \u00a0 \u00a0 \u00a0 \/* Days in year.[0-365] *\/<\/p>\n<p>\u00a0 int tm_isdst; \u00a0 \u00a0 \u00a0 \u00a0 \/* DST. \u00a0 \u00a0 [-1\/0\/1]*\/<\/p>\n<p>}<\/p>\n<p>\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528localtime\u8fd9\u4e2a\u51fd\u6570\u6765\u628a\u65f6\u95f4\u6233\u7684\u4fe1\u606f\u8f6c\u79fb\u5230\u8fd9\u4e2atm\u7ed3\u6784\u4f53\u5f53\u4e2d\u7136\u540e\u8bfb\u53d6&#xff0c;\u5728\u4ee5\u7279\u5b9a\u683c\u5f0f\u6765\u6253\u5370\u51fa\u65f6\u95f4<\/p>\n<p>\u8fd9\u91cc\u6709\u51e0\u4e2a\u5c0f\u7684\u77e5\u8bc6\u70b9<\/p>\n<p>1.\u5982\u4f55\u6253\u5370\u5bf9\u5e94\u7684\u884c\u53f7\u548c\u6587\u4ef6\u5462&#xff1f;<\/p>\n<p>\u53ef\u4ee5\u4f7f\u7528__FILE__ \u548c __LINE__ \u4e24\u4e2a\u5b8f\u5b9a\u4e49\u6765\u6253\u5370\u5bf9\u5e94\u7684\u6587\u4ef6\u540d\u548c\u884c\u53f7<\/p>\n<p>2.\u5b8f\u5b9a\u4e49\u4e2d\u7684\u53ef\u53d8\u53c2\u6570\u8be5\u5982\u4f55\u8868\u793a\u5462&#xff1f;<\/p>\n<p>\u4f7f\u7528##__VA_ARGS__\u6765\u8868\u793a<\/p>\n<p>\u4e0b\u9762\u5c31\u662f\u8be6\u7ec6\u7684\u4ee3\u7801<\/p>\n<p>#define INF 0<br \/>\n#define DBG 1<br \/>\n#define ERR 2<br \/>\n#define LOG_LEVEL DBG<br \/>\n#define LOG(level, format, &#8230;)                                                                                       \\\\<br \/>\n    do                                                                                                                \\\\<br \/>\n    {                                                                                                                 \\\\<br \/>\n        if (level &lt; LOG_LEVEL)                                                                                        \\\\<br \/>\n            break;                                                                                                    \\\\<br \/>\n        time_t t &#061; time(NULL);                                                                                        \\\\<br \/>\n        struct tm *ltm &#061; localtime(&amp;t);                                                                               \\\\<br \/>\n        char tmp[32] &#061; {0};                                                                                           \\\\<br \/>\n        strftime(tmp, 31, &#034;%H:%M:%S&#034;, ltm);                                                                           \\\\<br \/>\n        fprintf(stdout, &#034;[%p %s %s:%d]&#034; format &#034;\\\\n&#034;, (void *)pthread_self(), tmp, __FILE__, __LINE__, ##__VA_ARGS__); \\\\<br \/>\n    } while (0)<br \/>\n#define INF_LOG(format, &#8230;) LOG(INF, format, ##__VA_ARGS__)<br \/>\n#define DBG_LOG(format, &#8230;) LOG(DBG, format, ##__VA_ARGS__)<br \/>\n#define ERR_LOG(format, &#8230;) LOG(ERR, format, ##__VA_ARGS__) <\/p>\n<h3 id=\"%C2%A02.3%20%E5%A5%97%E6%8E%A5%E5%AD%97%E6%A8%A1%E5%9D%97%E7%9A%84%E5%AE%9E%E7%8E%B0\">\u00a02.3 \u5957\u63a5\u5b57\u6a21\u5757\u7684\u5b9e\u73b0<\/h3>\n<p>\u5957\u63a5\u5b57\u662f\u670d\u52a1\u5668\u7f16\u7a0b\u4e2d\u4e0d\u53ef\u7f3a\u5c11\u7684&#xff0c;\u6211\u4eec\u4f7f\u7528\u4e00\u4e2a\u7ed3\u6784\u4f53Socket\u6765\u7edf\u4e00\u7ba1\u7406<\/p>\n<p>1.\u9996\u5148\u5c01\u88c5\u521b\u5efa\u5957\u63a5\u5b57\u7684\u51fd\u6570Create()<\/p>\n<p> bool Create()<br \/>\n{<br \/>\n    _sockfd &#061; socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);<br \/>\n    if (_sockfd &lt; 0)<br \/>\n    {<br \/>\n        ERR_LOG(&#034;CREATE SOCKET FAILED!!&#034;);<br \/>\n        return false;<br \/>\n    }<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u8fd9\u91cc\u89e3\u91ca\u4e00\u4e0bsocket\u7684\u4e09\u4e2a\u53c2\u6570&#xff0c;\u7b2c\u4e00\u4e2a\u53c2\u6570\u8868\u793a\u4f7f\u7528IPV4\u534f\u8bae&#xff0c;\u7b2c\u4e8c\u4e2a\u53c2\u6570\u8868\u793a\u4f7f\u7528\u9762\u5411\u8fde\u63a5\u7684\u5957\u63a5\u5b57&#xff0c;\u7b2c\u4e09\u4e2a\u53c2\u6570\u8868\u793a\u9009\u62e9TCP\u534f\u8bae&#xff0c;\u4e5f\u53ef\u4ee5\u628a\u7b2c\u4e09\u4e2a\u53c2\u6570\u76f4\u63a5\u5199\u62100&#xff0c;\u7cfb\u7edf\u4f1a\u81ea\u52a8\u9009\u62e9\u534f\u8bae<\/p>\n<p> 2.\u5c01\u88c5\u7ed1\u5b9a\u5730\u5740\u4fe1\u606f\u7684\u51fd\u6570Bind()&#xff0c;\u4f20\u5165\u4e24\u4e2a\u53c2\u6570\u5373\u53ef&#xff0c;\u5373ip\u548cport<\/p>\n<p> bool Bind(const std::string &amp;ip, uint16_t port)<br \/>\n{<br \/>\n    struct sockaddr_in addr;<br \/>\n    addr.sin_family &#061; AF_INET;<br \/>\n    addr.sin_port &#061; htons(port);<br \/>\n    addr.sin_addr.s_addr &#061; inet_addr(ip.c_str());<br \/>\n    socklen_t len &#061; sizeof(struct sockaddr_in);<br \/>\n    int ret &#061; bind(_sockfd, (struct sockaddr *)&amp;addr, len);<br \/>\n    if (ret &lt; 0)<br \/>\n    {<br \/>\n        ERR_LOG(&#034;BIND ADDRESS FAILED!&#034;);<br \/>\n        return false;<br \/>\n    }<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u5176\u4e2dsockaddr_in \u8fd9\u4e2a\u7ed3\u6784\u4f53\u5305\u542b\u4e09\u4e2a\u6210\u5458&#xff0c;\u5206\u522b\u662fsin_family&#xff0c;sin_port&#xff0c;sin_addr<\/p>\n<p>sin_family&#xff1a;sin_family\u8bbe\u7f6e\u4e3aAF_INET\u8868\u793a\u4f7f\u7528IPV4\u534f\u8bae<\/p>\n<p>sin_port&#xff1a;\u4f20\u5165sin_port\u53c2\u6570\u7684\u65f6\u5019&#xff0c;\u9700\u8981\u5c06\u4e3b\u673a\u5b57\u8282\u5e8f\u8f6c\u5316\u4e3a\u7f51\u7edc\u5b57\u8282\u5e8f\u3002\u56e0\u4e3a\u7f51\u7edc\u534f\u8bae\u4e2d\u7edf\u4e00\u4f7f\u7528\u5927\u7aef\u6a21\u5f0f\u4f5c\u4e3a\u6807\u51c6\u5b57\u8282\u5e8f<\/p>\n<p>sin_addr&#xff1a;\u9700\u8981\u4f7f\u7528inet_addr\u628a\u70b9\u5206\u5341\u8fdb\u5236\u5b57\u7b26\u4e32\u8f6c\u5316\u4e3a\u7f51\u7edc\u5b57\u8282\u5e8f\u768432\u4f4d\u65e0\u7b26\u53f7\u6574\u6570\u7684\u51fd\u6570<\/p>\n<p>\u63a5\u4e0b\u6765\u89e3\u91cabind\u51fd\u6570&#xff0c;\u7b2c\u4e00\u4e2a\u53c2\u6570\u4f20\u5165\u521b\u5efa\u51fa\u6765\u7684\u5957\u63a5\u5b57&#xff0c; \u7b2c\u4e8c\u4e2a\u53c2\u6570\u662faddr\u5f3a\u8f6c\u7684\u5730\u5740&#xff0c;\u7b2c\u4e09\u4e2a\u53c2\u6570\u8868\u793a\u8868\u793aaddr\u7684\u5927\u5c0f<\/p>\n<p> 3.\u7ed1\u5b9a\u597d\u5730\u5740\u4fe1\u606f\u540e&#xff0c;\u5c31\u8981\u5f00\u59cb\u76d1\u542c\u4e86&#xff0c;\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528Listen\u51fd\u6570\u6765\u5305\u88c5&#xff0c;Listen\u4f20\u5165\u4e00\u4e2a\u7f3a\u7701\u53c2\u6570backlog<\/p>\n<p> bool Listen(int backlog &#061; MAX_LISTEN)<br \/>\n{<br \/>\n    int ret &#061; listen(_sockfd, backlog);<br \/>\n    if (ret &lt; 0)<br \/>\n    {<br \/>\n        ERR_LOG(&#034;SOCKET LISTEN FAILED!&#034;);<br \/>\n        return false;<br \/>\n    }<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u8fd9\u91cc\u89e3\u91ca\u4e00\u4e0blisten\u51fd\u6570\u7684\u4e24\u4e2a\u53c2\u6570&#xff0c;\u7b2c\u4e00\u4e2a\u53c2\u6570\u8868\u793a\u4f20\u5165\u7684\u5957\u63a5\u5b57&#xff0c;\u7b2c\u4e8c\u4e2a\u53c2\u6570\u8868\u793a\u5b9a\u4e49\u4e86\u00a0\u5df2\u5b8c\u6210\u8fde\u63a5\u961f\u5217&#xff08;ESTABLISHED \u72b6\u6001&#xff09;\u7684\u6700\u5927\u957f\u5ea6\u3002<\/p>\n<p> 4.\u63a5\u4e0b\u6765\u5c31\u662f\u5411\u670d\u52a1\u5668\u53d1\u8d77\u8fde\u63a5Connect()&#xff0c;\u4f20\u5165\u4e24\u4e2a\u53c2\u6570&#xff0c;ip\u548cport<\/p>\n<p> bool Connect(const std::string &amp;ip, uint16_t port)<br \/>\n{<br \/>\n    struct sockaddr_in addr;<br \/>\n    addr.sin_family &#061; AF_INET;<br \/>\n    addr.sin_port &#061; htons(port);<br \/>\n    addr.sin_addr.s_addr &#061; inet_addr(ip.c_str());<br \/>\n    socklen_t len &#061; sizeof(struct sockaddr_in);<br \/>\n    int ret &#061; connect(_sockfd, (struct sockaddr *)&amp;addr, len);<br \/>\n    if (ret &lt; 0)<br \/>\n    {<br \/>\n        ERR_LOG(&#034;CONNECT ADDRESS FAILED!&#034;);<br \/>\n        return false;<br \/>\n    }<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u8fd9\u91ccconnect\u7684\u53c2\u6570\u5c31\u4e0d\u591a\u8bf4<\/p>\n<p> ssize_t Recv(void *buf, size_t len, int flag &#061; 0) \/\/ flag\u4ee3\u8868\u8bbe\u7f6e\u4e00\u4e9b\u963b\u585e\u76f8\u5173\u7684\u64cd\u4f5c<br \/>\n{<br \/>\n    ssize_t ret &#061; recv(_sockfd, buf, len, flag);<br \/>\n    if (ret &lt;&#061; 0)<br \/>\n    {<br \/>\n        if (errno &#061;&#061; EAGAIN || errno &#061;&#061; EINTR)<br \/>\n        {<br \/>\n            return 0;<br \/>\n        }<br \/>\n        ERR_LOG(&#034;SOCKET RECV FAILED!&#034;);<br \/>\n        return -1;<br \/>\n    }<br \/>\n    return ret;<br \/>\n} <\/p>\n<p> 5. \u83b7\u53d6\u65b0\u94fe\u63a5\u4f7f\u7528Accept()\u51fd\u6570\u6765\u5c01\u88c5<\/p>\n<p> int Accept()<br \/>\n{<br \/>\n    int newfd &#061; accept(_sockfd, NULL, NULL);<br \/>\n    if (newfd &lt; 0)<br \/>\n    {<br \/>\n        ERR_LOG(&#034;SOCKET ACCEPT FAILED!&#034;);<br \/>\n        return -1;<br \/>\n    }<br \/>\n    return newfd;<br \/>\n} <\/p>\n<p>\u8fd9\u91cc\u6211\u4eec\u9009\u62e9\u5c06accept\u7684\u7b2c\u4e8c\u4e2a\u548c\u7b2c\u4e09\u4e2a\u53c2\u6570\u90fd\u8bbe\u7f6e\u4e3aNULL\u8868\u793a\u6211\u4eec\u4e0d\u5173\u5fc3\u5ba2\u6237\u7aef\u5730\u5740\u4fe1\u606f\u3002\u6240\u4ee5\u53ea\u4f20\u5165\u4e86\u7b2c\u4e00\u4e2a\u53c2\u6570\u5957\u63a5\u5b57&#xff0c;\u7528\u4e8e\u4ece\u5df2\u5b8c\u6210\u8fde\u63a5\u961f\u5217\u4e2d\u63d0\u53d6\u8fde\u63a5<\/p>\n<p> 6.\u4f7f\u7528Recv()\u51fd\u6570\u6765\u63a5\u53d7\u6570\u636e<\/p>\n<p> ssize_t Recv(void *buf, size_t len, int flag &#061; 0) \/\/ flag\u4ee3\u8868\u8bbe\u7f6e\u4e00\u4e9b\u963b\u585e\u76f8\u5173\u7684\u64cd\u4f5c<br \/>\n{<br \/>\n    ssize_t ret &#061; recv(_sockfd, buf, len, flag);<br \/>\n    if (ret &lt;&#061; 0)<br \/>\n    {<br \/>\n        if (errno &#061;&#061; EAGAIN || errno &#061;&#061; EINTR)<br \/>\n        {<br \/>\n            return 0;<br \/>\n        }<br \/>\n        ERR_LOG(&#034;SOCKET RECV FAILED!&#034;);<br \/>\n        return -1;<br \/>\n    }<br \/>\n    return ret;<br \/>\n} <\/p>\n<p>recv\u6709\u56db\u4e2a\u53c2\u6570&#xff0c;\u7b80\u5355\u89e3\u91ca\u4e00\u4e0b&#xff0c;\u7b2c\u4e00\u4e2a\u53c2\u6570\u4f20\u5165\u5957\u63a5\u5b57&#xff0c;\u7b2c\u4e8c\u4e2a\u53c2\u6570\u8868\u793a\u63a5\u53d7\u7684\u6570\u636e\u653e\u5230\u7684\u4f4d\u7f6e&#xff0c;\u7b2c\u4e09\u4e2a\u53c2\u6570\u8868\u793a\u5355\u6b21\u63a5\u53d7\u7684\u6570\u636e\u91cf&#xff0c;flags\u63a7\u5236\u63a5\u6536\u884c\u4e3a\u7684\u6807\u5fd7\u4f4d\u3002\u4f20\u51650\u8868\u793a\u963b\u585e\u8bfb\u53d6\u3002<\/p>\n<p> 7.\u518d\u6b21\u5c01\u88c5\u4e00\u4e2a\u51fd\u6570NonBlockRecv\u8868\u793a\u975e\u963b\u585e\u63a5\u53d7<\/p>\n<p> ssize_t NonBlockRecv(void *buf, size_t len)<br \/>\n{<br \/>\n    if (len &#061;&#061; 0)<br \/>\n        return 0;<br \/>\n    return Recv(buf, len, MSG_DONTWAIT);<br \/>\n} <\/p>\n<p>MSG_DONTWAIT\u8868\u793a\u4e0d\u8981\u7b49\u5f85\u7684\u63a5\u53d7<\/p>\n<p> 8.\u53d1\u9001\u6570\u636e\u5c01\u88c5\u4e00\u4e2aSend()\u51fd\u6570&#xff0c;\u5c01\u88c5\u4e09\u4e2a\u53c2\u6570\u5206\u522b\u662f\u53d1\u9001\u6570\u636e\u7684\u4f4d\u7f6e&#xff0c;len\u8868\u793a\u53d1\u9001\u6570\u636e\u7684\u5927\u5c0f&#xff0c;\u7b2c\u4e09\u4e2a\u53c2\u6570\u4e3aflag\u548cRecv\u53c2\u6570\u4e00\u6837<\/p>\n<p> ssize_t Send(const void *buf, size_t len, int flag &#061; 0)<br \/>\n{<br \/>\n    \/\/ ssize_t send(int sockfd, void* data, size_t len, int flag);<br \/>\n    ssize_t ret &#061; send(_sockfd, buf, len, flag);<br \/>\n    if (ret &lt; 0)<br \/>\n    {<br \/>\n        if (errno &#061;&#061; EAGAIN || errno &#061;&#061; EINTR)<br \/>\n        {<br \/>\n            return 0;<br \/>\n        }<br \/>\n        ERR_LOG(&#034;SOCKET SEND FAILED!&#034;);<br \/>\n        return -1;<br \/>\n    }<br \/>\n    return ret;<br \/>\n} <\/p>\n<p>send\u7684\u53c2\u6570\u5c31\u4e0d\u591a\u89e3\u91ca\u4e86  9.\u5c01\u88c5\u4e00\u4e2aNonBlockSend\u51fd\u6570\u8868\u793a\u975e\u963b\u585e\u53d1\u9001<\/p>\n<p> ssize_t NonBlockSend(void *buf, size_t len)<br \/>\n{<br \/>\n    if (len &#061;&#061; 0)<br \/>\n        return 0;<br \/>\n    return Send(buf, len, MSG_DONTWAIT);<br \/>\n} <\/p>\n<p>\u8fd9\u91cc\u540c\u6837\u4f7f\u7528MSG_DONTWAIT\u6765\u8868\u793a\u975e\u963b\u585e<\/p>\n<p> 10.\u5957\u63a5\u5b57\u4f7f\u7528\u5b8c\u6bd5\u540e\u9700\u8981\u5173\u95ed&#xff0c;\u8c61\u6587\u4ef6\u63cf\u8ff0\u7b26\u4e00\u6837<\/p>\n<p> void Close()<br \/>\n{<br \/>\n    if (_sockfd !&#061; -1)<br \/>\n    {<br \/>\n        close(_sockfd);<br \/>\n        _sockfd &#061; -1;<br \/>\n    }<br \/>\n} <\/p>\n<p>11.\u521b\u5efa\u4e00\u4e2a\u670d\u52a1\u5668\u8fde\u63a5&#xff0c;\u5728\u8fd9\u91cc\u5206\u4e3a5\u4e2a\u6b65\u9aa4&#xff0c;\u521b\u5efa\u5957\u63a5\u5b57&#xff0c;\u8bbe\u7f6e\u975e\u963b\u585e&#xff0c;\u7ed1\u5b9a\u5730\u5740&#xff0c;\u5f00\u59cb\u76d1\u542c&#xff0c;\u542f\u52a8\u5730\u5740\u91cd\u7528<\/p>\n<p> bool CreateServer(uint16_t port, const std::string &amp;ip &#061; &#034;0.0.0.0&#034;, bool block_flag &#061; false)<br \/>\n{<br \/>\n    \/\/ \u521b\u5efa\u5957\u63a5\u5b57<br \/>\n    if (Create() &#061;&#061; false)<br \/>\n        return false;<br \/>\n    \/\/ \u8bbe\u7f6e\u975e\u963b\u585e<br \/>\n    if (block_flag)<br \/>\n        NonBlock();<br \/>\n    \/\/ \u7ed1\u5b9a\u5730\u5740<br \/>\n    if (Bind(ip, port) &#061;&#061; false)<br \/>\n        return false;<br \/>\n    \/\/ \u5f00\u59cb\u76d1\u542c<br \/>\n    if (Listen() &#061;&#061; false)<br \/>\n        return false;<br \/>\n    \/\/ \u542f\u52a8\u5730\u5740\u91cd\u7528<br \/>\n    ReuseAddress();<br \/>\n    return true;<br \/>\n} <\/p>\n<p> 12.\u521b\u5efa\u4e00\u4e2a\u5ba2\u6237\u7aef\u8fde\u63a5&#xff0c;\u5206\u4e3a\u4e24\u4e2a\u6b65\u9aa4&#xff1a;Create\u548cConnect\u5982\u4e0b\u4ee3\u7801\u6240\u793a<\/p>\n<p> bool CreateClient(uint16_t port, const std::string &amp;ip)<br \/>\n{<br \/>\n    \/\/ 1.\u521b\u5efa\u5957\u63a5\u5b57&#xff0c; 2.\u6307\u5411\u8fde\u63a5\u670d\u52a1\u5668<br \/>\n    if (Create() &#061;&#061; false)<br \/>\n        return false;<br \/>\n    if (Connect(ip, port) &#061;&#061; false)<br \/>\n        return false;<br \/>\n    return true;<br \/>\n} <\/p>\n<p>13.\u5f00\u542f\u5730\u5740\u7aef\u53e3\u91cd\u7528<\/p>\n<\/p>\n<p>\u8fd9\u91cc\u89e3\u91ca\u4e00\u4e0b\u4ec0\u4e48\u4e8b\u542f\u52a8\u5730\u5740\u91cd\u7528&#xff0c;\u5728\u4e00\u4e2aTCP\u8fde\u63a5\u5173\u95ed\u65f6&#xff0c;\u64cd\u4f5c\u7cfb\u7edf\u4f1a\u4fdd\u7559\u8be5\u94fe\u63a5\u7684\u7aef\u53e3\u4e00\u6bb5\u65f6\u95f4&#xff0c;\u8fd9\u4e2a\u72b6\u6001\u88ab\u79f0\u4e3aTIME_WAIT\u3002\u5728TIME_WAIT\u72b6\u6001\u4e0b&#xff0c;\u7aef\u53e3\u4e0d\u80fd\u88ab\u7acb\u5373\u91cd\u65b0\u4f7f\u7528&#xff0c;\u8fd9\u662f\u4e3a\u4e86\u786e\u4fdd\u6240\u6709\u76f8\u5173\u7684TCP\u62a5\u6587\u6bb5&#xff08;\u5982\u5ef6\u8fdf\u7684ACK\u6216FIN&#xff09;\u90fd\u5df2\u7ecf\u88ab\u5904\u7406\u5b8c\u6bd5&#xff0c;\u4ece\u800c\u907f\u514d\u65b0\u94fe\u63a5\u4e0e\u65e7\u94fe\u63a5\u7684\u6570\u636e\u6df7\u6dc6\u3002\u8bbe\u7f6e\u5730\u5740\u91cd\u7528&#xff0c;\u53ef\u4ee5\u5728\u77ed\u65f6\u95f4\u5185\u8fde\u7eed\u542f\u7528\u540c\u4e00\u4e2a\u7aef\u53e3\u53f7<\/p>\n<p> void ReuseAddress()<br \/>\n{<br \/>\n    int val &#061; 1;<br \/>\n    setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&amp;val, sizeof(int));<br \/>\n    val &#061; 1;<br \/>\n    setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void *)&amp;val, sizeof(int));<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662fsetsockopt\u51fd\u6570\u7684\u539f\u578b<\/p>\n<p>int setsockopt(int sockfd, int level, int option_name, const void*\u00a0option_value, socklen_t option_len)<\/p>\n<p>socket\u53c2\u6570\u6307\u5b9a\u88ab\u64cd\u4f5c\u7684\u76ee\u6807socket&#xff0c;level\u53c2\u6570\u6307\u5b9a\u8981\u64cd\u4f5c\u90a3\u4e2a\u534f\u8bae\u7684\u9009\u9879&#xff0c;\u6bd4\u5982IPV4&#xff0c;IPV6&#xff0c;TCP\u7b49\u3002option_name\u53c2\u6570\u6307\u5b9a\u9009\u9879\u7684\u540d\u5b57&#xff0c;option_value\u548coption_len\u53c2\u6570\u5206\u522b\u662f\u88ab\u64cd\u4f5c\u9009\u9879\u7684\u503c\u548c\u957f\u5ea6<\/p>\n<p>\u8fd9\u91cc\u6211\u4eec\u628aval\u8bbe\u7f6e\u4e3a1&#xff0c;val\u662f\u4e00\u4e2a\u6574\u6570&#xff0c;\u901a\u5e38\u8bbe\u7f6e\u4e3a1\u62160\u30021\u8868\u793a\u542f\u52a8\u6307\u5b9a\u7684\u5957\u63a5\u5b57\u9009\u9879&#xff0c;0\u8868\u793a\u7981\u7528\u6307\u5b9a\u7684\u5957\u63a5\u5b57\u9009\u9879<\/p>\n<p> 14.\u8bbe\u7f6e\u5957\u63a5\u5b57\u963b\u585e\u5c5e\u6027&#8212;\u8bbe\u7f6e\u4e3a\u975e\u963b\u585e&#xff0c;\u8fd9\u91cc\u6211\u4eec\u7528\u5230\u7684\u51fd\u6570\u662ffcntl\u51fd\u6570&#xff0c;\u4ee3\u7801\u540e\u9762\u5c06\u4f1a\u7ed9\u51fa\u8be6\u7ec6\u7684\u89e3\u91ca<\/p>\n<p> void NonBlock()<br \/>\n{<br \/>\n    int flag &#061; fcntl(_sockfd, F_GETFL, 0);<br \/>\n    fcntl(_sockfd, F_SETFL, flag | O_NONBLOCK);<br \/>\n} <\/p>\n<p>fcntl\u51fd\u6570&#xff0c;\u6b63\u5982\u5176\u540d\u5b57\u4e00\u6837&#xff0c;\u63d0\u4f9b\u4e86\u5bf9\u6587\u4ef6\u63cf\u8ff0\u7b26\u7684\u5404\u79cd\u63a7\u5236\u64cd\u4f5c&#xff0c;\u53e6\u5916\u8981\u4e00\u4e2a\u5e38\u89c1\u7684\u63a7\u5236\u6587\u4ef6\u63cf\u8ff0\u7b26\u7684\u5c5e\u6027\u548c\u884c\u4e3a\u7684\u7cfb\u7edf\u8c03\u7528\u65f6ioctl&#xff0c;\u4f46\u662ffcntl\u662f\u7531POSIX \u89c4\u5b9a\u7684\u9996\u9009\u65b9\u6cd5\u3002<\/p>\n<p>\u6211\u4eec\u5148\u5728flag\u4e2d\u83b7\u53d6fd\u7684\u6807\u5fd7&#xff0c;\u7136\u540e\u518d\u5c06\u8fd9\u4e2a\u51fd\u6570\u7684\u7b2c\u4e8c\u4e2a\u53c2\u6570\u8bbe\u7f6e\u4e3aF_SETFL\u8868\u793a\u8bbe\u7f6efd\u7684\u6807\u5fd7&#xff0c;\u7b2c\u4e09\u4e2a\u53c2\u6570\u5c31\u5199\u6210flag | O_NONBLOCK\u8868\u793a\u518d\u52a0\u4e0a\u975e\u963b\u585e\u5c5e\u6027<\/p>\n<p> \u6700\u540e\u662f\u5b8c\u6574\u7684socket\u4ee3\u7801<\/p>\n<p> #define MAX_LISTEN 1024<\/p>\n<p>class Socket<br \/>\n{<br \/>\nprivate:<br \/>\n    int _sockfd;<\/p>\n<p>public:<br \/>\n    Socket() : _sockfd(-1) {}<br \/>\n    Socket(int fd) : _sockfd(fd) {}<br \/>\n    ~Socket() { Close(); }<br \/>\n    int Fd() { return _sockfd; }<br \/>\n    \/\/ \u521b\u5efa\u5957\u63a5\u5b57<br \/>\n    bool Create()<br \/>\n    {<br \/>\n        _sockfd &#061; socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);<br \/>\n        if (_sockfd &lt; 0)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;CREATE SOCKET FAILED!!&#034;);<br \/>\n            return false;<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ \u7ed1\u5b9a\u5730\u5740\u4fe1\u606f<br \/>\n    bool Bind(const std::string &amp;ip, uint16_t port)<br \/>\n    {<br \/>\n        struct sockaddr_in addr;<br \/>\n        addr.sin_family &#061; AF_INET;<br \/>\n        addr.sin_port &#061; htons(port);<br \/>\n        addr.sin_addr.s_addr &#061; inet_addr(ip.c_str());<br \/>\n        socklen_t len &#061; sizeof(struct sockaddr_in);<br \/>\n        int ret &#061; bind(_sockfd, (struct sockaddr *)&amp;addr, len);<br \/>\n        if (ret &lt; 0)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;BIND ADDRESS FAILED!&#034;);<br \/>\n            return false;<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ \u5f00\u59cb\u76d1\u542c<br \/>\n    bool Listen(int backlog &#061; MAX_LISTEN)<br \/>\n    {<br \/>\n        int ret &#061; listen(_sockfd, backlog);<br \/>\n        if (ret &lt; 0)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;SOCKET LISTEN FAILED!&#034;);<br \/>\n            return false;<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ \u5411\u670d\u52a1\u5668\u53d1\u8d77\u8fde\u63a5<br \/>\n    bool Connect(const std::string &amp;ip, uint16_t port)<br \/>\n    {<br \/>\n        struct sockaddr_in addr;<br \/>\n        addr.sin_family &#061; AF_INET;<br \/>\n        addr.sin_port &#061; htons(port);<br \/>\n        addr.sin_addr.s_addr &#061; inet_addr(ip.c_str());<br \/>\n        socklen_t len &#061; sizeof(struct sockaddr_in);<br \/>\n        int ret &#061; connect(_sockfd, (struct sockaddr *)&amp;addr, len);<br \/>\n        if (ret &lt; 0)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;CONNECT ADDRESS FAILED!&#034;);<br \/>\n            return false;<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ \u83b7\u53d6\u65b0\u94fe\u63a5<br \/>\n    int Accept()<br \/>\n    {<br \/>\n        int newfd &#061; accept(_sockfd, NULL, NULL);<br \/>\n        if (newfd &lt; 0)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;SOCKET ACCEPT FAILED!&#034;);<br \/>\n            return -1;<br \/>\n        }<br \/>\n        return newfd;<br \/>\n    }<br \/>\n    \/\/ \u63a5\u6536\u6570\u636e<br \/>\n    ssize_t Recv(void *buf, size_t len, int flag &#061; 0) \/\/ flag\u4ee3\u8868\u8bbe\u7f6e\u4e00\u4e9b\u963b\u585e\u76f8\u5173\u7684\u64cd\u4f5c<br \/>\n    {<br \/>\n        ssize_t ret &#061; recv(_sockfd, buf, len, flag);<br \/>\n        if (ret &lt;&#061; 0)<br \/>\n        {<br \/>\n            if (errno &#061;&#061; EAGAIN || errno &#061;&#061; EINTR)<br \/>\n            {<br \/>\n                return 0;<br \/>\n            }<br \/>\n            ERR_LOG(&#034;SOCKET RECV FAILED!&#034;);<br \/>\n            return -1;<br \/>\n        }<br \/>\n        return ret;<br \/>\n    }<br \/>\n    ssize_t NonBlockRecv(void *buf, size_t len)<br \/>\n    {<br \/>\n        if (len &#061;&#061; 0)<br \/>\n            return 0;<br \/>\n        return Recv(buf, len, MSG_DONTWAIT);<br \/>\n    }<br \/>\n    \/\/ \u53d1\u9001\u6570\u636e<br \/>\n    ssize_t Send(const void *buf, size_t len, int flag &#061; 0)<br \/>\n    {<br \/>\n        \/\/ ssize_t send(int sockfd, void* data, size_t len, int flag);<br \/>\n        ssize_t ret &#061; send(_sockfd, buf, len, flag);<br \/>\n        if (ret &lt; 0)<br \/>\n        {<br \/>\n            if (errno &#061;&#061; EAGAIN || errno &#061;&#061; EINTR)<br \/>\n            {<br \/>\n                return 0;<br \/>\n            }<br \/>\n            ERR_LOG(&#034;SOCKET SEND FAILED!&#034;);<br \/>\n            return -1;<br \/>\n        }<br \/>\n        return ret;<br \/>\n    }<br \/>\n    ssize_t NonBlockSend(void *buf, size_t len)<br \/>\n    {<br \/>\n        if (len &#061;&#061; 0)<br \/>\n            return 0;<br \/>\n        return Send(buf, len, MSG_DONTWAIT);<br \/>\n    }<\/p>\n<p>    \/\/ \u5173\u95ed\u5957\u63a5\u5b57<br \/>\n    void Close()<br \/>\n    {<br \/>\n        if (_sockfd !&#061; -1)<br \/>\n        {<br \/>\n            close(_sockfd);<br \/>\n            _sockfd &#061; -1;<br \/>\n        }<br \/>\n    }<br \/>\n    \/\/ \u521b\u5efa\u4e00\u4e2a\u670d\u52a1\u7aef\u8fde\u63a5<br \/>\n    bool CreateServer(uint16_t port, const std::string &amp;ip &#061; &#034;0.0.0.0&#034;, bool block_flag &#061; false)<br \/>\n    {<br \/>\n        \/\/ \u521b\u5efa\u5957\u63a5\u5b57<br \/>\n        if (Create() &#061;&#061; false)<br \/>\n            return false;<br \/>\n        \/\/ \u8bbe\u7f6e\u975e\u963b\u585e<br \/>\n        if (block_flag)<br \/>\n            NonBlock();<br \/>\n        \/\/ \u7ed1\u5b9a\u5730\u5740<br \/>\n        if (Bind(ip, port) &#061;&#061; false)<br \/>\n            return false;<br \/>\n        \/\/ \u5f00\u59cb\u76d1\u542c<br \/>\n        if (Listen() &#061;&#061; false)<br \/>\n            return false;<br \/>\n        \/\/ \u542f\u52a8\u5730\u5740\u91cd\u7528<br \/>\n        ReuseAddress();<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ \u521b\u5efa\u4e00\u4e2a\u5ba2\u6237\u7aef\u8fde\u63a5<br \/>\n    bool CreateClient(uint16_t port, const std::string &amp;ip)<br \/>\n    {<br \/>\n        \/\/ 1.\u521b\u5efa\u5957\u63a5\u5b57&#xff0c; 2.\u6307\u5411\u8fde\u63a5\u670d\u52a1\u5668<br \/>\n        if (Create() &#061;&#061; false)<br \/>\n            return false;<br \/>\n        if (Connect(ip, port) &#061;&#061; false)<br \/>\n            return false;<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ \u8bbe\u7f6e\u5957\u63a5\u5b57\u9009\u9879&#8211;\u5f00\u542f\u5730\u5740\u7aef\u53e3\u91cd\u7528<br \/>\n    void ReuseAddress()<br \/>\n    {<br \/>\n        int val &#061; 1;<br \/>\n        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&amp;val, sizeof(int));<br \/>\n        val &#061; 1;<br \/>\n        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void *)&amp;val, sizeof(int));<br \/>\n    }<br \/>\n    \/\/ \u8bbe\u7f6e\u5957\u63a5\u5b57\u963b\u585e\u5c5e\u6027&#8211;\u8bbe\u7f6e\u4e3a\u975e\u963b\u585e<br \/>\n    void NonBlock()<br \/>\n    {<br \/>\n        int flag &#061; fcntl(_sockfd, F_GETFL, 0);<br \/>\n        fcntl(_sockfd, F_SETFL, flag | O_NONBLOCK);<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"2.4%C2%A0%E4%BA%8B%E4%BB%B6%E7%AE%A1%E7%90%86Channel%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0\">2.4\u00a0\u4e8b\u4ef6\u7ba1\u7406Channel\u7c7b\u7684\u5b9e\u73b0<\/h3>\n<p>Channel\u6a21\u5757\u662f\u5bf9\u4e00\u4e2a\u63cf\u8ff0\u7b26\u9700\u8981\u8fdb\u884cIO\u4e8b\u4ef6\u7ba1\u7406\u7684\u6a21\u5757&#xff0c;\u5b9e\u73b0\u5bf9\u63cf\u8ff0\u7b26\u53ef\u8bfb&#xff0c;\u53ef\u5199&#xff0c;\u9519\u8bef\u4e8b\u4ef6\u7684\u7ba1\u7406\u64cd\u4f5c&#xff0c;\u4ee5\u53caPoller\u6a21\u5757\u5bf9\u63cf\u8ff0\u7b26\u8fdb\u884cIO\u4e8b\u4ef6\u76d1\u63a7\u5c31\u7eea\u540e&#xff0c;\u6839\u636e\u4e0d\u540c\u7684\u4e8b\u4ef6&#xff0c;\u56de\u8c03\u4e0d\u540c\u7684\u5904\u7406\u51fd\u6570\u529f\u80fd\u3002<\/p>\n<p>\u5728Channel\u7c7b\u7684\u79c1\u6709\u6210\u5458\u4e2d&#xff0c;\u4e3b\u8981\u5305\u542b\u6587\u4ef6\u63cf\u8ff0\u7b26_fd&#xff0c;\u5f53\u524d\u9700\u8981\u76d1\u63a7\u7684\u4e8b\u4ef6_events\u548c\u5f53\u524d\u89e6\u53d1\u7684\u4e8b\u4ef6_revents\u8fd8\u6709\u5404\u79cd\u4e8b\u4ef6\u88ab\u89e6\u53d1\u65f6\u7684\u56de\u8c03\u51fd\u6570<\/p>\n<p> int _fd;<br \/>\nEventLoop *_loop;<br \/>\nuint32_t _events;  \/\/ \u5f53\u524d\u9700\u8981\u76d1\u63a7\u7684\u4e8b\u4ef6<br \/>\nuint32_t _revents; \/\/ \u5f53\u524d\u89e6\u53d1\u7684\u4e8b\u4ef6<br \/>\nusing EventCallback &#061; std::function&lt;void()&gt;;<br \/>\nEventCallback _read_callback;  \/\/ \u53ef\u8bfb\u4e8b\u4ef6\u88ab\u89e6\u53d1\u7684\u56de\u8c03\u51fd\u6570<br \/>\nEventCallback _write_callback; \/\/ \u53ef\u5199\u4e8b\u4ef6\u88ab\u89e6\u53d1\u7684\u56de\u8c03\u51fd\u6570<br \/>\nEventCallback _error_callback; \/\/ \u9519\u8bef\u4e8b\u4ef6\u88ab\u89e6\u53d1\u7684\u56de\u8c03\u51fd\u6570<br \/>\nEventCallback _close_callback; \/\/ \u8fde\u63a5\u65ad\u5f00\u4e8b\u4ef6\u88ab\u89e6\u53d1\u7684\u56de\u8c03\u51fd\u6570<br \/>\nEventCallback _event_callback; \/\/ \u4efb\u610f\u4e8b\u4ef6\u88ab\u89e6\u53d1\u7684\u56de\u8c03\u51fd\u6570 <\/p>\n<p>\u00a0\u63a5\u4e0b\u6765\u662fChannel\u7c7b\u4e2d\u6240\u5305\u542b\u7684\u6210\u5458\u51fd\u6570<\/p>\n<p>\u9996\u5148\u662f\u8bbe\u7f6e\u5404\u79cd\u4e8b\u4ef6\u7684\u56de\u8c03\u51fd\u6570<\/p>\n<p> void SetReadCallback(const EventCallback &amp;cb)<br \/>\n{<br \/>\n    _read_callback &#061; cb;<br \/>\n}<br \/>\nvoid SetWriteCallback(const EventCallback &amp;cb)<br \/>\n{<br \/>\n    _write_callback &#061; cb;<br \/>\n}<br \/>\nvoid SetErrorCallback(const EventCallback &amp;cb)<br \/>\n{<br \/>\n    _error_callback &#061; cb;<br \/>\n}<br \/>\nvoid SetCloseCallback(const EventCallback &amp;cb)<br \/>\n{<br \/>\n    _close_callback &#061; cb;<br \/>\n}<br \/>\nvoid SetEventCallback(const EventCallback &amp;cb)<br \/>\n{<br \/>\n    _event_callback &#061; cb;<br \/>\n} <\/p>\n<p>\u63a5\u4e0b\u6765\u7684\u4e24\u4e2a\u51fd\u6570\u7528\u6765\u68c0\u6d4b\u5f53\u524d\u662f\u5426\u53ef\u8bfb\u548c\u53ef\u5199<\/p>\n<p> bool ReadAble() \/\/ \u5f53\u524d\u662f\u5426\u53ef\u8bfb<br \/>\n{<br \/>\n    return (_events &amp; EPOLLIN);<br \/>\n}<br \/>\nbool WriteAble() \/\/ \u5f53\u524d\u662f\u5426\u53ef\u5199<br \/>\n{<br \/>\n    return (_events &amp; EPOLLOUT);<br \/>\n} <\/p>\n<p>\u8fd9\u56db\u4e2a\u51fd\u6570\u7528\u6765\u542f\u52a8\u4e8b\u4ef6\u76d1\u63a7\u548c\u5173\u95ed\u4e8b\u4ef6\u76d1\u63a7<\/p>\n<p> void EnableRead() \/\/ \u542f\u52a8\u8bfb\u4e8b\u4ef6\u76d1\u63a7<br \/>\n{<br \/>\n    _events |&#061; EPOLLIN; \/*\u540e\u8fb9\u4f1a\u6dfb\u52a0\u5230EventLoop\u7684\u4e8b\u4ef6\u76d1\u63a7\u4e2d*\/<br \/>\n    Update();<br \/>\n}<br \/>\nvoid EnableWrite() \/\/ \u542f\u52a8\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n{<br \/>\n    _events |&#061; EPOLLOUT;<br \/>\n    Update();<br \/>\n}<br \/>\nvoid DisableRead() \/\/ \u5173\u95ed\u8bfb\u4e8b\u4ef6\u76d1\u63a7<br \/>\n{<br \/>\n    _events &amp;&#061; ~EPOLLIN;<br \/>\n    Update();<br \/>\n}<br \/>\nvoid DisableWrite() \/\/ \u5173\u95ed\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n{<br \/>\n    _events &amp;&#061; ~EPOLLOUT;<br \/>\n    Update();<br \/>\n}<br \/>\nvoid DisableAll() \/\/ \u5173\u95ed\u6240\u6709\u4e8b\u4ef6\u76d1\u63a7<br \/>\n{<br \/>\n    _events &#061; 0;<br \/>\n    Update();<br \/>\n} <\/p>\n<p>\u8fd8\u9700\u8981\u5bf9\u76d1\u63a7\u8fdb\u884c\u79fb\u9664\u548c\u66f4\u65b0\u7684\u51fd\u6570&#xff0c;\u8fd9\u4e24\u4e2a\u51fd\u6570\u9700\u8981\u5728\u7c7b\u5916\u5b9e\u73b0&#xff0c;\u56e0\u4e3aEventLoop\u7c7b\u5728Channel::Remove()\u548cChannel::Update()\u4e2d\u88ab\u4f7f\u7528\u65f6&#xff0c;\u7f16\u8bd1\u5668\u9700\u8981\u770b\u5230\u4ed6\u7684\u5b8c\u6574\u5b9a\u4e49<\/p>\n<p> void Channel::Remove() \/\/ \u79fb\u9664\u76d1\u63a7<br \/>\n{<br \/>\n    return _loop-&gt;RemoveEvent(this);<br \/>\n}<br \/>\nvoid Channel::Update()<br \/>\n{<br \/>\n    return _loop-&gt;UpdateEvent(this);<br \/>\n} <\/p>\n<p>\u63a5\u4e0b\u6765\u662f\u4e8b\u4ef6\u5904\u7406\u51fd\u6570&#xff0c;\u5c31\u8c03\u7528\u8fd9\u4e2a\u51fd\u6570&#xff0c;\u81ea\u5df1\u89e6\u53d1\u4e86\u4ec0\u4e48\u4e8b\u4ef6\u5982\u4f55\u81ea\u5df1\u51b3\u5b9a\u3002\u8fd9\u91cc\u89e3\u91ca\u4e00\u4e9b\u5e38\u7528\u7684epoll\u4e8b\u4ef6\u7c7b\u578b\u3002<\/p>\n<ul>\n<li>EPOLLIN&#xff1a;\u6570\u636e\u53ef\u8bfb<\/li>\n<li>EPOLLRDHUP&#xff1a;TCP\u8fde\u63a5\u88ab\u5bf9\u65b9\u5173\u95ed&#xff0c;\u6216\u8005\u5bf9\u65b9\u5173\u95ed\u4e86\u5199\u64cd\u4f5c&#xff0c;\u5b83\u7531GNU\u5f15\u5165<\/li>\n<li>EPOLLPRI&#xff1a;\u9ad8\u4f18\u5148\u7ea7\u6570\u636e\u53ef\u8bfb&#xff0c;\u6bd4\u5982TCP\u5e26\u5916\u6570\u636e<\/li>\n<li>EPOLLOUT&#xff1a;\u6570\u636e\u53ef\u5199<\/li>\n<li>EPOLLERR&#xff1a;\u9519\u8bef<\/li>\n<li>EPOLLHUP&#xff1a;\u6302\u8d77&#xff0c;\u6bd4\u5982\u7ba1\u9053\u7684\u5199\u7aef\u88ab\u5173\u95ed\u540e&#xff0c;\u8bfb\u7aef\u63cf\u8ff0\u7b26\u4e0a\u5c06\u88ab\u6536\u5230EPOLLHUP\u4e8b\u4ef6\u3002<\/li>\n<\/ul>\n<p> void HandleEvent() \/\/ \u4e8b\u4ef6\u5904\u7406&#xff0c;\u4e00\u65e6\u8fde\u63a5\u89e6\u53d1\u4e86\u4e8b\u4ef6&#xff0c;\u5c31\u8c03\u7528\u8fd9\u4e2a\u51fd\u6570&#xff0c;\u81ea\u5df1\u89e6\u53d1\u4e86\u4ec0\u4e48\u4e8b\u4ef6\u5982\u4f55\u81ea\u5df1\u51b3\u5b9a<br \/>\n{<br \/>\n    if ((_revents &amp; EPOLLIN) || (_revents &amp; EPOLLRDHUP) || (_revents &amp; EPOLLPRI))<br \/>\n    {<br \/>\n        \/*\u4e0d\u7ba1\u4efb\u4f55\u4e8b\u4ef6&#xff0c;\u90fd\u8c03\u7528\u7684\u56de\u8c03\u51fd\u6570*\/<br \/>\n        if (_read_callback)<br \/>\n            _read_callback();<br \/>\n    }<br \/>\n    \/*\u6709\u53ef\u80fd\u4f1a\u91ca\u653e\u8fde\u63a5\u7684\u64cd\u4f5c\u4e8b\u4ef6&#xff0c;\u4e00\u6b21\u53ea\u5904\u7406\u4e00\u4e2a*\/<br \/>\n    if (_revents &amp; EPOLLOUT)<br \/>\n    {<br \/>\n        \/*\u4e0d\u7ba1\u4efb\u4f55\u4e8b\u4ef6&#xff0c;\u90fd\u8c03\u7528\u7684\u56de\u8c03\u51fd\u6570*\/<\/p>\n<p>        if (_write_callback)<br \/>\n            _write_callback();<br \/>\n    }<br \/>\n    else if (_revents &amp; EPOLLERR)<br \/>\n    {<\/p>\n<p>        if (_error_callback)<br \/>\n            _error_callback();<br \/>\n    }<br \/>\n    else if (_revents &amp; EPOLLHUP)<br \/>\n    {<\/p>\n<p>        if (_close_callback)<br \/>\n            _close_callback();<br \/>\n    }<br \/>\n    if (_event_callback)<br \/>\n        _event_callback();<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662f\u6574\u4e2aChannel\u7c7b\u7684\u5b9e\u73b0<\/p>\n<p> class Channel<br \/>\n{<br \/>\nprivate:<br \/>\n    int _fd;<br \/>\n    EventLoop *_loop;<br \/>\n    uint32_t _events;  \/\/ \u5f53\u524d\u9700\u8981\u76d1\u63a7\u7684\u4e8b\u4ef6<br \/>\n    uint32_t _revents; \/\/ \u5f53\u524d\u89e6\u53d1\u7684\u4e8b\u4ef6<br \/>\n    using EventCallback &#061; std::function&lt;void()&gt;;<br \/>\n    EventCallback _read_callback;  \/\/ \u53ef\u8bfb\u4e8b\u4ef6\u88ab\u89e6\u53d1\u7684\u56de\u8c03\u51fd\u6570<br \/>\n    EventCallback _write_callback; \/\/ \u53ef\u5199\u4e8b\u4ef6\u88ab\u89e6\u53d1\u7684\u56de\u8c03\u51fd\u6570<br \/>\n    EventCallback _error_callback; \/\/ \u9519\u8bef\u4e8b\u4ef6\u88ab\u89e6\u53d1\u7684\u56de\u8c03\u51fd\u6570<br \/>\n    EventCallback _close_callback; \/\/ \u8fde\u63a5\u65ad\u5f00\u4e8b\u4ef6\u88ab\u89e6\u53d1\u7684\u56de\u8c03\u51fd\u6570<br \/>\n    EventCallback _event_callback; \/\/ \u4efb\u610f\u4e8b\u4ef6\u88ab\u89e6\u53d1\u7684\u56de\u8c03\u51fd\u6570<br \/>\npublic:<br \/>\n    Channel(EventLoop *loop, int fd) : _fd(fd), _events(0), _revents(0), _loop(loop) {}<br \/>\n    int Fd() { return _fd; }<br \/>\n    void SetREvents(uint32_t events) { _revents &#061; events; }<br \/>\n    uint32_t Events() { return _events; }<br \/>\n    void SetReadCallback(const EventCallback &amp;cb)<br \/>\n    {<br \/>\n        _read_callback &#061; cb;<br \/>\n    }<br \/>\n    void SetWriteCallback(const EventCallback &amp;cb)<br \/>\n    {<br \/>\n        _write_callback &#061; cb;<br \/>\n    }<br \/>\n    void SetErrorCallback(const EventCallback &amp;cb)<br \/>\n    {<br \/>\n        _error_callback &#061; cb;<br \/>\n    }<br \/>\n    void SetCloseCallback(const EventCallback &amp;cb)<br \/>\n    {<br \/>\n        _close_callback &#061; cb;<br \/>\n    }<br \/>\n    void SetEventCallback(const EventCallback &amp;cb)<br \/>\n    {<br \/>\n        _event_callback &#061; cb;<br \/>\n    }<br \/>\n    bool ReadAble() \/\/ \u5f53\u524d\u662f\u5426\u53ef\u8bfb<br \/>\n    {<br \/>\n        return (_events &amp; EPOLLIN);<br \/>\n    }<br \/>\n    bool WriteAble() \/\/ \u5f53\u524d\u662f\u5426\u53ef\u5199<br \/>\n    {<br \/>\n        return (_events &amp; EPOLLOUT);<br \/>\n    }<br \/>\n    void EnableRead() \/\/ \u542f\u52a8\u8bfb\u4e8b\u4ef6\u76d1\u63a7<br \/>\n    {<br \/>\n        _events |&#061; EPOLLIN; \/*\u540e\u8fb9\u4f1a\u6dfb\u52a0\u5230EventLoop\u7684\u4e8b\u4ef6\u76d1\u63a7\u4e2d*\/<br \/>\n        Update();<br \/>\n    }<br \/>\n    void EnableWrite() \/\/ \u542f\u52a8\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n    {<br \/>\n        _events |&#061; EPOLLOUT;<br \/>\n        Update();<br \/>\n    }<br \/>\n    void DisableRead() \/\/ \u5173\u95ed\u8bfb\u4e8b\u4ef6\u76d1\u63a7<br \/>\n    {<br \/>\n        _events &amp;&#061; ~EPOLLIN;<br \/>\n        Update();<br \/>\n    }<br \/>\n    void DisableWrite() \/\/ \u5173\u95ed\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n    {<br \/>\n        _events &amp;&#061; ~EPOLLOUT;<br \/>\n        Update();<br \/>\n    }<br \/>\n    void DisableAll() \/\/ \u5173\u95ed\u6240\u6709\u4e8b\u4ef6\u76d1\u63a7<br \/>\n    {<br \/>\n        _events &#061; 0;<br \/>\n        Update();<br \/>\n    }<br \/>\n    void Remove(); \/\/ \u79fb\u9664\u76d1\u63a7<br \/>\n    void Update();<br \/>\n    void HandleEvent() \/\/ \u4e8b\u4ef6\u5904\u7406&#xff0c;\u4e00\u65e6\u8fde\u63a5\u89e6\u53d1\u4e86\u4e8b\u4ef6&#xff0c;\u5c31\u8c03\u7528\u8fd9\u4e2a\u51fd\u6570&#xff0c;\u81ea\u5df1\u89e6\u53d1\u4e86\u4ec0\u4e48\u4e8b\u4ef6\u5982\u4f55\u81ea\u5df1\u51b3\u5b9a<br \/>\n    {<br \/>\n        if ((_revents &amp; EPOLLIN) || (_revents &amp; EPOLLRDHUP) || (_revents &amp; EPOLLPRI))<br \/>\n        {<br \/>\n            \/*\u4e0d\u7ba1\u4efb\u4f55\u4e8b\u4ef6&#xff0c;\u90fd\u8c03\u7528\u7684\u56de\u8c03\u51fd\u6570*\/<br \/>\n            if (_read_callback)<br \/>\n                _read_callback();<br \/>\n        }<br \/>\n        \/*\u6709\u53ef\u80fd\u4f1a\u91ca\u653e\u8fde\u63a5\u7684\u64cd\u4f5c\u4e8b\u4ef6&#xff0c;\u4e00\u6b21\u53ea\u5904\u7406\u4e00\u4e2a*\/<br \/>\n        if (_revents &amp; EPOLLOUT)<br \/>\n        {<br \/>\n            \/*\u4e0d\u7ba1\u4efb\u4f55\u4e8b\u4ef6&#xff0c;\u90fd\u8c03\u7528\u7684\u56de\u8c03\u51fd\u6570*\/<\/p>\n<p>            if (_write_callback)<br \/>\n                _write_callback();<br \/>\n        }<br \/>\n        else if (_revents &amp; EPOLLERR)<br \/>\n        {<\/p>\n<p>            if (_error_callback)<br \/>\n                _error_callback();<br \/>\n        }<br \/>\n        else if (_revents &amp; EPOLLHUP)<br \/>\n        {<\/p>\n<p>            if (_close_callback)<br \/>\n                _close_callback();<br \/>\n        }<br \/>\n        if (_event_callback)<br \/>\n            _event_callback();<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"2.5%C2%A0%E6%8F%8F%E8%BF%B0%E7%AC%A6%E4%BA%8B%E4%BB%B6%E7%9B%91%E6%8E%A7Poller%E7%B1%BB%E5%AE%9E%E7%8E%B0\">2.5\u00a0\u63cf\u8ff0\u7b26\u4e8b\u4ef6\u76d1\u63a7Poller\u7c7b\u5b9e\u73b0<\/h3>\n<p>Poller\u6a21\u5757\u662f\u5bf9epoll\u8fdb\u884c\u5c01\u88c5\u7684\u4e00\u4e2a\u6a21\u5757&#xff0c;\u4e3b\u8981\u5b9e\u73b0epoll\u7684IO\u4e8b\u4ef6\u6dfb\u52a0&#xff0c;\u4fee\u6539&#xff0c;\u79fb\u9664&#xff0c;\u83b7\u53d6\u6d3b\u8dc3\u8fde\u63a5\u529f\u80fd<\/p>\n<p>\u9996\u5148\u6765\u8bf4\u660e\u4e00\u4e0b\u8fd9\u4e2a\u7c7b\u7684\u79c1\u6709\u6210\u5458\u53d8\u91cf&#xff0c;\u9996\u5148\u662fepoll\u6587\u4ef6\u63cf\u8ff0\u7b26_epfd&#xff0c;\u7136\u540e\u662f_evt&#xff0c;\u8fd9\u662f\u7528\u6765\u63cf\u8ff0\u9700\u8981\u76d1\u63a7\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26&#xff0c;\u6700\u540e\u662f_channels&#xff0c;\u8fd9\u662f\u7528\u6765\u901a\u8fc7\u6587\u4ef6\u63cf\u8ff0\u7b26\u627e\u5230\u5176\u5bf9\u5e94\u7684Channel\u6a21\u5757\u3002<\/p>\n<p> int _epfd;<br \/>\nstruct epoll_event _evs[MAX_EPOLLEVENTS];<br \/>\nstd::unordered_map&lt;int, Channel *&gt; _channels;<\/p>\n<p>\u63a5\u4e0b\u6765\u6ce8\u610f\u4ecb\u7ecd\u5176\u4e2d\u7684\u6210\u5458\u51fd\u6570<\/p>\n<p>\u9996\u5148\u662f\u5bf9epoll\u7684\u76f4\u63a5\u64cd\u4f5c\u51fd\u6570Update&#xff0c;Update\u4e2d\u4f20\u5165\u4e24\u4e2a\u53c2\u6570&#xff0c;\u5206\u522b\u662fchannel\u6307\u9488\u548c\u9700\u8981\u6267\u884c\u7684\u64cd\u4f5cop&#xff0c;\u9996\u5148\u6211\u4eec\u9700\u8981\u901a\u8fc7channel\u6307\u9488\u83b7\u5f97fd&#xff0c;\u7136\u540e\u521b\u5efa\u4e00\u4e2aepoll_event\u7c7b\u578b\u7684\u7ed3\u6784\u4f53\u5e76\u5bf9\u5176\u8fdb\u884c\u521d\u59cb\u5316&#xff0c;\u8fd9\u91cc\u4ecb\u7ecd\u4e00\u4e0bepoll_event<\/p>\n<p> struct epoll_event {<br \/>\n    uint32_t events;  \/\/ \u4e8b\u4ef6\u7c7b\u578b&#xff08;\u4f4d\u63a9\u7801&#xff09;<br \/>\n    epoll_data_t data; \/\/ \u7528\u6237\u6570\u636e&#xff08;\u8054\u5408\u4f53&#xff09;<br \/>\n};<\/p>\n<p>typedef union epoll_data {<br \/>\n    void *ptr;      \/\/ \u7528\u6237\u81ea\u5b9a\u4e49\u6570\u636e\u6307\u9488<br \/>\n    int fd;         \/\/ \u6587\u4ef6\u63cf\u8ff0\u7b26<br \/>\n    uint32_t u32;   \/\/ 32\u4f4d\u65e0\u7b26\u53f7\u6574\u6570<br \/>\n    uint64_t u64;   \/\/ 64\u4f4d\u65e0\u7b26\u53f7\u6574\u6570<br \/>\n} epoll_data_t; <\/p>\n<p>\u5728epoll_data\u8fd9\u4e2a\u8054\u5408\u4f53\u5f53\u4e2d&#xff0c;\u6700\u5e38\u7528\u7684\u6570\u636e\u662ffd<\/p>\n<p>\u7136\u540e\u4f7f\u7528epoll_ctl\u5bf9epoll\u5b9e\u4f8b\u6dfb\u52a0\u3001\u4fee\u6539\u6216\u5220\u9664\u76d1\u63a7\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26\u53ca\u5176\u5173\u6ce8\u7684\u4e8b\u4ef6<\/p>\n<p> int epoll_ctl(int __epfd, int __op, int __fd, epoll_event *) throw() <\/p>\n<p>\u53c2\u6570\u89e3\u91ca&#xff1a;<\/p>\n<ul>\n<li>__epfd&#xff1a;\u7531epoll_create\u6216epoll_create1\u521b\u5efa\u7684epoll\u5b9e\u4f8b\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26<\/li>\n<li>__op&#xff1a;\u4e00\u822c\u4f7f\u7528\u4ee5\u4e0b\u4e09\u79cd\u64cd\u4f5c\u7c7b\u578b&#xff1a;EPOLL_CTL_ADD\u3001EPOLL_CTL_MOD\u3001EPOLL_CTL_DEL<\/li>\n<li>__fd&#xff1a;\u9700\u8981\u88ab\u76d1\u63a7\u6216\u64cd\u4f5c\u7684\u666e\u901a\u6587\u4ef6\u63cf\u8ff0\u7b26<\/li>\n<li>epoll_event\u7c7b\u578b\u53c2\u6570&#xff1a;\u5b9a\u4e49\u9700\u8981\u76d1\u63a7\u7684\u4e8b\u4ef6\u7c7b\u578b\u548c\u5173\u8054\u7684\u7528\u6237\u6570\u636e<\/li>\n<\/ul>\n<p>Update\u7684\u5b8c\u6574\u5b9e\u73b0&#xff1a;<\/p>\n<p> void Update(Channel *channel, int op)<br \/>\n{<br \/>\n    \/\/ int epoll_ctl(int epfd, int op, int fd, struct epoll_event* ev);<br \/>\n    int fd &#061; channel-&gt;Fd();<br \/>\n    struct epoll_event ev;<br \/>\n    ev.data.fd &#061; fd;<br \/>\n    ev.events &#061; channel-&gt;Events();<br \/>\n    int ret &#061; epoll_ctl(_epfd, op, fd, &amp;ev);<br \/>\n    if (ret &lt; 0)<br \/>\n    {<br \/>\n        ERR_LOG(&#034;EPOLLCTL FAILED!&#034;);<br \/>\n        \/\/ abort(); \/\/\u9000\u51fa\u7a0b\u5e8f<br \/>\n    }<br \/>\n    return;<br \/>\n} <\/p>\n<p>\u7136\u540e\u5c31\u662f\u5224\u65ad\u4e00\u4e2aChannel\u662f\u5426\u5df2\u7ecf\u6dfb\u52a0\u4e86\u4e8b\u4ef6\u76d1\u63a7<\/p>\n<p> bool HasChannel(Channel *channel)<br \/>\n{<br \/>\n    auto it &#061; _channels.find(channel-&gt;Fd());<br \/>\n    if (it &#061;&#061; _channels.end())<br \/>\n    {<br \/>\n        return false;<br \/>\n    }<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u6dfb\u52a0\u6216\u4fee\u6539\u76d1\u63a7\u4e8b\u4ef6&#xff0c;\u5982\u679cChannel\u80fd\u627e\u5230&#xff0c;\u90a3\u4e48\u5c31\u4fee\u6539\u5426\u5219\u5c31\u6dfb\u52a0<\/p>\n<p> void UpdateEvent(Channel *channel)<br \/>\n{<br \/>\n    bool ret &#061; HasChannel(channel);<br \/>\n    if (ret &#061;&#061; false)<br \/>\n    {<br \/>\n        \/\/ \u4e0d\u5b58\u5728\u5219\u6dfb\u52a0<br \/>\n        _channels.insert(std::make_pair(channel-&gt;Fd(), channel));<br \/>\n        return Update(channel, EPOLL_CTL_ADD);<br \/>\n    }<br \/>\n    return Update(channel, EPOLL_CTL_MOD);<br \/>\n} <\/p>\n<p>\u79fb\u9664\u76d1\u63a7<\/p>\n<p> void RemoveEvent(Channel *channel)<br \/>\n{<br \/>\n    auto it &#061; _channels.find(channel-&gt;Fd());<br \/>\n    {<br \/>\n        if (it !&#061; _channels.end())<br \/>\n        {<br \/>\n            _channels.erase(it);<br \/>\n        }<br \/>\n        Update(channel, EPOLL_CTL_DEL);<br \/>\n    }<br \/>\n} <\/p>\n<p>\u5f00\u59cb\u76d1\u63a7&#xff0c;\u5e76\u4e14\u8fd4\u56de\u6d3b\u8dc3\u8fde\u63a5<\/p>\n<p>\u4ecb\u7ecd\u4e00\u4e0bepoll_wait&#xff0c;\u7528\u4e8e\u7b49\u5f85epoll\u5b9e\u4f8b\u76d1\u63a7\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26\u4e0a\u53d1\u751f\u7684\u4e8b\u4ef6&#xff0c;\u8fd4\u56de\u503c\u662f\u5c31\u7eea\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26\u7684\u6570\u91cf\u3002\u5e76\u4e14\u8fd9\u4e2a\u51fd\u6570\u4f1a\u628a\u5c31\u7eea\u4e8b\u4ef6\u586b\u5145\u5230\u7b2c\u4e8c\u4e2a\u53c2\u6570\u6307\u5411\u7684\u6570\u7ec4\u4e2d<\/p>\n<p> void Poll(std::vector&lt;Channel *&gt; *active)<br \/>\n{<br \/>\n    int nfds &#061; epoll_wait(_epfd, _evs, MAX_EPOLLEVENTS, -1); \/\/-1\u4ee3\u8868\u963b\u585e\u76d1\u63a7<br \/>\n    if (nfds &lt; 0)<br \/>\n    {<br \/>\n        if (errno &#061;&#061; EINTR)<br \/>\n        {<br \/>\n            return;<br \/>\n        }<br \/>\n        ERR_LOG(&#034;EPOLL WAIT ERROR:%s\\\\n&#034;, strerror(errno));<br \/>\n        abort();<br \/>\n    }<br \/>\n    for (int i &#061; 0; i &lt; nfds; i&#043;&#043;)<br \/>\n    {<br \/>\n        auto it &#061; _channels.find(_evs[i].data.fd);<br \/>\n        assert(it !&#061; _channels.end());<br \/>\n        it-&gt;second-&gt;SetREvents(_evs[i].events);<br \/>\n        active-&gt;push_back(it-&gt;second);<br \/>\n    }<br \/>\n    return;<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662f\u5b8c\u6574\u4ee3\u7801<\/p>\n<p> #define MAX_EPOLLEVENTS 1024<br \/>\nclass Poller<br \/>\n{<br \/>\nprivate:<br \/>\n    int _epfd;<br \/>\n    struct epoll_event _evs[MAX_EPOLLEVENTS];<br \/>\n    std::unordered_map&lt;int, Channel *&gt; _channels;<\/p>\n<p>private:<br \/>\n    \/\/ \u5bf9epoll\u7684\u76f4\u63a5\u64cd\u4f5c<br \/>\n    void Update(Channel *channel, int op)<br \/>\n    {<br \/>\n        \/\/ int epoll_ctl(int epfd, int op, int fd, struct epoll_event* ev);<br \/>\n        int fd &#061; channel-&gt;Fd();<br \/>\n        struct epoll_event ev;<br \/>\n        ev.data.fd &#061; fd;<br \/>\n        ev.events &#061; channel-&gt;Events();<br \/>\n        int ret &#061; epoll_ctl(_epfd, op, fd, &amp;ev);<br \/>\n        if (ret &lt; 0)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;EPOLLCTL FAILED!&#034;);<br \/>\n            \/\/ abort(); \/\/\u9000\u51fa\u7a0b\u5e8f<br \/>\n        }<br \/>\n        return;<br \/>\n    }<br \/>\n    \/\/ \u5224\u65ad\u4e00\u4e2aChannel\u662f\u5426\u5df2\u7ecf\u6dfb\u52a0\u4e86\u4e8b\u4ef6\u76d1\u63a7<br \/>\n    bool HasChannel(Channel *channel)<br \/>\n    {<br \/>\n        auto it &#061; _channels.find(channel-&gt;Fd());<br \/>\n        if (it &#061;&#061; _channels.end())<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<\/p>\n<p>public:<br \/>\n    Poller()<br \/>\n    {<br \/>\n        _epfd &#061; epoll_create(MAX_EPOLLEVENTS);<br \/>\n        if (_epfd &lt; 0)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;EPOLL CREATE FAILED!&#034;);<br \/>\n            abort();<br \/>\n        }<br \/>\n    }<br \/>\n    void UpdateEvent(Channel *channel) \/\/ \u6dfb\u52a0\u6216\u4fee\u6539\u76d1\u63a7\u4e8b\u4ef6<br \/>\n    {<br \/>\n        bool ret &#061; HasChannel(channel);<br \/>\n        if (ret &#061;&#061; false)<br \/>\n        {<br \/>\n            \/\/ \u4e0d\u5b58\u5728\u5219\u6dfb\u52a0<br \/>\n            _channels.insert(std::make_pair(channel-&gt;Fd(), channel));<br \/>\n            return Update(channel, EPOLL_CTL_ADD);<br \/>\n        }<br \/>\n        return Update(channel, EPOLL_CTL_MOD);<br \/>\n    }<br \/>\n    void RemoveEvent(Channel *channel) \/\/ \u79fb\u9664\u76d1\u63a7<br \/>\n    {<br \/>\n        auto it &#061; _channels.find(channel-&gt;Fd());<br \/>\n        {<br \/>\n            if (it !&#061; _channels.end())<br \/>\n            {<br \/>\n                _channels.erase(it);<br \/>\n            }<br \/>\n            Update(channel, EPOLL_CTL_DEL);<br \/>\n        }<br \/>\n    }<br \/>\n    void Poll(std::vector&lt;Channel *&gt; *active) \/\/ \u5f00\u59cb\u76d1\u63a7,\u8fd4\u56de\u6d3b\u8dc3\u8fde\u63a5<br \/>\n    {<br \/>\n        int nfds &#061; epoll_wait(_epfd, _evs, MAX_EPOLLEVENTS, -1); \/\/-1\u4ee3\u8868\u963b\u585e\u76d1\u63a7<br \/>\n        if (nfds &lt; 0)<br \/>\n        {<br \/>\n            if (errno &#061;&#061; EINTR)<br \/>\n            {<br \/>\n                return;<br \/>\n            }<br \/>\n            ERR_LOG(&#034;EPOLL WAIT ERROR:%s\\\\n&#034;, strerror(errno));<br \/>\n            abort();<br \/>\n        }<br \/>\n        for (int i &#061; 0; i &lt; nfds; i&#043;&#043;)<br \/>\n        {<br \/>\n            auto it &#061; _channels.find(_evs[i].data.fd);<br \/>\n            assert(it !&#061; _channels.end());<br \/>\n            it-&gt;second-&gt;SetREvents(_evs[i].events);<br \/>\n            active-&gt;push_back(it-&gt;second);<br \/>\n        }<br \/>\n        return;<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"2.6%20%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1%E7%AE%A1%E7%90%86TimerWheel%E7%B1%BB%E5%AE%9E%E7%8E%B0\">2.6 \u5b9a\u65f6\u4efb\u52a1\u7ba1\u7406TimerWheel\u7c7b\u5b9e\u73b0<\/h3>\n<p>\u524d\u9762\u7684\u51c6\u5907\u77e5\u8bc6\u4e2d\u6211\u4eec\u5df2\u7ecf\u57fa\u672c\u5b9e\u73b0\u4e86\u65f6\u95f4\u8f6e&#xff0c;\u552f\u4e00\u9700\u8981\u89e3\u91ca\u7684\u5c31\u662f\u5bf9\u4e8e\u5b9a\u65f6\u5668\u6587\u4ef6\u63cf\u8ff0\u7b26\u7684\u4f7f\u7528<\/p>\n<p>\u5b9a\u65f6\u5668\u6587\u4ef6\u63cf\u8ff0\u7b26\u7684\u521b\u5efa&#xff1a;timerfd_create<\/p>\n<p>\u7b2c\u4e00\u4e2a\u53c2\u6570\u4e00\u822c\u4f20\u5165\u7684\u662fCLOCK_MONOTONIC&#xff0c;\u8868\u793a\u4f7f\u7528\u5355\u8c03\u65f6\u949f&#xff0c;\u4e0d\u6536\u7cfb\u7edf\u65f6\u95f4\u8c03\u6574\u5f71\u54cd<\/p>\n<p>\u7b2c\u4e8c\u4e2a\u53c2\u6570\u4f20\u51650\u8868\u793a\u6ca1\u6709\u7279\u6b8a\u6807\u5fd7<\/p>\n<p>\u7136\u540e\u6211\u4eec\u9700\u8981\u8bbe\u7f6e\u5b9a\u65f6\u5668\u53c2\u6570&#xff0c;\u8fd9\u91cc\u4f7f\u7528\u7684\u662fitimerspec\u7c7b\u578b\u7684\u7ed3\u6784\u4f53<\/p>\n<p> struct itimerspec<br \/>\n{<br \/>\n    struct timespec it_interval;<br \/>\n    struct timespec it_value;<br \/>\n};<\/p>\n<p>it_value\u5305\u542b\u4e24\u4e2a\u53c2\u6570&#xff0c;tv_sec\u548ctv_nsec\u5206\u522b\u7528\u6765\u8bbe\u7f6e\u79d2\u548c\u6beb\u79d2&#xff0c;tv_sec\u7528\u6765\u8bbe\u7f6e\u7b2c\u4e00\u6b21\u8d85\u65f6\u65f6\u95f4&#xff0c;it_interval\u540c\u6837\u5305\u542b\u4e24\u4e2a\u53c2\u6570tv_sec\u548ctv_nsec&#xff0c;\u7528\u6765\u8bbe\u7f6e\u7b2c\u4e00\u6b21\u8d85\u65f6\u540e&#xff0c;\u6bcf\u6b21\u7684\u8d85\u65f6\u65f6\u95f4\u95f4\u9694<\/p>\n<p>\u53ef\u4ee5\u4f7f\u7528read\u51fd\u6570&#xff0c;\u4f20\u5165\u5b9a\u65f6\u5668\u6587\u4ef6\u63cf\u8ff0\u7b26\u6765\u8bfb\u53d6\u4e00\u5171\u8d85\u65f6\u4e86\u591a\u5c11\u6b21<\/p>\n<p> int ret &#061; read(_timerfd, &amp;times, 8); <\/p>\n<p>\u4e0b\u9762\u5c31\u662f\u8fd9\u4e2a\u7c7b\u5b8c\u6574\u4ee3\u7801\u4e86<\/p>\n<p> using TaskFunc &#061; std::function&lt;void()&gt;;<br \/>\nusing ReleaseFunc &#061; std::function&lt;void()&gt;;<br \/>\nclass TimerTask<br \/>\n{<br \/>\nprivate:<br \/>\n    uint64_t _id;         \/\/ \u5b9a\u65f6\u5668\u4efb\u52a1\u5bf9\u8c61id<br \/>\n    uint32_t _timeout;    \/\/ \u5b9a\u65f6\u4efb\u52a1\u7684\u8d85\u65f6\u65f6\u95f4<br \/>\n    bool _canceled;       \/\/ false-\u8868\u793a\u6ca1\u6709\u88ab\u53d6\u6d88<br \/>\n    TaskFunc _task_cb;    \/\/ \u5b9a\u65f6\u5668\u5bf9\u8c61\u8981\u6267\u884c\u7684\u5b9a\u65f6\u4efb\u52a1<br \/>\n    ReleaseFunc _release; \/\/ \u7528\u4e8e\u5220\u9664TimerWheel\u4e2d\u4fdd\u5b58\u7684\u5b9a\u65f6\u5668\u5bf9\u8c61\u4fe1\u606f<br \/>\npublic:<br \/>\n    TimerTask(uint64_t id, uint32_t delay, const TaskFunc &amp;cb)<br \/>\n        : _id(id), _timeout(delay), _task_cb(cb), _canceled(false)<br \/>\n    {<br \/>\n    }<\/p>\n<p>    ~TimerTask()<br \/>\n    {<br \/>\n        if (_canceled &#061;&#061; false)<br \/>\n            _task_cb();<br \/>\n        _release();<br \/>\n    }<\/p>\n<p>    void Cancel()<br \/>\n    {<br \/>\n        _canceled &#061; true;<br \/>\n    }<\/p>\n<p>    void SetRelease(const ReleaseFunc &amp;cb)<br \/>\n    {<br \/>\n        _release &#061; cb;<br \/>\n    }<\/p>\n<p>    uint32_t DelayTime()<br \/>\n    {<br \/>\n        return _timeout;<br \/>\n    }<br \/>\n};<\/p>\n<p>class TimerWheel<br \/>\n{<br \/>\nprivate:<br \/>\n    using WeakTask &#061; std::weak_ptr&lt;TimerTask&gt;;<br \/>\n    using PtrTask &#061; std::shared_ptr&lt;TimerTask&gt;;<br \/>\n    int _tick;     \/\/ \u5f53\u524d\u7684\u79d2\u9488&#xff0c;\u8d70\u5230\u54ea\u91cc\u91ca\u653e\u54ea\u91cc<br \/>\n    int _capacity; \/\/ \u8868\u76d8\u6700\u5927\u6570\u91cf&#xff0c;\u5176\u5b9e\u5c31\u662f\u6700\u5927\u5ef6\u8fdf\u65f6\u95f4<br \/>\n    std::vector&lt;std::vector&lt;PtrTask&gt;&gt; _wheel;<br \/>\n    std::unordered_map&lt;uint64_t, WeakTask&gt; _timers; \/\/ \u4f7f\u7528\u4efb\u52a1ID\u627e\u5230\u5bf9\u5e94\u7684weak_ptr<\/p>\n<p>    EventLoop *_loop;<br \/>\n    int _timerfd; \/\/ \u5b9a\u65f6\u5668\u63cf\u8ff0\u7b26<br \/>\n    std::unique_ptr&lt;Channel&gt; _timer_channel;<\/p>\n<p>private:<br \/>\n    void RemoveTimer(uint16_t id)<br \/>\n    {<br \/>\n        auto it &#061; _timers.find(id);<br \/>\n        if (it !&#061; _timers.end())<br \/>\n        {<br \/>\n            _timers.erase(it);<br \/>\n        }<br \/>\n    }<br \/>\n    static int CreateTimerFd()<br \/>\n    {<br \/>\n        int timerfd &#061; timerfd_create(CLOCK_MONOTONIC, 0);<br \/>\n        if (timerfd &lt; 0)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;TIMERED CREATE FAILED!&#034;);<br \/>\n            abort();<br \/>\n        }<\/p>\n<p>        struct itimerspec itime;<br \/>\n        itime.it_value.tv_sec &#061; 1;<br \/>\n        itime.it_value.tv_nsec &#061; 0; \/\/ \u7b2c\u4e00\u6b21\u8d85\u65f6\u65f6\u95f4\u4e3a1s\u540e<br \/>\n        itime.it_interval.tv_sec &#061; 1;<br \/>\n        itime.it_interval.tv_nsec &#061; 0; \/\/ \u7b2c\u4e00\u6b21\u8d85\u65f6\u540e&#xff0c;\u6bcf\u6b21\u8d85\u65f6\u7684\u65f6\u95f4\u95f4\u9694<br \/>\n        timerfd_settime(timerfd, 0, &amp;itime, NULL);<br \/>\n        return timerfd;<br \/>\n    }<br \/>\n    int ReadTimefd()<br \/>\n    {<br \/>\n        uint64_t times;<br \/>\n        \/\/\u6709\u53ef\u80fd\u56e0\u4e3a\u5176\u4ed6\u63cf\u8ff0\u7b26\u7684\u4e8b\u4ef6\u5904\u7406\u82b1\u8d39\u65f6\u95f4\u6bd4\u8f83\u957f&#xff0c;\u7136\u540e\u5728\u5904\u7406\u5b9a\u65f6\u5668\u63cf\u8ff0\u7b26\u4e8b\u4ef6\u7684\u65f6\u5019&#xff0c;\u6709\u53ef\u80fd\u5c31\u5df2\u7ecf\u8d85\u65f6\u4e86\u5f88\u591a\u6b21<br \/>\n        \/\/read\u8bfb\u53d6\u5230\u7684\u6570\u636etimes\u5c31\u662f\u4ece\u4e0a\u4e00\u6b21read\u4e4b\u540e\u8d85\u65f6\u7684\u6b21\u6570<br \/>\n        int ret &#061; read(_timerfd, &amp;times, 8);<br \/>\n        if (ret &lt; 0)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;READ TIMER FAILED!&#034;);<br \/>\n            abort();<br \/>\n        }<br \/>\n        return times;<br \/>\n    }<br \/>\n    \/\/ \u8fd9\u4e2a\u51fd\u6570\u6bcf\u79d2\u88ab\u6267\u884c\u4e00\u6b21&#xff0c;\u76f8\u5f53\u4e8e\u79d2\u9488\u5411\u540e\u8d70\u4e86\u4e00\u6b65<br \/>\n    void RunTimeTask()<br \/>\n    {<br \/>\n        _tick &#061; (_tick &#043; 1) % _capacity;<br \/>\n        _wheel[_tick].clear();<br \/>\n    }<br \/>\n    void OnTime()<br \/>\n    {<br \/>\n        \/\/\u6839\u636e\u5b9e\u9645\u8d85\u65f6\u7684\u6b21\u6570&#xff0c;\u6267\u884c\u5bf9\u5e94\u7684\u8d85\u65f6\u4efb\u52a1<br \/>\n        int times &#061; ReadTimefd();<br \/>\n        for(int i &#061; 0; i &lt; times; i&#043;&#043;)<br \/>\n        {<br \/>\n            RunTimeTask();<br \/>\n        }<br \/>\n    }<br \/>\n    void TimerAddInLoop(uint64_t id, uint32_t delay, const TaskFunc &amp;cb) \/\/ \u6dfb\u52a0\u5b9a\u65f6\u4efb\u52a1<br \/>\n    {<br \/>\n        PtrTask pt(new TimerTask(id, delay, cb));<br \/>\n        pt-&gt;SetRelease(std::bind(&amp;TimerWheel::RemoveTimer, this, id));<br \/>\n        int pos &#061; (_tick &#043; delay) % _capacity;<br \/>\n        _wheel[pos].push_back(pt);<br \/>\n        _timers[id] &#061; WeakTask(pt);<br \/>\n    }<\/p>\n<p>    void TimerRefreshInLoop(uint64_t id) \/\/ \u5237\u65b0\/\u5ef6\u8fdf\u5b9a\u65f6\u4efb\u52a1<br \/>\n    {<br \/>\n        \/\/ \u901a\u8fc7\u4fdd\u5b58\u7684\u5b9a\u65f6\u5668\u5bf9\u8c61\u7684weakptr\u6784\u9020\u4e00\u4e2ashared_ptr\u51fa\u6765&#xff0c;\u6dfb\u52a0\u5230\u8f6e\u5b50\u4e2d<br \/>\n        auto it &#061; _timers.find(id);<br \/>\n        if (it &#061;&#061; _timers.end())<br \/>\n        {<br \/>\n            \/\/ \u6ca1\u6709\u627e\u5230\u5b9a\u65f6\u4efb\u52a1<br \/>\n            return;<br \/>\n        }<br \/>\n        PtrTask pt &#061; it-&gt;second.lock(); \/\/ lock\u83b7\u53d6weakptr\u7ba1\u7406\u7684\u5bf9\u8c61\u5bf9\u5e94\u7684shared_ptr;<br \/>\n        int delay &#061; pt-&gt;DelayTime();<br \/>\n        int pos &#061; (_tick &#043; delay) % _capacity;<br \/>\n        _wheel[pos].push_back(pt);<br \/>\n    }<\/p>\n<p>    void TimerCancelInLoop(uint64_t id)<br \/>\n    {<br \/>\n        auto it &#061; _timers.find(id);<br \/>\n        if (it &#061;&#061; _timers.end())<br \/>\n        {<br \/>\n            \/\/ \u6ca1\u6709\u627e\u5230\u5b9a\u65f6\u4efb\u52a1<br \/>\n            return;<br \/>\n        }<br \/>\n        PtrTask pt &#061; it-&gt;second.lock();<br \/>\n        if (pt)<br \/>\n            pt-&gt;Cancel();<br \/>\n    }<\/p>\n<p>public:<br \/>\n    TimerWheel(EventLoop *loop)<br \/>\n        : _capacity(60),<br \/>\n          _tick(0),<br \/>\n          _wheel(_capacity),<br \/>\n          _loop(loop),<br \/>\n          _timerfd(CreateTimerFd()),<br \/>\n          _timer_channel(new Channel(_loop, _timerfd))<br \/>\n    {<br \/>\n        _timer_channel-&gt;SetReadCallback(std::bind(&amp;TimerWheel::OnTime, this));<br \/>\n        _timer_channel-&gt;EnableRead();<br \/>\n    }<br \/>\n    \/*\u5b9a\u65f6\u5668\u4e2d\u6709\u4e2a_timers\u6210\u5458&#xff0c;\u5b9a\u65f6\u5668\u4fe1\u606f\u7684\u64cd\u4f5c\u6709\u53ef\u80fd\u5728\u591a\u7ebf\u7a0b\u4e2d\u8fdb\u884c&#xff0c; \u56e0\u6b64\u9700\u8981\u8003\u8651\u7ebf\u7a0b\u5b89\u5168\u95ee\u9898*\/<br \/>\n    \/*\u5982\u679c\u4e0d\u60f3\u52a0\u9501&#xff0c;\u90a3\u5c31\u628a\u5bf9\u5b9a\u65f6\u7684\u6240\u6709\u64cd\u4f5c&#xff0c;\u90fd\u653e\u5728\u4e00\u4e2a\u7ebf\u7a0b\u4e2d\u8fdb\u884c*\/<br \/>\n    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &amp;cb);<br \/>\n    \/\/ \u5237\u65b0\/\u5ef6\u8fdf\u5b9a\u65f6\u4efb\u52a1<br \/>\n    void TimerRefresh(uint64_t id);<br \/>\n    void TimerCancel(uint64_t id);<br \/>\n    \/*\u8fd9\u4e2a\u63a5\u53e3\u5b58\u5728\u7ebf\u7a0b\u5b89\u5168\u95ee\u9898&#8211;\u8fd9\u4e2a\u63a5\u53e3\u5b9e\u9645\u4e0a\u4e0d\u80fd\u88ab\u5916\u754c\u4f7f\u7528\u8005\u8c03\u7528&#xff0c;\u53ea\u80fd\u5728\u6a21\u5757\u5185&#xff0c;\u5728\u5bf9\u5e94\u7684EventLoop\u7ebf\u7a0b\u5185\u6267\u884c*\/<br \/>\n    bool HasTimer(uint64_t id)<br \/>\n    {<br \/>\n        auto it &#061; _timers.find(id);<br \/>\n        if (it &#061;&#061; _timers.end())<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"2.7%C2%A0Reactor-EventLoop%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%B1%BB%E5%AE%9E%E7%8E%B0\" style=\"background-color:transparent\">2.7\u00a0Reactor-EventLoop\u7ebf\u7a0b\u6c60\u7c7b\u5b9e\u73b0<\/h3>\n<p>EventLoop\u6a21\u5757\u53ef\u4ee5\u7406\u89e3\u4e3aReactor\u6a21\u5757&#xff0c;\u5b83\u662f\u5bf9Poller\u6a21\u5757&#xff0c;TimeQueue\u6a21\u5757&#xff0c;Socket\u6a21\u5757\u7684\u4e00\u4e2a\u6574\u4f53\u5c01\u88c5&#xff0c;\u8fdb\u884c\u6240\u6709\u63cf\u8ff0\u7b26\u7684\u4e8b\u4ef6\u76d1\u63a7<\/p>\n<p>\u9996\u5148\u662fEventLoop\u7684\u79c1\u6709\u6210\u5458\u53d8\u91cf<\/p>\n<p> using Functor &#061; std::function&lt;void()&gt;;<br \/>\nstd::thread::id _thread_id;              \/\/ \u7ebf\u7a0bID<br \/>\nint _event_fd;                           \/\/ eventfd\u5524\u9192IO\u4e8b\u4ef6\u76d1\u63a7\u6709\u53ef\u80fd\u5bfc\u81f4\u7684\u963b\u585e<br \/>\nstd::unique_ptr&lt;Channel&gt; _event_channel; \/\/ \u901a\u8fc7\u8fd9\u4e2a\u6765\u7ba1\u7406_event_fd\u4e2d\u7684\u4e8b\u4ef6<br \/>\nPoller _poller;                          \/\/ \u8fdb\u884c\u6240\u6709\u63cf\u8ff0\u7b26\u7684\u4e8b\u4ef6\u76d1\u63a7<br \/>\nstd::vector&lt;Functor&gt; _tasks;             \/\/ \u4efb\u52a1\u6c60<br \/>\nstd::mutex _mutex;                       \/\/ \u5b9e\u73b0\u4efb\u52a1\u6c60\u64cd\u4f5c\u7684\u7ebf\u7a0b\u5b89\u5168<br \/>\nTimerWheel _timer_wheel;                 \/\/ \u5b9a\u65f6\u5668\u6a21\u5757 <\/p>\n<p>\u7136\u540e\u5c31\u662f\u5bf9\u5176\u4e2d\u7684\u6210\u5458\u51fd\u6570\u89e3\u91ca<\/p>\n<p>\u9996\u5148\u662f\u6267\u884c\u4efb\u52a1\u6c60\u4e2d\u7684\u6240\u6709\u4efb\u52a1RunAllTask\u51fd\u6570<\/p>\n<p> void RunAllTask()<br \/>\n{<br \/>\n    std::vector&lt;Functor&gt; functor;<br \/>\n    {<br \/>\n        std::unique_lock&lt;std::mutex&gt; _lock(_mutex);<br \/>\n        _tasks.swap(functor); \/\/ \u4ea4\u6362\u4e4b\u540e&#xff0c;\u4efb\u52a1\u5168\u90e8\u4ea4\u6362\u5230\u4e86functor\u91cc\u9762<br \/>\n    }<br \/>\n    for (auto &amp;f : functor)<br \/>\n    {<br \/>\n        f();<br \/>\n    }<br \/>\n} <\/p>\n<p>\u8fd9\u4e2a\u51fd\u6570\u6709\u4e00\u4e2a\u70b9\u9700\u8981\u89e3\u91ca\u4e00\u4e0b&#xff0c;\u5c31\u662f\u4e3a\u4ec0\u4e48\u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u8981\u52a0\u4e0a\u5927\u62ec\u53f7<\/p>\n<p> {<br \/>\n    std::unique_lock&lt;std::mutex&gt; _lock(_mutex);<br \/>\n    _tasks.swap(functor); \/\/ \u4ea4\u6362\u4e4b\u540e&#xff0c;\u4efb\u52a1\u5168\u90e8\u4ea4\u6362\u5230\u4e86functor\u91cc\u9762<br \/>\n} <\/p>\n<p>\u539f\u56e0&#xff1a;\u5927\u62ec\u53f7\u7528\u6765\u5b9a\u4e49\u4e00\u4e2a\u4f5c\u7528\u57df&#xff0c;\u4f7f\u7528\u5927\u62ec\u53f7\u5305\u542bstd::unique_lock&lt;srd::mutex&gt;\u7684\u58f0\u660e\u548c_tasks.swap(functor)\u7684\u8c03\u7528&#xff0c;\u662f\u4e3a\u4e86\u9650\u5236std::unique_lock\u5bf9\u8c61\u7684\u751f\u547d\u5468\u671f\u548c\u4f5c\u7528\u57df\u3002std::unique_lock&lt;std::mutex&gt;\u662f\u4e00\u4e2aRALL\u5bf9\u8c61&#xff0c;\u4f1a\u5728\u6784\u9020\u65f6\u83b7\u53d6\u9501&#xff0c;\u5e76\u5728\u6790\u6784\u65f6\u81ea\u52a8\u91ca\u653e\u9501&#xff0c;\u5c06\u5bf9\u8c61\u7684\u4f5c\u7528\u57df\u9650\u5236\u5728\u5927\u62ec\u53f7\u5185&#xff0c;\u53ef\u4ee5\u786e\u4fdd\u5728\u79bb\u5f00\u8fd9\u4e2a\u4f5c\u7528\u57df\u65f6&#xff0c;\u9501\u4f1a\u88ab\u81ea\u52a8\u91ca\u653e&#xff0c;\u8fd9\u53ef\u4ee5\u9632\u6b62\u7531\u4e8e\u5f02\u5e38\u6216\u63d0\u524d\u8fd4\u56de\u5bfc\u81f4\u7684\u9501\u672a\u91ca\u653e\u95ee\u9898<\/p>\n<p> \u521b\u5efaeventfd<\/p>\n<p> static int CreateEventFd()<br \/>\n{<br \/>\n    int efd &#061; eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);<br \/>\n    if (efd &lt; 0)<br \/>\n    {<br \/>\n        ERR_LOG(&#034;CREATE EVENTFD FAILED!&#034;);<br \/>\n        abort();<br \/>\n    }<br \/>\n    return efd;<br \/>\n} <\/p>\n<p>\u8fd9\u91cc\u89e3\u91ca\u4e00\u4e0beventfd\u51fd\u6570<\/p>\n<p>\u7b2c\u4e00\u4e2a\u53c2\u65700\u8868\u793a\u521d\u59cb\u4e8b\u4ef6\u8ba1\u6570\u4e3a0&#xff0c;\u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u6807\u5fd7\u4f4d&#xff0c;\u7528\u4e8e\u63a7\u5236eventfd\u7684\u884c\u4e3a<\/p>\n<p>EFD_CLOEXEC&#xff1a;\u8bbe\u7f6eclose-on-exec\u6807\u5fd7&#xff0c;\u786e\u4fdd\u5728\u6267\u884cexec\u7cfb\u5217\u51fd\u6570\u65f6\u5173\u95ed\u6587\u4ef6\u63cf\u8ff0\u7b26<\/p>\n<p>\u4f8b\u5982&#xff0c;\u5728\u521b\u5efa\u5b50\u8fdb\u7a0b\u65f6&#xff0c;\u7236\u8fdb\u7a0b\u53ef\u80fd\u6253\u5f00\u4e86\u4e00\u4e9b\u6587\u4ef6\u63cf\u8ff0\u7b26\u7528\u4e8e\u5185\u90e8\u901a\u4fe1\u3002\u5982\u679c\u4e0d\u8bbe\u7f6eclose-on-exec\u6807\u5fd7&#xff0c;\u8fd9\u4e9b\u6587\u4ef6\u63cf\u8ff0\u7b26\u53ef\u80fd\u4f1a\u88ab\u5b50\u8fdb\u7a0b\u7ee7\u627f&#xff0c;\u5bfc\u81f4\u8d44\u6e90\u6cc4\u6f0f\u6216\u5b89\u5168\u95ee\u9898\u3002<\/p>\n<p>EFD_NONBLOCK&#xff1a;\u8bbe\u7f6e\u975e\u963b\u585e\u6a21\u5f0f&#xff0c;\u5bf9eventfd\u7684\u8bfb\u5199\u64cd\u4f5c\u4e0d\u4f1a\u963b\u585e\u8c03\u7528\u7ebf\u7a0b<\/p>\n<p> \u4ece_event_fd\u4e2d\u8bfb\u53d6\u4e8b\u4ef6\u8ba1\u6570<\/p>\n<p> void ReadEventFd()<br \/>\n{<br \/>\n    uint64_t res &#061; 0;<br \/>\n    int ret &#061; read(_event_fd, &amp;res, sizeof(res));<br \/>\n    if (ret &lt; 0)<br \/>\n    {<br \/>\n        if (errno &#061;&#061; EINTR || errno &#061;&#061; EAGAIN)<br \/>\n        {<br \/>\n            return;<br \/>\n        }<br \/>\n        ERR_LOG(&#034;READ EVENTFD FAILED!&#034;);<br \/>\n        abort();<br \/>\n    }<br \/>\n    return;<br \/>\n} <\/p>\n<p>\u5411eventfd\u4e2d\u5199\u5165\u4e00\u4e2a\u4e8b\u4ef6\u8ba1\u6570&#xff0c;\u4ee5\u901a\u77e5\u5176\u4ed6\u7ebf\u7a0b\u6216\u8fdb\u7a0b\u4e8b\u4ef6\u7684\u53d1\u751f<\/p>\n<p> void WakeUpEventFd()<br \/>\n{<br \/>\n    uint64_t val &#061; 1;<br \/>\n    int ret &#061; write(_event_fd, &amp;val, sizeof(val));<br \/>\n    if (ret &lt; 0)<br \/>\n    {<br \/>\n        if (errno &#061;&#061; EINTR)<br \/>\n        {<br \/>\n            return;<br \/>\n        }<br \/>\n        ERR_LOG(&#034;READ EVENTFD FAILED!&#034;);<br \/>\n        abort();<br \/>\n    }<br \/>\n    return;<br \/>\n} <\/p>\n<p>Start\u51fd\u6570&#xff0c;\u5206\u4e3a\u4e09\u4e2a\u6b65\u9aa4&#xff1a;\u4e8b\u4ef6\u76d1\u63a7-&gt;\u5c31\u7eea\u4e8b\u4ef6\u5904\u7406-&gt;\u6267\u884c\u4efb\u52a1<\/p>\n<p> void Start()<br \/>\n{<br \/>\n    while (1)<br \/>\n    {<br \/>\n        std::vector&lt;Channel *&gt; actives;<br \/>\n        _poller.Poll(&amp;actives);<\/p>\n<p>        for (auto &amp;channel : actives)<br \/>\n        {<br \/>\n            channel-&gt;HandleEvent();<br \/>\n        }<\/p>\n<p>        RunAllTask();<br \/>\n    }<br \/>\n} <\/p>\n<p>\u4f7f\u7528IsInLoop\u51fd\u6570\u5224\u65ad\u5f53\u524d\u7ebf\u7a0b\u662f\u5426\u4e3aeventloop\u5bf9\u5e94\u7684\u7ebf\u7a0b<\/p>\n<p> bool IsInLoop()<br \/>\n{<br \/>\n    return (_thread_id &#061;&#061; std::this_thread::get_id());<br \/>\n} <\/p>\n<p>\u5224\u65ad\u8981\u6267\u884c\u7684\u4efb\u52a1\u662f\u5426\u5904\u4e8e\u5f53\u524d\u7ebf\u7a0b\u4e2d&#xff0c;\u5982\u679c\u662f\u5219\u6267\u884c&#xff0c;\u4e0d\u662f\u5219\u538b\u5165\u961f\u5217<\/p>\n<p> void RunInLoop(const Functor &amp;cb)<br \/>\n{<br \/>\n    if (IsInLoop())<br \/>\n    {<br \/>\n        return cb();<br \/>\n    }<br \/>\n    return QueueInLoop(cb);<br \/>\n} <\/p>\n<p>\u5c06\u64cd\u4f5c\u538b\u5165\u4efb\u52a1\u6c60<\/p>\n<p> void QueueInLoop(const Functor &amp;cb)<br \/>\n{<br \/>\n    {<br \/>\n        std::unique_lock&lt;std::mutex&gt; _lock(_mutex);<br \/>\n        _tasks.push_back(cb);<br \/>\n    }<br \/>\n    \/\/ \u5524\u9192\u6709\u53ef\u80fd\u56e0\u4e3a\u6ca1\u6709\u4e8b\u4ef6\u5c31\u7eea\u800c\u5bfc\u81f4\u7684epoll\u963b\u585e<br \/>\n    \/\/ \u5176\u5b9e\u5c31\u662f\u7ed9eventfd\u5199\u5165\u4e00\u4e2a\u6570\u636e&#xff0c;eventfd\u5c31\u4f1a\u89e6\u53d1\u53ef\u8bfb\u4e8b\u4ef6<br \/>\n    WakeUpEventFd();<br \/>\n} <\/p>\n<p>\u6700\u540e\u5c31\u662f\u5bf9\u63cf\u8ff0\u7b26\u76d1\u63a7\u7684\u64cd\u4f5c<\/p>\n<p> \/\/ \u6dfb\u52a0\/\u4fee\u6539\u63cf\u8ff0\u7b26\u7684\u4e8b\u4ef6\u76d1\u63a7<br \/>\nvoid UpdateEvent(Channel *channel)<br \/>\n{<br \/>\n    return _poller.UpdateEvent(channel);<br \/>\n}<br \/>\n\/\/ \u79fb\u9664\u63cf\u8ff0\u7b26\u7684\u76d1\u63a7<br \/>\nvoid RemoveEvent(Channel *channel)<br \/>\n{<br \/>\n    return _poller.RemoveEvent(channel);<br \/>\n}<br \/>\nvoid TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &amp;cb)<br \/>\n{<br \/>\n    return _timer_wheel.TimerAdd(id, delay, cb);<br \/>\n}<br \/>\nvoid TimerRefresh(uint64_t id)<br \/>\n{<br \/>\n    return _timer_wheel.TimerRefresh(id);<br \/>\n}<br \/>\nvoid TimerCancel(uint64_t id)<br \/>\n{<br \/>\n    return _timer_wheel.TimerCancel(id);<br \/>\n}<br \/>\nbool HasTimer(uint64_t id)<br \/>\n{<br \/>\n    return _timer_wheel.HasTimer(id);<br \/>\n} <\/p>\n<p>\u5168\u90e8\u4ee3\u7801\u5982\u4e0b<\/p>\n<p> class EventLoop<br \/>\n{<br \/>\nprivate:<br \/>\n    using Functor &#061; std::function&lt;void()&gt;;<br \/>\n    std::thread::id _thread_id;              \/\/ \u7ebf\u7a0bID<br \/>\n    int _event_fd;                           \/\/ eventfd\u5524\u9192IO\u4e8b\u4ef6\u76d1\u63a7\u6709\u53ef\u80fd\u5bfc\u81f4\u7684\u963b\u585e<br \/>\n    std::unique_ptr&lt;Channel&gt; _event_channel; \/\/ \u901a\u8fc7\u8fd9\u4e2a\u6765\u7ba1\u7406_event_fd\u4e2d\u7684\u4e8b\u4ef6<br \/>\n    Poller _poller;                          \/\/ \u8fdb\u884c\u6240\u6709\u63cf\u8ff0\u7b26\u7684\u4e8b\u4ef6\u76d1\u63a7<br \/>\n    std::vector&lt;Functor&gt; _tasks;             \/\/ \u4efb\u52a1\u6c60<br \/>\n    std::mutex _mutex;                       \/\/ \u5b9e\u73b0\u4efb\u52a1\u6c60\u64cd\u4f5c\u7684\u7ebf\u7a0b\u5b89\u5168<br \/>\n    TimerWheel _timer_wheel;                 \/\/ \u5b9a\u65f6\u5668\u6a21\u5757<br \/>\npublic:<br \/>\n    \/\/ \u6267\u884c\u4efb\u52a1\u6c60\u4e2d\u7684\u6240\u6709\u4efb\u52a1<br \/>\n    void RunAllTask()<br \/>\n    {<br \/>\n        std::vector&lt;Functor&gt; functor;<br \/>\n        {<br \/>\n            std::unique_lock&lt;std::mutex&gt; _lock(_mutex);<br \/>\n            _tasks.swap(functor); \/\/ \u4ea4\u6362\u4e4b\u540e&#xff0c;\u4efb\u52a1\u5168\u90e8\u4ea4\u6362\u5230\u4e86functor\u91cc\u9762<br \/>\n        }<br \/>\n        for (auto &amp;f : functor)<br \/>\n        {<br \/>\n            f();<br \/>\n        }<br \/>\n    }<br \/>\n    static int CreateEventFd()<br \/>\n    {<br \/>\n        int efd &#061; eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);<br \/>\n        if (efd &lt; 0)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;CREATE EVENTFD FAILED!&#034;);<br \/>\n            abort();<br \/>\n        }<br \/>\n        return efd;<br \/>\n    }<br \/>\n    void ReadEventFd()<br \/>\n    {<br \/>\n        uint64_t res &#061; 0;<br \/>\n        int ret &#061; read(_event_fd, &amp;res, sizeof(res));<br \/>\n        if (ret &lt; 0)<br \/>\n        {<br \/>\n            if (errno &#061;&#061; EINTR || errno &#061;&#061; EAGAIN)<br \/>\n            {<br \/>\n                return;<br \/>\n            }<br \/>\n            ERR_LOG(&#034;READ EVENTFD FAILED!&#034;);<br \/>\n            abort();<br \/>\n        }<br \/>\n        return;<br \/>\n    }<br \/>\n    void WakeUpEventFd()<br \/>\n    {<br \/>\n        uint64_t val &#061; 1;<br \/>\n        int ret &#061; write(_event_fd, &amp;val, sizeof(val));<br \/>\n        if (ret &lt; 0)<br \/>\n        {<br \/>\n            if (errno &#061;&#061; EINTR)<br \/>\n            {<br \/>\n                return;<br \/>\n            }<br \/>\n            ERR_LOG(&#034;READ EVENTFD FAILED!&#034;);<br \/>\n            abort();<br \/>\n        }<br \/>\n        return;<br \/>\n    }<\/p>\n<p>public:<br \/>\n    EventLoop()<br \/>\n        : _thread_id(std::this_thread::get_id()),<br \/>\n          _event_fd(CreateEventFd()),<br \/>\n          _event_channel(new Channel(this, _event_fd)),<br \/>\n          _timer_wheel(this)<br \/>\n    {<br \/>\n        _event_channel-&gt;SetReadCallback(std::bind(&amp;EventLoop::ReadEventFd, this));<br \/>\n        \/\/ \u542f\u52a8eventfd\u8bfb\u4e8b\u4ef6\u76d1\u63a7<br \/>\n        _event_channel-&gt;EnableRead();<br \/>\n    }<br \/>\n    void Start() \/\/ \u4e09\u6b65\u8d70&#8211;\u4e8b\u4ef6\u76d1\u63a7-&gt;\u5c31\u7eea\u4e8b\u4ef6\u5904\u7406-&gt;\u6267\u884c\u4efb\u52a1<br \/>\n    {<br \/>\n        while (1)<br \/>\n        {<br \/>\n            std::vector&lt;Channel *&gt; actives;<br \/>\n            _poller.Poll(&amp;actives);<\/p>\n<p>            for (auto &amp;channel : actives)<br \/>\n            {<br \/>\n                channel-&gt;HandleEvent();<br \/>\n            }<\/p>\n<p>            RunAllTask();<br \/>\n        }<br \/>\n    }<br \/>\n    \/\/ \u7528\u4e8e\u5224\u65ad\u5f53\u524d\u7ebf\u7a0b\u662f\u5426\u662feventloop\u5bf9\u5e94\u7684\u7ebf\u7a0b<br \/>\n    bool IsInLoop()<br \/>\n    {<br \/>\n        return (_thread_id &#061;&#061; std::this_thread::get_id());<br \/>\n    }<br \/>\n    void AssertInLoop()<br \/>\n    {<br \/>\n        assert(_thread_id &#061;&#061; std::this_thread::get_id());<br \/>\n    }<br \/>\n    \/\/ \u5224\u65ad\u8981\u6267\u884c\u7684\u4efb\u52a1\u662f\u5426\u5904\u4e8e\u5f53\u524d\u7ebf\u7a0b\u4e2d&#xff0c;\u5982\u679c\u662f\u5219\u6267\u884c&#xff0c;\u5982\u679c\u4e0d\u662f\u5219\u538b\u5165\u961f\u5217<br \/>\n    void RunInLoop(const Functor &amp;cb)<br \/>\n    {<br \/>\n        if (IsInLoop())<br \/>\n        {<br \/>\n            return cb();<br \/>\n        }<br \/>\n        return QueueInLoop(cb);<br \/>\n    }<br \/>\n    \/\/ \u5c06\u64cd\u4f5c\u538b\u5165\u4efb\u52a1\u6c60<br \/>\n    void QueueInLoop(const Functor &amp;cb)<br \/>\n    {<br \/>\n        {<br \/>\n            std::unique_lock&lt;std::mutex&gt; _lock(_mutex);<br \/>\n            _tasks.push_back(cb);<br \/>\n        }<br \/>\n        \/\/ \u5524\u9192\u6709\u53ef\u80fd\u56e0\u4e3a\u6ca1\u6709\u4e8b\u4ef6\u5c31\u7eea\u800c\u5bfc\u81f4\u7684epoll\u963b\u585e<br \/>\n        \/\/ \u5176\u5b9e\u5c31\u662f\u7ed9eventfd\u5199\u5165\u4e00\u4e2a\u6570\u636e&#xff0c;eventfd\u5c31\u4f1a\u89e6\u53d1\u53ef\u8bfb\u4e8b\u4ef6<br \/>\n        WakeUpEventFd();<br \/>\n    }<br \/>\n    \/\/ \u6dfb\u52a0\/\u4fee\u6539\u63cf\u8ff0\u7b26\u7684\u4e8b\u4ef6\u76d1\u63a7<br \/>\n    void UpdateEvent(Channel *channel)<br \/>\n    {<br \/>\n        return _poller.UpdateEvent(channel);<br \/>\n    }<br \/>\n    \/\/ \u79fb\u9664\u63cf\u8ff0\u7b26\u7684\u76d1\u63a7<br \/>\n    void RemoveEvent(Channel *channel)<br \/>\n    {<br \/>\n        return _poller.RemoveEvent(channel);<br \/>\n    }<br \/>\n    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &amp;cb)<br \/>\n    {<br \/>\n        return _timer_wheel.TimerAdd(id, delay, cb);<br \/>\n    }<br \/>\n    void TimerRefresh(uint64_t id)<br \/>\n    {<br \/>\n        return _timer_wheel.TimerRefresh(id);<br \/>\n    }<br \/>\n    void TimerCancel(uint64_t id)<br \/>\n    {<br \/>\n        return _timer_wheel.TimerCancel(id);<br \/>\n    }<br \/>\n    bool HasTimer(uint64_t id)<br \/>\n    {<br \/>\n        return _timer_wheel.HasTimer(id);<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"%C2%A02.8%20%E7%94%A8%E4%BA%8E%E7%AE%A1%E7%90%86%E5%8D%95%E4%B8%AA%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF%E7%BA%BF%E7%A8%8BLoopThread%E7%B1%BB\" style=\"background-color:transparent\">\u00a02.8 \u7528\u4e8e\u7ba1\u7406\u5355\u4e2a\u4e8b\u4ef6\u5faa\u73af\u7ebf\u7a0bLoopThread\u7c7b<\/h3>\n<p>\u8fd9\u4e2a\u7c7b\u7684\u4e3b\u8981\u4f5c\u7528\u662f\u786e\u4fdd\u7ebf\u7a0b\u5b89\u5168\u5730\u521b\u5efa\u548c\u8bbf\u95eeEventLoop\u5bf9\u8c61<\/p>\n<p>\u5173\u4e8e\u6210\u5458\u53d8\u91cf<\/p>\n<p> std::mutex _mutex;             \/\/ \u4e92\u65a5\u9501<br \/>\nstd::condition_variable _cond; \/\/ \u6761\u4ef6\u53d8\u91cf<br \/>\nEventLoop *_loop;              \/\/ EventLoop\u6307\u9488\u53d8\u91cf&#xff0c;\u8fd9\u4e2a\u5bf9\u8c61\u9700\u8981\u5728\u7ebf\u7a0b<br \/>\nstd::thread _thread;           \/\/ EventLoop\u5bf9\u5e94\u7684\u7ebf\u7a0b <\/p>\n<p>\u63a5\u4e0b\u6765\u89e3\u91ca\u4e00\u4e0b\u6210\u5458\u51fd\u6570<\/p>\n<p>\u9996\u5148\u662fThreadEntry&#xff0c;\u8d1f\u8d23\u5728\u7ebf\u7a0b\u4e2d\u5b9e\u4f8b\u5316EventLoop\u5bf9\u8c61&#xff0c;\u5e76\u786e\u4fdd\u5176\u4ed6\u7ebf\u7a0b\u80fd\u591f\u5b89\u5168\u5730\u8bbf\u95ee\u8fd9\u4e2aEventLoop\u5bf9\u8c61\u3002<\/p>\n<p> void ThreadEntry()<br \/>\n{<br \/>\n    EventLoop loop;<br \/>\n    {<br \/>\n        std::unique_lock&lt;std::mutex&gt; lock(_mutex);<br \/>\n        _loop &#061; &amp;loop;<br \/>\n        _cond.notify_all();<br \/>\n    }<br \/>\n    loop.Start();<br \/>\n} <\/p>\n<p>\u8fd9\u91cc\u89e3\u91ca\u4e00\u4e0b_cond.notify_all()&#xff0c;\u4ed6\u53ef\u4ee5\u5524\u9192\u6240\u6709\u5728_cond\u6761\u4ef6\u53d8\u91cf\u4e0a\u7b49\u5f85\u7684\u7ebf\u7a0b&#xff0c;\u901a\u77e5\u4ed6\u4eec_loop\u5df2\u7ecf\u521d\u59cb\u5316\u5b8c\u6210\u3002<\/p>\n<p> \u5173\u4e8e\u8fd9\u4e2a\u7c7b\u7684\u521d\u59cb\u5316\u51fd\u6570<\/p>\n<p>\u521d\u59cb\u5316_thread\u6210\u5458\u53d8\u91cf\u4e3a\u4e00\u4e2a\u65b0\u7684\u7ebf\u7a0b&#xff0c;\u8be5\u7ebf\u7a0b\u5c06\u6267\u884cThreadEntry\u65b9\u6cd5\u3002<\/p>\n<p> LoopThread()<br \/>\n    : _loop(NULL),<br \/>\n      _thread(std::thread(&amp;LoopThread::ThreadEntry, this))<br \/>\n{<br \/>\n} <\/p>\n<p>\u7136\u540e\u5c31\u662f\u8fd4\u56de\u5f53\u524d\u7ebf\u7a0b\u5173\u8054\u7684EventLoop\u6307\u9488<\/p>\n<p>\u76f4\u5230_loop\u4e0d\u4e3a\u7a7a\u624d\u5c06loop\u521d\u59cb\u5316<\/p>\n<p> EventLoop *GetLoop()<br \/>\n{<br \/>\n    EventLoop *loop &#061; NULL;<br \/>\n    {<br \/>\n        std::unique_lock&lt;std::mutex&gt; lock(_mutex); \/\/ \u52a0\u9501<br \/>\n        \/*\u6ee1\u8db3\u4ec0\u4e48\u7684\u6761\u4ef6\u5c31\u4e0d\u4f1a\u7b49\u5f85*\/<br \/>\n        \/\/ loop\u4e3a\u7a7a\u5c31\u4e00\u76f4\u963b\u585e<br \/>\n        _cond.wait(lock, [&amp;]()<br \/>\n                    { return _loop !&#061; NULL; });<br \/>\n        loop &#061; _loop;<br \/>\n    }<br \/>\n    return loop;<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662f\u5b8c\u6574\u4ee3\u7801<\/p>\n<p> class LoopThread<br \/>\n{<br \/>\nprivate:<br \/>\n    \/*\u7528\u4e8e\u5b9e\u73b0_loop\u83b7\u53d6\u7684\u540c\u6b65\u5173\u7cfb&#xff0c;\u907f\u514d\u7ebf\u7a0b\u521b\u5efa\u4e86&#xff0c;\u4f46\u662f_loop\u8fd8\u6ca1\u6709\u5b9e\u4f8b\u5316\u4e4b\u524d\u53bb\u83b7\u53d6_loop*\/<br \/>\n    std::mutex _mutex;             \/\/ \u4e92\u65a5\u9501<br \/>\n    std::condition_variable _cond; \/\/ \u6761\u4ef6\u53d8\u91cf<br \/>\n    EventLoop *_loop;              \/\/ EventLoop\u6307\u9488\u53d8\u91cf&#xff0c;\u8fd9\u4e2a\u5bf9\u8c61\u9700\u8981\u5728\u7ebf\u7a0b<br \/>\n    std::thread _thread;           \/\/ EventLoop\u5bf9\u5e94\u7684\u7ebf\u7a0b<br \/>\nprivate:<br \/>\n    \/*\u5b9e\u4f8b\u5316EventLoop\u5bf9\u8c61&#xff0c;\u5524\u9192_cond\u4e0a\u6709\u53ef\u80fd\u963b\u585e\u7684\u7ebf\u7a0b&#xff0c;\u5e76\u4e14\u5f00\u59cb\u8fd0\u884cEventLoop\u6a21\u5757\u7684\u529f\u80fd*\/<br \/>\n    void ThreadEntry()<br \/>\n    {<br \/>\n        EventLoop loop;<br \/>\n        {<br \/>\n            std::unique_lock&lt;std::mutex&gt; lock(_mutex);<br \/>\n            _loop &#061; &amp;loop;<br \/>\n            _cond.notify_all();<br \/>\n        }<br \/>\n        loop.Start();<br \/>\n    }<\/p>\n<p>public:<br \/>\n    \/*\u521b\u5efa\u7ebf\u7a0b&#xff0c;\u8bbe\u7f6e\u7ebf\u7a0b\u5165\u53e3\u51fd\u6570*\/<br \/>\n    LoopThread()<br \/>\n        : _loop(NULL),<br \/>\n          _thread(std::thread(&amp;LoopThread::ThreadEntry, this))<br \/>\n    {<br \/>\n    }<br \/>\n    \/*\u8fd4\u56de\u5f53\u524d\u7ebf\u7a0b\u5173\u8054\u7684EventLoop\u6307\u9488*\/<br \/>\n    EventLoop *GetLoop()<br \/>\n    {<br \/>\n        EventLoop *loop &#061; NULL;<br \/>\n        {<br \/>\n            std::unique_lock&lt;std::mutex&gt; lock(_mutex); \/\/ \u52a0\u9501<br \/>\n            \/*\u6ee1\u8db3\u4ec0\u4e48\u7684\u6761\u4ef6\u5c31\u4e0d\u4f1a\u7b49\u5f85*\/<br \/>\n            \/\/ loop\u4e3a\u7a7a\u5c31\u4e00\u76f4\u963b\u585e<br \/>\n            _cond.wait(lock, [&amp;]()<br \/>\n                       { return _loop !&#061; NULL; });<br \/>\n            loop &#061; _loop;<br \/>\n        }<br \/>\n        return loop;<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"2.9%C2%A0%C2%A0%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E4%B8%BB%E8%A6%81%E9%80%BB%E8%BE%91LoopThreadPool%E7%B1%BB\">2.9\u00a0\u00a0\u7ebf\u7a0b\u6c60\u7684\u4e3b\u8981\u903b\u8f91LoopThreadPool\u7c7b<\/h3>\n<p>LoopThreadPool\u7528\u4e8e\u7ba1\u7406\u591a\u4e2aLoopThread\u5bf9\u8c61&#xff0c;\u63d0\u4f9b\u7ebf\u7a0b\u6c60\u529f\u80fd<\/p>\n<p>\u9996\u5148\u662f\u6210\u5458\u53d8\u91cf<\/p>\n<p> int _thread_count;<br \/>\nint _next_idx;<br \/>\nEventLoop *_baseloop;<br \/>\nstd::vector&lt;LoopThread *&gt; _threads;<br \/>\nstd::vector&lt;EventLoop *&gt; _loops; <\/p>\n<ul>\n<li>_thread_count&#xff1a;\u7ebf\u7a0b\u7684\u6570\u91cf<\/li>\n<li>_next_idx&#xff1a;\u4e0b\u4e00\u4e2a\u7ebf\u7a0b\u7684\u7d22\u5f15<\/li>\n<li>_baseloop&#xff1a;\u6307\u5411\u4e00\u4e2aEventLoop\u7684\u6307\u9488<\/li>\n<li>_threads&#xff1a;\u5b58\u50a8\u6307\u5411LoopThread\u5bf9\u8c61\u7684\u6307\u9488<\/li>\n<li>_loops&#xff1a;\u5b58\u50a8\u6307\u5411EventLoop\u5bf9\u8c61\u7684\u6307\u9488<\/li>\n<\/ul>\n<p>\u7136\u540e\u5c31\u662f\u5bf9\u4e3b\u8981\u7684\u6210\u5458\u51fd\u6570\u7684\u89e3\u91ca<\/p>\n<p>\u9996\u5148\u662f\u5bf9\u7ebf\u7a0b\u6c60\u7684\u521b\u5efaCreate()<\/p>\n<p>\u5f53\u7ebf\u7a0b\u7684\u603b\u6570\u5927\u4e8e0\u7684\u65f6\u5019&#xff0c;\u9996\u5148\u9700\u8981\u5bf9_threads\u548c_loops\u8fd9\u4e24\u4e2a\u6570\u7ec4\u8fdb\u884c\u521d\u59cb\u5316&#xff0c;\u7136\u540e\u521b\u5efa_thread_count\u6570\u76ee\u7684\u7ebf\u7a0b\u4ee5\u53ca\u7ebf\u7a0b\u5bf9\u5e94\u7684EventLoop<\/p>\n<p> \u63a5\u4e0b\u6765\u662fNextLoop\u51fd\u6570&#xff0c;\u8fd9\u4e2a\u4f7f\u7528\u4e86\u8f6e\u8be2\u7684\u65b9\u5f0f\u6765\u5206\u914d\u4efb\u52a1<\/p>\n<p> EventLoop *NextLoop()<br \/>\n{<br \/>\n    if (_thread_count &#061;&#061; 0)<br \/>\n    {<br \/>\n        return _baseloop;<br \/>\n    }<br \/>\n    _next_idx &#061; (_next_idx &#043; 1) % _thread_count;<br \/>\n    return _loops[_next_idx];<br \/>\n} <\/p>\n<p>\u5982\u679c\u53ef\u7528\u7684\u5de5\u4f5c\u7ebf\u7a0b\u6570\u76ee\u4e3a0&#xff0c;\u90a3\u4e48\u8fd4\u56de_baseloop&#xff0c;\u5373\u57fa\u7840\u7684\u4e8b\u4ef6\u5faa\u73af\u3002\u901a\u8fc7\u6a21\u8fd0\u7b97\u66f4\u65b0_next_idx\u5b9e\u73b0\u8f6e\u8be2\u9009\u62e9&#xff0c;\u6700\u540e\u6839\u636e\u66f4\u65b0\u540e\u7684_next_idx\u8fd4\u56de\u76f8\u5e94\u7684\u4e8b\u4ef6\u5faa\u73af<\/p>\n<p> \u4e0b\u9762\u5c31\u662f\u8fd9\u4e2a\u7c7b\u7684\u5b8c\u6574\u4ee3\u7801<\/p>\n<p> class LoopThreadPool<br \/>\n{<br \/>\nprivate:<br \/>\n    int _thread_count;<br \/>\n    int _next_idx;<br \/>\n    EventLoop *_baseloop;<br \/>\n    std::vector&lt;LoopThread *&gt; _threads;<br \/>\n    std::vector&lt;EventLoop *&gt; _loops;<\/p>\n<p>public:<br \/>\n    LoopThreadPool(EventLoop *baseloop)<br \/>\n        : _thread_count(0),<br \/>\n          _next_idx(0),<br \/>\n          _baseloop(baseloop)<br \/>\n    {<br \/>\n    }<br \/>\n    void SetThreadCount(int count)<br \/>\n    {<br \/>\n        _thread_count &#061; count;<br \/>\n    }<br \/>\n    void Create()<br \/>\n    {<br \/>\n        if (_thread_count &gt; 0)<br \/>\n        {<br \/>\n            _threads.resize(_thread_count);<br \/>\n            _loops.resize(_thread_count);<br \/>\n            for (int i &#061; 0; i &lt; _thread_count; i&#043;&#043;)<br \/>\n            {<br \/>\n                _threads[i] &#061; new LoopThread();<br \/>\n                _loops[i] &#061; _threads[i]-&gt;GetLoop();<br \/>\n            }<br \/>\n        }<br \/>\n        return;<br \/>\n    }<br \/>\n    EventLoop *NextLoop()<br \/>\n    {<br \/>\n        if (_thread_count &#061;&#061; 0)<br \/>\n        {<br \/>\n            return _baseloop;<br \/>\n        }<br \/>\n        _next_idx &#061; (_next_idx &#043; 1) % _thread_count;<br \/>\n        return _loops[_next_idx];<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"%C2%A02.10%20Any%E7%B1%BB%E4%BB%A3%E7%A0%81%E7%9A%84%E5%AE%9E%E7%8E%B0\">\u00a02.10 Any\u7c7b\u4ee3\u7801\u7684\u5b9e\u73b0<\/h3>\n<p>\u524d\u9762\u7684\u51c6\u5907\u77e5\u8bc6\u4e2d\u5df2\u7ecf\u8be6\u7ec6\u89e3\u91ca\u4e86Any\u7c7b\u7684\u5177\u4f53\u5b9e\u73b0&#xff0c;\u90a3\u4e48\u8fd9\u91cc\u76f4\u63a5\u7ed9\u51fa\u4ee3\u7801<\/p>\n<p>class Any<br \/>\n{<br \/>\nprivate:<br \/>\n    class holder<br \/>\n    {<br \/>\n    public:<br \/>\n        virtual ~holder()<br \/>\n        {<br \/>\n        }<br \/>\n        \/\/ \u6570\u636e\u7c7b\u578b<br \/>\n        virtual const std::type_info &amp;type() &#061; 0;<br \/>\n        \/\/ \u514b\u9686\u51fa\u65b0\u7684\u5bf9\u8c61<br \/>\n        virtual holder *clone() &#061; 0;<br \/>\n    };<br \/>\n    template &lt;class T&gt;<br \/>\n    class placeholder : public holder<br \/>\n    {<br \/>\n    public:<br \/>\n        placeholder(const T &amp;val) : _val(val) {}<br \/>\n        \/\/ \u83b7\u53d6\u5b50\u7c7b\u5bf9\u8c61\u4fdd\u5b58\u7684\u6570\u636e\u7c7b\u578b<br \/>\n        virtual const std::type_info &amp;type()<br \/>\n        {<br \/>\n            return typeid(T);<br \/>\n        }<br \/>\n        \/\/ \u9488\u5bf9\u51fa\u5f53\u524d\u7684\u5bf9\u8c61\u81ea\u8eab&#xff0c;\u514b\u9686\u51fa\u4e00\u4e2a\u65b0\u7684\u5bf9\u8c61<br \/>\n        virtual holder *clone()<br \/>\n        {<br \/>\n            return new placeholder(_val);<br \/>\n        }<\/p>\n<p>    public:<br \/>\n        T _val;<br \/>\n    };<br \/>\n    holder *_content;<\/p>\n<p>public:<br \/>\n    Any() : _content(NULL) {}<br \/>\n    template &lt;class T&gt;<br \/>\n    Any(const T &amp;val) : _content(new placeholder&lt;T&gt;(val)) {}<br \/>\n    Any(const Any &amp;other) : _content(other._content ? other._content-&gt;clone() : NULL) {}<br \/>\n    ~Any() { delete _content; }<\/p>\n<p>    Any &amp;swap(Any &amp;other)<br \/>\n    {<br \/>\n        std::swap(_content, other._content);<br \/>\n        return *this;<br \/>\n    }<\/p>\n<p>    template &lt;class T&gt;<br \/>\n    \/\/ \u8fd4\u56de\u5b50\u7c7b\u5bf9\u8c61\u4fdd\u5b58\u7684\u6570\u636e\u7684\u6307\u9488<br \/>\n    T *get()<br \/>\n    {<br \/>\n        \/\/ \u60f3\u8981\u83b7\u53d6\u7684\u6570\u636e\u7c7b\u578b&#xff0c;\u5fc5\u987b\u548c\u4fdd\u5b58\u7684\u6570\u636e\u7c7b\u578b\u4e00\u81f4<br \/>\n        \/\/ if(typeid(T) !&#061; _content-&gt;type()) return NULL;<br \/>\n        assert(typeid(T) &#061;&#061; _content-&gt;type());<br \/>\n        return &amp;((placeholder&lt;T&gt; *)_content)-&gt;_val;<br \/>\n    }<br \/>\n    \/\/ \u8d4b\u503c\u8fd0\u7b97\u7b26\u91cd\u8f7d\u51fd\u6570<br \/>\n    template &lt;class T&gt;<br \/>\n    Any &amp;operator&#061;(const T &amp;val)<br \/>\n    {<br \/>\n        \/\/ \u4e3aval\u6784\u9020\u4e00\u4e2a\u4e34\u65f6\u7684\u901a\u7528\u5bb9\u5668&#xff0c;\u7136\u540e\u4e0e\u5f53\u524d\u5bb9\u5668\u81ea\u8eab\u8fdb\u884c\u6307\u9488\u4ea4\u6362<br \/>\n        \/\/ \u4e34\u65f6\u5bf9\u8c61\u91ca\u653e\u7684\u65f6\u5019&#xff0c;\u539f\u5148\u4fdd\u5b58\u7684\u6570\u636e\u4e5f\u5c31\u88ab\u91ca\u653e\u4e86<br \/>\n        Any(val).swap(*this);<br \/>\n        return *this;<br \/>\n    }<br \/>\n    Any &amp;operator&#061;(const Any &amp;other)<br \/>\n    {<br \/>\n        Any(other).swap(*this);<br \/>\n        return *this;<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"2.11%20%E9%80%9A%E4%BF%A1%E8%BF%9E%E6%8E%A5%E7%AE%A1%E7%90%86Connection%E7%B1%BB%E5%AE%9E%E7%8E%B0\" style=\"background-color:transparent\">2.11 \u901a\u4fe1\u8fde\u63a5\u7ba1\u7406Connection\u7c7b\u5b9e\u73b0<\/h3>\n<p>Connection\u6a21\u5757\u65f6\u5bf9Buffer\u6a21\u5757&#xff0c;Socket\u6a21\u5757Channel\u6a21\u5757\u7684\u4e00\u4e2a\u6574\u4f53\u5c01\u88c5&#xff0c;\u5b9e\u73b0\u4e86\u5bf9\u4e00\u4e2a\u5957\u63a5\u901a\u4fe1\u5b57\u6574\u4f53\u7684\u7ba1\u7406&#xff0c;\u6bcf\u4e00\u4e2a\u8fdb\u884c\u6570\u636e\u901a\u4fe1\u7684\u5957\u63a5\u5b57&#xff08;\u4e5f\u5c31\u662faccept\u83b7\u53d6\u5230\u7684\u65b0\u94fe\u63a5&#xff09;\u90fd\u4f1a\u4f7f\u7528Connecition\u8fdb\u884c\u7ba1\u7406\u3002<\/p>\n<p>\u9996\u5148&#xff0c;\u8fde\u63a5Connection\u7684\u72b6\u6001\u80af\u5b9a\u6709\u591a\u79cd&#xff0c;\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528enum\u6765\u7ba1\u7406\u8fde\u63a5\u7684\u72b6\u6001<\/p>\n<p> typedef enum<br \/>\n{<br \/>\n    DISCONNECTED, \/\/ \u8fde\u63a5\u5173\u95ed\u72b6\u6001<br \/>\n    CONNECTING,   \/\/ \u8fde\u63a5\u5efa\u7acb\u6210\u529f\u5f85\u5904\u7406\u72b6\u6001<br \/>\n    CONNECTED,    \/\/ \u8fde\u63a5\u5efa\u7acb\u5b8c\u6210&#xff0c;\u5404\u79cd\u8bbe\u7f6e\u5df2\u5b8c\u6210\u53ef\u4ee5\u901a\u4fe1\u7684\u72b6\u6001<br \/>\n    DISCONNECTING \/\/ \u5f85\u5173\u95ed\u72b6\u6001<br \/>\n} ConnStatu;<\/p>\n<p>\u63a5\u4e0b\u6765\u4ecb\u7ecd\u4e00\u4e0bConnection\u4e3b\u9898\u7684\u8bbe\u8ba1<\/p>\n<p>\u8fd9\u91cc\u4ecb\u7ecd\u4e00\u4e0bshared_from_this&#xff0c;\u4ed6\u662fC&#043;&#043;\u6807\u51c6\u5e93\u7684\u4e00\u4e2a\u673a\u5236&#xff0c;\u5b9a\u4e49\u5728&lt;memory&gt;\u5934\u6587\u4ef6\u4e2d&#xff0c;\u901a\u8fc7std::enable_shared_fron_this\u6a21\u7248\u7c7b\u63d0\u4f9b\u3002\u5b83\u5141\u8bb8\u4e00\u4e2a\u5bf9\u8c61\u5b89\u5168\u5730\u751f\u6210\u6307\u5411\u81ea\u8eab\u7684shared_ptr&#xff0c;\u800c\u4e0d\u4f1a\u521b\u5efa\u989d\u5916\u7684\u63a7\u5236\u5757<\/p>\n<p>shared_fron_this\u89e3\u51b3\u4e86\u4ee5\u4e0b\u95ee\u9898<\/p>\n<li>\u907f\u514d\u591a\u63a7\u5236\u5757&#xff1a;\u786e\u4fdd\u6240\u6709shared_ptr\u5171\u4eab\u540c\u4e00\u4e2a\u63a7\u5236\u5757<\/li>\n<li>\u9632\u6b62\u53cc\u91cd\u91ca\u653e&#xff1a;\u6d88\u9664\u56e0\u591a\u4e2a\u63a7\u5236\u5757\u5bfc\u81f4\u7684\u91cd\u590d\u6790\u6784<\/li>\n<li>\u5b89\u5168\u81ea\u5f15\u7528&#xff1a;\u4f7f\u5bf9\u8c61\u80fd\u5b89\u5168\u5730\u53c2\u4e0e\u56de\u8c03\u7b49\u9700\u8981\u5ef6\u957f\u751f\u547d\u5468\u671f\u7684\u573a\u666f<\/li>\n<p>\u6240\u4ee5&#xff0c;\u4e3a\u4e86\u5b89\u5168\u5730\u751f\u6210\u6307\u5411\u81ea\u8eab\u7684shared_ptr&#xff0c;\u6211\u4eec\u8ba9Connection\u7ee7\u627fenable_shared_from_this&lt;Connection&gt;<\/p>\n<p> \u4e0b\u9762\u4ecb\u7ecd\u4e00\u4e0b\u8fd9\u4e2a\u7c7b\u7684\u79c1\u6709\u6210\u5458<\/p>\n<p> uint64_t _conn_id; \/\/ \u8fde\u63a5\u552f\u4e00ID&#xff0c;\u4fbf\u4e8e\u8fde\u63a5\u7684\u7ba1\u7406\u548c\u67e5\u627e<br \/>\n\/\/ uint64_t _timer_id; \/\/\u5b9a\u65f6\u5668ID&#xff0c;\u5fc5\u987b\u662f\u552f\u4e00\u7684&#xff0c;\u4e3a\u4e86\u7b80\u5316\u64cd\u4f5c\u4f7f\u7528conn_id\u4f5c\u4e3a\u5b9a\u65f6\u5668ID<br \/>\nint _sockfd;                   \/\/ \u8fde\u63a5\u5173\u8054\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26<br \/>\nbool _enable_inactive_release; \/\/ \u8fde\u63a5\u662f\u5426\u542f\u52a8\u975e\u6d3b\u8dc3\u9500\u6bc1&#xff0c;\u9ed8\u8ba4\u662ffalse<br \/>\nEventLoop *_loop;              \/\/ \u8fde\u63a5\u6240\u5173\u8054\u7684\u4e00\u4e2aloop<br \/>\nConnStatu _statu;              \/\/ \u8fde\u63a5\u72b6\u6001<br \/>\nSocket _socket;                \/\/ \u5957\u63a5\u5b57\u8fde\u63a5\u7ba1\u7406<br \/>\nChannel _channel;              \/\/ \u8fde\u63a5\u7684\u4e8b\u4ef6\u7ba1\u7406<br \/>\nBuffer _in_buffer;             \/\/ \u8f93\u5165\u7f13\u51b2\u533a&#8212;\u5b58\u653e\u4ecesocket\u4e2d\u8bfb\u53d6\u5230\u7684\u6570\u636e<br \/>\nBuffer _out_buffer;            \/\/ \u8f93\u51fa\u7f13\u51b2\u533a&#8212;\u5b58\u653e\u8981\u53d1\u9001\u7ed9\u5bf9\u7aef\u7684\u6570\u636e<br \/>\nAny _context;                  \/\/ \u8bf7\u6c42\u7684\u5904\u7406\u63a5\u6536\u5904\u7406\u4e0a\u4e0b\u6587<br \/>\n\/\/ \u5bf9\u5916\u64cd\u4f5c\u4f7f\u7528\u667a\u80fd\u6307\u9488<br \/>\n\/\/ \u8fd9\u56db\u4e2a\u56de\u8c03\u51fd\u6570&#xff0c;\u662f\u8ba9\u670d\u52a1\u5668\u6a21\u5757\u6765\u8bbe\u7f6e\u7684(\u5176\u5b9e\u670d\u52a1\u5668\u6a21\u5757\u7684\u5904\u7406\u56de\u8c03\u4e5f\u662f\u7ec4\u4ef6\u4f7f\u7528\u8005\u8bbe\u7f6e\u7684)<br \/>\n\/**\/<br \/>\nusing ConnectedCallback &#061; std::function&lt;void(const PtrConnection &amp;)&gt;;<br \/>\nusing MessageCallback &#061; std::function&lt;void(const PtrConnection &amp;, Buffer *)&gt;;<br \/>\nusing ClosedCallback &#061; std::function&lt;void(const PtrConnection &amp;)&gt;;<br \/>\nusing AnyEventCallback &#061; std::function&lt;void(const PtrConnection &amp;)&gt;;<br \/>\nConnectedCallback _connected_callback;<br \/>\nMessageCallback _message_callback;<br \/>\nClosedCallback _closed_callback;<br \/>\nAnyEventCallback _event_callback;<br \/>\n\/*\u7ec4\u4ef6\u5185\u7684\u8fde\u63a5\u5173\u95ed\u56de\u8c03&#8211;\u7ec4\u4ef6\u5185\u8bbe\u7f6e\u7684&#xff0c;\u56e0\u4e3a\u670d\u52a1\u5668\u7ec4\u4ef6\u5185\u4f1a\u628a\u6240\u6709\u7684\u94fe\u63a5\u7ba1\u7406\u8d77\u6765&#xff0c;\u4e00\u65e6\u67d0\u4e2a\u8fde\u63a5\u8981\u5173\u95ed*\/<br \/>\n\/*\u5c31\u5e94\u8be5\u4ece\u7ba1\u7406\u7684\u5730\u65b9\u79fb\u9664\u6389\u81ea\u5df1\u7684\u4fe1\u606f*\/<br \/>\nClosedCallback _server_closed_callback; <\/p>\n<p>\u7136\u540e\u5c31\u662f\u5173\u4e8e\u6210\u5458\u51fd\u6570\u7684\u4ecb\u7ecd<\/p>\n<p>\u9996\u5148\u662f\u5bf9\u63cf\u8ff0\u7b26\u53ef\u8bfb\u4e8b\u4ef6\u89e6\u53d1\u540e\u8c03\u7528\u7684\u51fd\u6570&#xff0c;\u63a5\u6536socket\u6570\u636e\u653e\u5230\u63a5\u6536\u7f13\u51b2\u533a\u4e2d&#xff0c;\u7136\u540e\u8c03\u7528_message_callback<\/p>\n<p> void HandleRead()<br \/>\n{<br \/>\n    \/*\u63a5\u6536socket\u7684\u6570\u636e&#xff0c;\u653e\u5230\u7f13\u51b2\u533a*\/<br \/>\n    char buf[65536];<br \/>\n    ssize_t ret &#061; _socket.NonBlockRecv(buf, 65535);<br \/>\n    if (ret &lt; 0)<br \/>\n    {<br \/>\n        \/*\u51fa\u9519\u4e86&#xff0c;\u4e0d\u80fd\u76f4\u63a5\u5173\u95ed\u8fde\u63a5&#xff0c;\u8981\u770b\u63a5\u53d7\u7f13\u51b2\u533a\u548c\u53d1\u9001\u7f13\u51b2\u533a\u4e2d\u8fd8\u6709\u6ca1\u6709\u6570\u636e*\/<br \/>\n        return ShutDownInLoop();<br \/>\n    }<br \/>\n    \/\/ else if(ret &#061;&#061; 0)<br \/>\n    \/\/ {<br \/>\n    \/\/     \/\/\u8fd9\u91cc\u76840\u8868\u793a\u6ca1\u6709\u8bfb\u53d6\u5230\u6570\u636e&#xff0c;\u800c\u4e0d\u662f\u8fde\u63a5\u65ad\u5f00\u4e86&#xff0c;\u8fde\u63a5\u65ad\u5f00\u8fd4\u56de\u7684\u662f-1<br \/>\n    \/\/     return;<br \/>\n    \/\/ }<br \/>\n    \/\/ \u5c06\u6570\u636e\u653e\u5165\u5230\u8f93\u5165\u7f13\u51b2\u533a,\u5e76\u4e14\u79fb\u52a8\u5199\u504f\u79fb<br \/>\n    _in_buffer.WriteAndPush(buf, ret);<br \/>\n    \/*\u8c03\u7528_message_callback\u8fdb\u884c\u4e1a\u52a1\u5904\u7406*\/<br \/>\n    if (_in_buffer.ReadAbleSize() &gt; 0)<br \/>\n    {<br \/>\n        \/\/ shared_fron_this\u4ece\u5f53\u524d\u5bf9\u8c61\u81ea\u8eab\u83b7\u53d6\u5230<br \/>\n        return _message_callback(shared_from_this(), &amp;_in_buffer);<br \/>\n    }<br \/>\n} <\/p>\n<p>\u5904\u7406\u5199\u4e8b\u4ef6\u7684\u51fd\u6570\u903b\u8f91\u4e0e\u4e0a\u9762\u5dee\u4e0d\u591a<\/p>\n<p> void HandleWrite() \/\/ \u63cf\u8ff0\u7b26\u53ef\u5199\u4e8b\u4ef6\u89e6\u53d1\u540e\u8c03\u7528\u7684\u51fd\u6570&#xff0c;\u5c06\u53d1\u9001\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u8fdb\u884c\u53d1\u9001<br \/>\n{<br \/>\n    \/\/_out_buffer\u4e2d\u4fdd\u5b58\u7684\u6570\u636e\u5c31\u662f\u8981\u53d1\u9001\u7684\u6570\u636e<br \/>\n    ssize_t ret &#061; _socket.NonBlockSend(_out_buffer.ReadPosition(), _out_buffer.ReadAbleSize());<br \/>\n    if (ret &lt; 0)<br \/>\n    {<br \/>\n        \/\/ \u53d1\u9001\u9519\u8bef\u5c31\u8be5\u5173\u95ed\u8fde\u63a5\u4e86<br \/>\n        if (_in_buffer.ReadAbleSize() &gt; 0)<br \/>\n        {<br \/>\n            _message_callback(shared_from_this(), &amp;_in_buffer);<br \/>\n        }<br \/>\n        return Release(); \/\/ \u8fd9\u65f6\u5019\u5c31\u662f\u5b9e\u9645\u7684\u5173\u95ed\u91ca\u653e\u64cd\u4f5c<br \/>\n    }<br \/>\n    _out_buffer.MoveReadOffset(ret);<br \/>\n    if (_out_buffer.ReadAbleSize() &#061;&#061; 0)<br \/>\n    {<br \/>\n        _channel.DisableWrite(); \/\/ \u6ca1\u6709\u6570\u636e\u5f85\u53d1\u9001\u4e86&#xff0c;\u5173\u95ed\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n        \/\/ \u5982\u679c\u8fde\u63a5\u65f6\u5f85\u5173\u95ed\u72b6\u6001&#xff0c;\u5219\u6709\u6570\u636e&#xff0c;\u53d1\u9001\u5b8c\u6570\u636e\u91ca\u653e\u8fde\u63a5&#xff0c;\u6ca1\u6709\u6570\u636e\u5219\u76f4\u63a5\u91ca\u653e<br \/>\n        if (_statu &#061;&#061; DISCONNECTING)<br \/>\n        {<br \/>\n            return Release();<br \/>\n        }<br \/>\n    }<br \/>\n    return;<br \/>\n} <\/p>\n<p>\u7136\u540e\u5c31\u662f\u63cf\u8ff0\u7b26\u89e6\u53d1\u6302\u65ad\u4e8b\u4ef6\u548c\u51fa\u9519\u4e8b\u4ef6<\/p>\n<p> void HandleClose() \/\/ \u63cf\u8ff0\u7b26\u89e6\u53d1\u6302\u65ad\u4e8b\u4ef6<br \/>\n{<br \/>\n    \/\/ \u4e00\u65e6\u8fde\u63a5\u6302\u65ad\u4e86&#xff0c;\u5957\u63a5\u5b57\u5c31\u4ec0\u4e48\u90fd\u5e72\u4e0d\u4e86&#xff0c;\u56e0\u6b64\u6709\u6570\u636e\u5c31\u5904\u7406\u4e00\u4e0b&#xff0c;\u5b8c\u6bd5\u5173\u95ed\u8fde\u63a5<br \/>\n    if (_in_buffer.ReadAbleSize() &gt; 0)<br \/>\n    {<br \/>\n        _message_callback(shared_from_this(), &amp;_in_buffer);<br \/>\n    }<br \/>\n    return Release();<br \/>\n}<br \/>\nvoid HandleError() \/\/ \u63cf\u8ff0\u7b26\u89e6\u53d1\u51fa\u9519\u4e8b\u4ef6<br \/>\n{<br \/>\n    HandleClose();<br \/>\n} <\/p>\n<p>\u5f53\u63cf\u8ff0\u7b26\u89e6\u53d1\u4efb\u4e00\u4e8b\u4ef6\u65f6&#xff0c;\u6211\u4eec\u9700\u8981\u5237\u65b0\u8fde\u63a5\u7684\u6d3b\u8dc3\u5ea6<\/p>\n<p> void HandleEvent() \/\/ \u63cf\u8ff0\u7b26\u89e6\u53d1\u4efb\u4e00\u4e8b\u4ef6<br \/>\n{<br \/>\n    \/\/ \u5237\u65b0\u94fe\u63a5\u7684\u6d3b\u8dc3\u5ea6 &#043; \u8c03\u7528\u7ec4\u4ef6\u4f7f\u7528\u8005\u7684\u4efb\u610f\u4e8b\u4ef6\u56de\u8c03<br \/>\n    if (_enable_inactive_release &#061;&#061; true)<br \/>\n    {<br \/>\n        _loop-&gt;TimerRefresh(_conn_id);<br \/>\n    }<br \/>\n    if (_event_callback)<br \/>\n    {<br \/>\n        _event_callback(shared_from_this());<br \/>\n    }<br \/>\n} <\/p>\n<p>\u4e0b\u4e2a\u51fd\u6570\u4f1a\u628a\u8fde\u63a5\u72b6\u6001\u4ece\u534a\u8fde\u63a5\u4fee\u6539\u4e3a\u8fde\u63a5\u72b6\u6001&#xff0c;\u5e76\u4e14\u4f1a\u542f\u52a8\u8bfb\u4e8b\u4ef6\u76d1\u63a7<\/p>\n<p> void EstablishedInLoop() \/\/ \u8fde\u63a5\u83b7\u53d6\u4e4b\u540e&#xff0c;\u6240\u5904\u7684\u72b6\u6001\u4e0b\u8981\u8fdb\u884c\u7684\u5404\u79cd\u8bbe\u7f6e(\u7ed9Channel\u8bbe\u7f6e\u65f6\u95f4\u56de\u8c03&#xff0c;\u542f\u52a8\u8bfb\u76d1\u63a7)<br \/>\n{<br \/>\n    \/\/ \u4fee\u6539\u8fde\u63a5\u72b6\u6001 &#043; \u542f\u52a8\u8bfb\u4e8b\u4ef6\u76d1\u63a7 &#043; \u8c03\u7528\u56de\u8c03\u51fd\u6570<br \/>\n    assert(_statu &#061;&#061; CONNECTING); \/\/ \u5f53\u524d\u7684\u72b6\u6001\u5fc5\u987b\u4e00\u5b9a\u662f\u4e0a\u5c42\u7684\u534a\u8fde\u63a5\u72b6\u6001<br \/>\n    _statu &#061; CONNECTED;           \/\/ \u5f53\u524d\u51fd\u6570\u6267\u884c\u5b8c\u6bd5&#xff0c;\u5219\u8fde\u63a5\u8fdb\u5165\u5df2\u5b8c\u6210\u8fde\u63a5\u72b6\u6001<br \/>\n    \/\/ \u4e00\u65e6\u542f\u52a8\u8bfb\u4e8b\u4ef6\u76d1\u63a7\u5c31\u6709\u53ef\u80fd\u4f1a\u7acb\u5373\u89e6\u53d1\u8bfb\u4e8b\u4ef6&#xff0c;\u5982\u679c\u8fd9\u65f6\u5019\u542f\u52a8\u4e86\u975e\u6d3b\u8dc3\u94fe\u63a5\u9500\u6bc1<br \/>\n    _channel.EnableRead();<br \/>\n    if (_connected_callback)<br \/>\n        _connected_callback(shared_from_this());<br \/>\n} <\/p>\n<p>\u5bf9\u8fde\u63a5\u8fdb\u884c\u91ca\u653e\u7684\u51fd\u6570ReleaseInLoop()<\/p>\n<p> void ReleaseInLoop() \/\/ \u8fd9\u4e2a\u63a5\u53e3\u624d\u662f\u5b9e\u9645\u7684\u91ca\u653e\u63a5\u53e3<br \/>\n{<br \/>\n    \/\/ \u4fee\u6539\u8fde\u63a5\u72b6\u6001&#xff0c;\u8bbe\u7f6e\u4e3aDISCONNECTED<br \/>\n    _statu &#061; DISCONNECTED;<br \/>\n    \/\/ \u79fb\u9664\u8fde\u63a5\u7684\u4e8b\u4ef6\u76d1\u63a7<br \/>\n    _channel.Remove();<br \/>\n    \/\/ \u5173\u95ed\u63cf\u8ff0\u7b26<br \/>\n    _socket.Close();<br \/>\n    \/\/ \u5982\u679c\u5f53\u524d\u5b9a\u65f6\u5668\u961f\u5217\u4e2d\u8fd8\u6709\u5b9a\u65f6\u9500\u6bc1\u4efb\u52a1&#xff0c;\u5219\u53d6\u6d88\u4efb\u52a1&#xff0c;\u907f\u514d\u91ce\u6307\u9488\u64cd\u4f5c<br \/>\n    if (_loop-&gt;HasTimer(_conn_id))<br \/>\n        CancelInactiveReleaseInLoop();<br \/>\n    \/\/ \u8c03\u7528\u5173\u95ed\u56de\u8c03\u51fd\u6570&#xff0c;\u907f\u514d\u56e0\u4e3a\u5148\u79fb\u9664\u670d\u52a1\u5668\u7ba1\u7406\u7684\u8fde\u63a5\u4fe1\u606f\u5bfc\u81f4Connection\u88ab\u91ca\u653e&#xff0c;\u518d\u53bb\u5904\u7406\u5c31\u4f1a\u51fa\u9519&#xff0c;\u56e0\u6b64\u5148\u8c03\u7528\u7528\u6237<br \/>\n    if (_closed_callback)<br \/>\n        _closed_callback(shared_from_this());<br \/>\n    \/\/ \u79fb\u9664\u670d\u52a1\u5668\u5185\u90e8\u7ba1\u7406\u7684\u8fde\u63a5\u4fe1\u606f<br \/>\n    if (_server_closed_callback)<br \/>\n        _server_closed_callback(shared_from_this());<br \/>\n} <\/p>\n<p>\u628a\u6570\u636e\u653e\u5165\u5230\u53d1\u9001\u7f13\u51b2\u533a&#xff0c;\u542f\u52a8\u53ef\u5199\u4e8b\u4ef6\u76d1\u63a7<\/p>\n<p> void SendInLoop(Buffer &amp;buf)<br \/>\n{<br \/>\n    if (_statu &#061;&#061; DISCONNECTED)<br \/>\n        return;<br \/>\n    _out_buffer.WriteBufferAndPush(buf);<br \/>\n    if (_channel.WriteAble() &#061;&#061; false)<br \/>\n    {<br \/>\n        _channel.EnableWrite();<br \/>\n    }<br \/>\n} <\/p>\n<p>\u8fd9\u4e2a\u5173\u95ed\u64cd\u4f5c\u5e76\u975e\u5b9e\u9645\u7684\u8fde\u63a5\u91ca\u653e\u64cd\u4f5c&#xff0c;\u9700\u8981\u5224\u65ad\u8fd8\u6709\u6ca1\u6709\u6570\u636e\u5f85\u5904\u7406&#xff0c;\u5f85\u53d1\u9001<\/p>\n<p> void ShutDownInLoop()<br \/>\n{<br \/>\n    _statu &#061; DISCONNECTED; \/\/ \u8bbe\u7f6e\u8fde\u63a5\u4e3a\u534a\u5173\u95ed\u72b6\u6001<br \/>\n    if (_in_buffer.ReadAbleSize() &gt; 0)<br \/>\n    {<br \/>\n        if (_message_callback)<br \/>\n            _message_callback(shared_from_this(), &amp;_in_buffer);<br \/>\n    }<br \/>\n    \/\/ \u8981\u4e48\u5c31\u662f\u5199\u5165\u6570\u636e\u7684\u65f6\u5019\u51fa\u9519\u5173\u95ed&#xff0c;\u8981\u4e48\u5c31\u662f\u6ca1\u6709\u5f85\u53d1\u9001\u6570\u636e&#xff0c;\u76f4\u63a5\u5173\u95ed<br \/>\n    if (_out_buffer.ReadAbleSize() &gt; 0)<br \/>\n    {<br \/>\n        if (_channel.WriteAble() &#061;&#061; false) \/\/ \u662f\u5426\u542f\u52a8\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n        {<br \/>\n            _channel.EnableWrite();<br \/>\n        }<br \/>\n    }<br \/>\n    \/\/ \u6ca1\u6709\u6570\u636e\u4e86<br \/>\n    if (_out_buffer.ReadAbleSize() &#061;&#061; 0)<br \/>\n    {<br \/>\n        Release();<br \/>\n    }<br \/>\n} <\/p>\n<p>\u542f\u52a8\u975e\u6d3b\u8dc3\u94fe\u63a5\u8d85\u65f6\u91ca\u653e&#xff0c;\u4e0d\u5b58\u5728\u8fd9\u4e2a\u9500\u6bc1\u4efb\u52a1\u5c31\u65b0\u589e&#xff0c;\u5df2\u7ecf\u5b58\u5728\u5219\u5237\u65b0\u5b9a\u65f6\u5668<\/p>\n<p> void EnableInactiveReleaseInLoop(int sec)<br \/>\n{<br \/>\n    \/\/ \u5c06\u5224\u65ad\u6807\u5fd7_enable_inactive_release \u7f6e\u4e3atrue<br \/>\n    _enable_inactive_release &#061; true;<br \/>\n    \/\/ \u5982\u679c\u5f53\u524d\u5b9a\u65f6\u9500\u6bc1\u4efb\u52a1\u5df2\u7ecf\u5b58\u5728&#xff0c;\u90a3\u5c31\u5237\u65b0\u5ef6\u8fdf\u4e00\u4e0b\u5373\u53ef<br \/>\n    if (_loop-&gt;HasTimer(_conn_id))<br \/>\n    {<br \/>\n        return _loop-&gt;TimerRefresh(_conn_id);<br \/>\n    }<br \/>\n    \/\/ \u5982\u679c\u4e0d\u5b58\u5728\u5b9a\u65f6\u9500\u6bc1\u4efb\u52a1&#xff0c;\u5219\u65b0\u589e<br \/>\n    _loop-&gt;TimerAdd(_conn_id, sec, std::bind(&amp;Connection::Release, this));<br \/>\n} <\/p>\n<p>\u53d6\u6d88\u975e\u6d3b\u8dc3\u8fde\u63a5\u91ca\u653e<\/p>\n<p> void CancelInactiveReleaseInLoop()<br \/>\n{<br \/>\n    _enable_inactive_release &#061; false;<br \/>\n    if (_loop-&gt;HasTimer(_conn_id))<br \/>\n    {<br \/>\n        _loop-&gt;TimerCancel(_conn_id);<br \/>\n    }<br \/>\n} <\/p>\n<p>\u5207\u6362\u534f\u8bae&#xff0c;\u91cd\u7f6e\u4e0a\u4e0b\u6587\u4ee5\u53ca\u9636\u6bb5\u6027\u5904\u7406\u51fd\u6570<\/p>\n<p> void UpgradeInLoop(const Any &amp;context, const ConnectedCallback &amp;conn, const MessageCallback &amp;msg,<br \/>\n                    const ClosedCallback &amp;closed, const AnyEventCallback &amp;event)<br \/>\n{<br \/>\n    _context &#061; context;<br \/>\n    _connected_callback &#061; conn;<br \/>\n    _message_callback &#061; msg;<br \/>\n    _closed_callback &#061; closed;<br \/>\n    _event_callback &#061; event;<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662fConnection\u7c7b\u7684\u5b8c\u6574\u4ee3\u7801<\/p>\n<p> typedef enum<br \/>\n{<br \/>\n    DISCONNECTED, \/\/ \u8fde\u63a5\u5173\u95ed\u72b6\u6001<br \/>\n    CONNECTING,   \/\/ \u8fde\u63a5\u5efa\u7acb\u6210\u529f\u5f85\u5904\u7406\u72b6\u6001<br \/>\n    CONNECTED,    \/\/ \u8fde\u63a5\u5efa\u7acb\u5b8c\u6210&#xff0c;\u5404\u79cd\u8bbe\u7f6e\u5df2\u5b8c\u6210\u53ef\u4ee5\u901a\u4fe1\u7684\u72b6\u6001<br \/>\n    DISCONNECTING \/\/ \u5f85\u5173\u95ed\u72b6\u6001<br \/>\n} ConnStatu;<\/p>\n<p>using PtrConnection &#061; std::shared_ptr&lt;Connection&gt;;<\/p>\n<p>class Connection : public std::enable_shared_from_this&lt;Connection&gt;<br \/>\n{<br \/>\nprivate:<br \/>\n    uint64_t _conn_id; \/\/ \u8fde\u63a5\u552f\u4e00ID&#xff0c;\u4fbf\u4e8e\u8fde\u63a5\u7684\u7ba1\u7406\u548c\u67e5\u627e<br \/>\n    \/\/ uint64_t _timer_id; \/\/\u5b9a\u65f6\u5668ID&#xff0c;\u5fc5\u987b\u662f\u552f\u4e00\u7684&#xff0c;\u4e3a\u4e86\u7b80\u5316\u64cd\u4f5c\u4f7f\u7528conn_id\u4f5c\u4e3a\u5b9a\u65f6\u5668ID<br \/>\n    int _sockfd;                   \/\/ \u8fde\u63a5\u5173\u8054\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26<br \/>\n    bool _enable_inactive_release; \/\/ \u8fde\u63a5\u662f\u5426\u542f\u52a8\u975e\u6d3b\u8dc3\u9500\u6bc1&#xff0c;\u9ed8\u8ba4\u662ffalse<br \/>\n    EventLoop *_loop;              \/\/ \u8fde\u63a5\u6240\u5173\u8054\u7684\u4e00\u4e2aloop<br \/>\n    ConnStatu _statu;              \/\/ \u8fde\u63a5\u72b6\u6001<br \/>\n    Socket _socket;                \/\/ \u5957\u63a5\u5b57\u8fde\u63a5\u7ba1\u7406<br \/>\n    Channel _channel;              \/\/ \u8fde\u63a5\u7684\u4e8b\u4ef6\u7ba1\u7406<br \/>\n    Buffer _in_buffer;             \/\/ \u8f93\u5165\u7f13\u51b2\u533a&#8212;\u5b58\u653e\u4ecesocket\u4e2d\u8bfb\u53d6\u5230\u7684\u6570\u636e<br \/>\n    Buffer _out_buffer;            \/\/ \u8f93\u51fa\u7f13\u51b2\u533a&#8212;\u5b58\u653e\u8981\u53d1\u9001\u7ed9\u5bf9\u7aef\u7684\u6570\u636e<br \/>\n    Any _context;                  \/\/ \u8bf7\u6c42\u7684\u5904\u7406\u63a5\u6536\u5904\u7406\u4e0a\u4e0b\u6587<br \/>\n    \/\/ \u5bf9\u5916\u64cd\u4f5c\u4f7f\u7528\u667a\u80fd\u6307\u9488<br \/>\n    \/\/ \u8fd9\u56db\u4e2a\u56de\u8c03\u51fd\u6570&#xff0c;\u662f\u8ba9\u670d\u52a1\u5668\u6a21\u5757\u6765\u8bbe\u7f6e\u7684(\u5176\u5b9e\u670d\u52a1\u5668\u6a21\u5757\u7684\u5904\u7406\u56de\u8c03\u4e5f\u662f\u7ec4\u4ef6\u4f7f\u7528\u8005\u8bbe\u7f6e\u7684)<br \/>\n    \/**\/<br \/>\n    using ConnectedCallback &#061; std::function&lt;void(const PtrConnection &amp;)&gt;;<br \/>\n    using MessageCallback &#061; std::function&lt;void(const PtrConnection &amp;, Buffer *)&gt;;<br \/>\n    using ClosedCallback &#061; std::function&lt;void(const PtrConnection &amp;)&gt;;<br \/>\n    using AnyEventCallback &#061; std::function&lt;void(const PtrConnection &amp;)&gt;;<br \/>\n    ConnectedCallback _connected_callback;<br \/>\n    MessageCallback _message_callback;<br \/>\n    ClosedCallback _closed_callback;<br \/>\n    AnyEventCallback _event_callback;<br \/>\n    \/*\u7ec4\u4ef6\u5185\u7684\u8fde\u63a5\u5173\u95ed\u56de\u8c03&#8211;\u7ec4\u4ef6\u5185\u8bbe\u7f6e\u7684&#xff0c;\u56e0\u4e3a\u670d\u52a1\u5668\u7ec4\u4ef6\u5185\u4f1a\u628a\u6240\u6709\u7684\u94fe\u63a5\u7ba1\u7406\u8d77\u6765&#xff0c;\u4e00\u65e6\u67d0\u4e2a\u8fde\u63a5\u8981\u5173\u95ed*\/<br \/>\n    \/*\u5c31\u5e94\u8be5\u4ece\u7ba1\u7406\u7684\u5730\u65b9\u79fb\u9664\u6389\u81ea\u5df1\u7684\u4fe1\u606f*\/<br \/>\n    ClosedCallback _server_closed_callback;<\/p>\n<p>private:<br \/>\n    \/*\u4e94\u4e2achannel\u7684\u4e8b\u4ef6\u56de\u8c03\u51fd\u6570*\/<br \/>\n    void HandleRead() \/\/ \u63cf\u8ff0\u7b26\u53ef\u8bfb\u4e8b\u4ef6\u89e6\u53d1\u540e\u8c03\u7528\u7684\u51fd\u6570&#xff0c;\u63a5\u6536socket\u6570\u636e\u653e\u5230\u63a5\u53d7\u7f13\u51b2\u533a\u4e2d&#xff0c;\u7136\u540e\u8c03\u7528_message_callback<br \/>\n    {<br \/>\n        \/*\u63a5\u6536socket\u7684\u6570\u636e&#xff0c;\u653e\u5230\u7f13\u51b2\u533a*\/<br \/>\n        char buf[65536];<br \/>\n        ssize_t ret &#061; _socket.NonBlockRecv(buf, 65535);<br \/>\n        if (ret &lt; 0)<br \/>\n        {<br \/>\n            \/*\u51fa\u9519\u4e86&#xff0c;\u4e0d\u80fd\u76f4\u63a5\u5173\u95ed\u8fde\u63a5&#xff0c;\u8981\u770b\u63a5\u53d7\u7f13\u51b2\u533a\u548c\u53d1\u9001\u7f13\u51b2\u533a\u4e2d\u8fd8\u6709\u6ca1\u6709\u6570\u636e*\/<br \/>\n            return ShutDownInLoop();<br \/>\n        }<br \/>\n        \/\/ else if(ret &#061;&#061; 0)<br \/>\n        \/\/ {<br \/>\n        \/\/     \/\/\u8fd9\u91cc\u76840\u8868\u793a\u6ca1\u6709\u8bfb\u53d6\u5230\u6570\u636e&#xff0c;\u800c\u4e0d\u662f\u8fde\u63a5\u65ad\u5f00\u4e86&#xff0c;\u8fde\u63a5\u65ad\u5f00\u8fd4\u56de\u7684\u662f-1<br \/>\n        \/\/     return;<br \/>\n        \/\/ }<br \/>\n        \/\/ \u5c06\u6570\u636e\u653e\u5165\u5230\u8f93\u5165\u7f13\u51b2\u533a,\u5e76\u4e14\u79fb\u52a8\u5199\u504f\u79fb<br \/>\n        _in_buffer.WriteAndPush(buf, ret);<br \/>\n        \/*\u8c03\u7528_message_callback\u8fdb\u884c\u4e1a\u52a1\u5904\u7406*\/<br \/>\n        if (_in_buffer.ReadAbleSize() &gt; 0)<br \/>\n        {<br \/>\n            \/\/ shared_fron_this\u4ece\u5f53\u524d\u5bf9\u8c61\u81ea\u8eab\u83b7\u53d6\u5230<br \/>\n            return _message_callback(shared_from_this(), &amp;_in_buffer);<br \/>\n        }<br \/>\n    }<br \/>\n    void HandleWrite() \/\/ \u63cf\u8ff0\u7b26\u53ef\u5199\u4e8b\u4ef6\u89e6\u53d1\u540e\u8c03\u7528\u7684\u51fd\u6570&#xff0c;\u5c06\u53d1\u9001\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u8fdb\u884c\u53d1\u9001<br \/>\n    {<br \/>\n        \/\/_out_buffer\u4e2d\u4fdd\u5b58\u7684\u6570\u636e\u5c31\u662f\u8981\u53d1\u9001\u7684\u6570\u636e<br \/>\n        ssize_t ret &#061; _socket.NonBlockSend(_out_buffer.ReadPosition(), _out_buffer.ReadAbleSize());<br \/>\n        if (ret &lt; 0)<br \/>\n        {<br \/>\n            \/\/ \u53d1\u9001\u9519\u8bef\u5c31\u8be5\u5173\u95ed\u8fde\u63a5\u4e86<br \/>\n            if (_in_buffer.ReadAbleSize() &gt; 0)<br \/>\n            {<br \/>\n                _message_callback(shared_from_this(), &amp;_in_buffer);<br \/>\n            }<br \/>\n            return Release(); \/\/ \u8fd9\u65f6\u5019\u5c31\u662f\u5b9e\u9645\u7684\u5173\u95ed\u91ca\u653e\u64cd\u4f5c<br \/>\n        }<br \/>\n        _out_buffer.MoveReadOffset(ret);<br \/>\n        if (_out_buffer.ReadAbleSize() &#061;&#061; 0)<br \/>\n        {<br \/>\n            _channel.DisableWrite(); \/\/ \u6ca1\u6709\u6570\u636e\u5f85\u53d1\u9001\u4e86&#xff0c;\u5173\u95ed\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n            \/\/ \u5982\u679c\u8fde\u63a5\u65f6\u5f85\u5173\u95ed\u72b6\u6001&#xff0c;\u5219\u6709\u6570\u636e&#xff0c;\u53d1\u9001\u5b8c\u6570\u636e\u91ca\u653e\u8fde\u63a5&#xff0c;\u6ca1\u6709\u6570\u636e\u5219\u76f4\u63a5\u91ca\u653e<br \/>\n            if (_statu &#061;&#061; DISCONNECTING)<br \/>\n            {<br \/>\n                return Release();<br \/>\n            }<br \/>\n        }<br \/>\n        return;<br \/>\n    }<br \/>\n    void HandleClose() \/\/ \u63cf\u8ff0\u7b26\u89e6\u53d1\u6302\u65ad\u4e8b\u4ef6<br \/>\n    {<br \/>\n        \/\/ \u4e00\u65e6\u8fde\u63a5\u6302\u65ad\u4e86&#xff0c;\u5957\u63a5\u5b57\u5c31\u4ec0\u4e48\u90fd\u5e72\u4e0d\u4e86&#xff0c;\u56e0\u6b64\u6709\u6570\u636e\u5c31\u5904\u7406\u4e00\u4e0b&#xff0c;\u5b8c\u6bd5\u5173\u95ed\u8fde\u63a5<br \/>\n        if (_in_buffer.ReadAbleSize() &gt; 0)<br \/>\n        {<br \/>\n            _message_callback(shared_from_this(), &amp;_in_buffer);<br \/>\n        }<br \/>\n        return Release();<br \/>\n    }<br \/>\n    void HandleError() \/\/ \u63cf\u8ff0\u7b26\u89e6\u53d1\u51fa\u9519\u4e8b\u4ef6<br \/>\n    {<br \/>\n        HandleClose();<br \/>\n    }<br \/>\n    void HandleEvent() \/\/ \u63cf\u8ff0\u7b26\u89e6\u53d1\u4efb\u4e00\u4e8b\u4ef6<br \/>\n    {<br \/>\n        \/\/ \u5237\u65b0\u94fe\u63a5\u7684\u6d3b\u8dc3\u5ea6 &#043; \u8c03\u7528\u7ec4\u4ef6\u4f7f\u7528\u8005\u7684\u4efb\u610f\u4e8b\u4ef6\u56de\u8c03<br \/>\n        if (_enable_inactive_release &#061;&#061; true)<br \/>\n        {<br \/>\n            _loop-&gt;TimerRefresh(_conn_id);<br \/>\n        }<br \/>\n        if (_event_callback)<br \/>\n        {<br \/>\n            _event_callback(shared_from_this());<br \/>\n        }<br \/>\n    }<br \/>\nvoid EstablishedInLoop() \/\/ \u8fde\u63a5\u83b7\u53d6\u4e4b\u540e&#xff0c;\u6240\u5904\u7684\u72b6\u6001\u4e0b\u8981\u8fdb\u884c\u7684\u5404\u79cd\u8bbe\u7f6e(\u7ed9Channel\u8bbe\u7f6e\u65f6\u95f4\u56de\u8c03&#xff0c;\u542f\u52a8\u8bfb\u76d1\u63a7)<br \/>\n{<br \/>\n    \/\/ \u4fee\u6539\u8fde\u63a5\u72b6\u6001 &#043; \u542f\u52a8\u8bfb\u4e8b\u4ef6\u76d1\u63a7 &#043; \u8c03\u7528\u56de\u8c03\u51fd\u6570<br \/>\n    assert(_statu &#061;&#061; CONNECTING); \/\/ \u5f53\u524d\u7684\u72b6\u6001\u5fc5\u987b\u4e00\u5b9a\u662f\u4e0a\u5c42\u7684\u534a\u8fde\u63a5\u72b6\u6001<br \/>\n    _statu &#061; CONNECTED;           \/\/ \u5f53\u524d\u51fd\u6570\u6267\u884c\u5b8c\u6bd5&#xff0c;\u5219\u8fde\u63a5\u8fdb\u5165\u5df2\u5b8c\u6210\u8fde\u63a5\u72b6\u6001<br \/>\n    \/\/ \u4e00\u65e6\u542f\u52a8\u8bfb\u4e8b\u4ef6\u76d1\u63a7\u5c31\u6709\u53ef\u80fd\u4f1a\u7acb\u5373\u89e6\u53d1\u8bfb\u4e8b\u4ef6&#xff0c;\u5982\u679c\u8fd9\u65f6\u5019\u542f\u52a8\u4e86\u975e\u6d3b\u8dc3\u94fe\u63a5\u9500\u6bc1<br \/>\n    _channel.EnableRead();<br \/>\n    if (_connected_callback)<br \/>\n        _connected_callback(shared_from_this());<br \/>\n}<br \/>\n    void ReleaseInLoop() \/\/ \u8fd9\u4e2a\u63a5\u53e3\u624d\u662f\u5b9e\u9645\u7684\u91ca\u653e\u63a5\u53e3<br \/>\n    {<br \/>\n        \/\/ \u4fee\u6539\u8fde\u63a5\u72b6\u6001&#xff0c;\u8bbe\u7f6e\u4e3aDISCONNECTED<br \/>\n        _statu &#061; DISCONNECTED;<br \/>\n        \/\/ \u79fb\u9664\u8fde\u63a5\u7684\u4e8b\u4ef6\u76d1\u63a7<br \/>\n        _channel.Remove();<br \/>\n        \/\/ \u5173\u95ed\u63cf\u8ff0\u7b26<br \/>\n        _socket.Close();<br \/>\n        \/\/ \u5982\u679c\u5f53\u524d\u5b9a\u65f6\u5668\u961f\u5217\u4e2d\u8fd8\u6709\u5b9a\u65f6\u9500\u6bc1\u4efb\u52a1&#xff0c;\u5219\u53d6\u6d88\u4efb\u52a1&#xff0c;\u907f\u514d\u91ce\u6307\u9488\u64cd\u4f5c<br \/>\n        if (_loop-&gt;HasTimer(_conn_id))<br \/>\n            CancelInactiveReleaseInLoop();<br \/>\n        \/\/ \u8c03\u7528\u5173\u95ed\u56de\u8c03\u51fd\u6570&#xff0c;\u907f\u514d\u56e0\u4e3a\u5148\u79fb\u9664\u670d\u52a1\u5668\u7ba1\u7406\u7684\u8fde\u63a5\u4fe1\u606f\u5bfc\u81f4Connection\u88ab\u91ca\u653e&#xff0c;\u518d\u53bb\u5904\u7406\u5c31\u4f1a\u51fa\u9519&#xff0c;\u56e0\u6b64\u5148\u8c03\u7528\u7528\u6237<br \/>\n        if (_closed_callback)<br \/>\n            _closed_callback(shared_from_this());<br \/>\n        \/\/ \u79fb\u9664\u670d\u52a1\u5668\u5185\u90e8\u7ba1\u7406\u7684\u8fde\u63a5\u4fe1\u606f<br \/>\n        if (_server_closed_callback)<br \/>\n            _server_closed_callback(shared_from_this());<br \/>\n    }<\/p>\n<p>    \/\/ \u8fd9\u4e2a\u63a5\u53e3\u5e76\u4e0d\u662f\u5b9e\u9645\u7684\u53d1\u9001\u63a5\u53e3&#xff0c;\u800c\u53ea\u662f\u628a\u6570\u636e\u653e\u5230\u53d1\u9001\u7f13\u51b2\u533a&#xff0c;\u542f\u52a8\u53ef\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n    void SendInLoop(Buffer &amp;buf)<br \/>\n    {<br \/>\n        if (_statu &#061;&#061; DISCONNECTED)<br \/>\n            return;<br \/>\n        _out_buffer.WriteBufferAndPush(buf);<br \/>\n        if (_channel.WriteAble() &#061;&#061; false)<br \/>\n        {<br \/>\n            _channel.EnableWrite();<br \/>\n        }<br \/>\n    }<br \/>\n    \/\/ \u8fd9\u4e2a\u5173\u95ed\u64cd\u4f5c\u5e76\u975e\u5b9e\u9645\u7684\u8fde\u63a5\u91ca\u653e\u64cd\u4f5c&#xff0c;\u9700\u8981\u5224\u65ad\u8fd8\u6709\u6ca1\u6709\u6570\u636e\u5f85\u5904\u7406&#xff0c;\u5f85\u53d1\u9001<br \/>\n    void ShutDownInLoop()<br \/>\n    {<br \/>\n        _statu &#061; DISCONNECTED; \/\/ \u8bbe\u7f6e\u8fde\u63a5\u4e3a\u534a\u5173\u95ed\u72b6\u6001<br \/>\n        if (_in_buffer.ReadAbleSize() &gt; 0)<br \/>\n        {<br \/>\n            if (_message_callback)<br \/>\n                _message_callback(shared_from_this(), &amp;_in_buffer);<br \/>\n        }<br \/>\n        \/\/ \u8981\u4e48\u5c31\u662f\u5199\u5165\u6570\u636e\u7684\u65f6\u5019\u51fa\u9519\u5173\u95ed&#xff0c;\u8981\u4e48\u5c31\u662f\u6ca1\u6709\u5f85\u53d1\u9001\u6570\u636e&#xff0c;\u76f4\u63a5\u5173\u95ed<br \/>\n        if (_out_buffer.ReadAbleSize() &gt; 0)<br \/>\n        {<br \/>\n            if (_channel.WriteAble() &#061;&#061; false) \/\/ \u662f\u5426\u542f\u52a8\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n            {<br \/>\n                _channel.EnableWrite();<br \/>\n            }<br \/>\n        }<br \/>\n        \/\/ \u6ca1\u6709\u6570\u636e\u4e86<br \/>\n        if (_out_buffer.ReadAbleSize() &#061;&#061; 0)<br \/>\n        {<br \/>\n            Release();<br \/>\n        }<br \/>\n    }<br \/>\n    \/\/ \u542f\u52a8\u975e\u6d3b\u8dc3\u8fde\u63a5\u8d85\u65f6\u91ca\u653e\u89c4\u5219<br \/>\n    void EnableInactiveReleaseInLoop(int sec)<br \/>\n    {<br \/>\n        \/\/ \u5c06\u5224\u65ad\u6807\u5fd7_enable_inactive_release \u7f6e\u4e3atrue<br \/>\n        _enable_inactive_release &#061; true;<br \/>\n        \/\/ \u5982\u679c\u5f53\u524d\u5b9a\u65f6\u9500\u6bc1\u4efb\u52a1\u5df2\u7ecf\u5b58\u5728&#xff0c;\u90a3\u5c31\u5237\u65b0\u5ef6\u8fdf\u4e00\u4e0b\u5373\u53ef<br \/>\n        if (_loop-&gt;HasTimer(_conn_id))<br \/>\n        {<br \/>\n            return _loop-&gt;TimerRefresh(_conn_id);<br \/>\n        }<br \/>\n        \/\/ \u5982\u679c\u4e0d\u5b58\u5728\u5b9a\u65f6\u9500\u6bc1\u4efb\u52a1&#xff0c;\u5219\u65b0\u589e<br \/>\n        _loop-&gt;TimerAdd(_conn_id, sec, std::bind(&amp;Connection::Release, this));<br \/>\n    }<br \/>\n    void CancelInactiveReleaseInLoop()<br \/>\n    {<br \/>\n        _enable_inactive_release &#061; false;<br \/>\n        if (_loop-&gt;HasTimer(_conn_id))<br \/>\n        {<br \/>\n            _loop-&gt;TimerCancel(_conn_id);<br \/>\n        }<br \/>\n    }<br \/>\n    \/\/ \u5207\u6362\u534f\u8bae&#xff0c;\u91cd\u7f6e\u4e0a\u4e0b\u6587\u4ee5\u53ca\u9636\u6bb5\u6027\u5904\u7406\u51fd\u6570<br \/>\n    void UpgradeInLoop(const Any &amp;context, const ConnectedCallback &amp;conn, const MessageCallback &amp;msg,<br \/>\n                       const ClosedCallback &amp;closed, const AnyEventCallback &amp;event)<br \/>\n    {<br \/>\n        _context &#061; context;<br \/>\n        _connected_callback &#061; conn;<br \/>\n        _message_callback &#061; msg;<br \/>\n        _closed_callback &#061; closed;<br \/>\n        _event_callback &#061; event;<br \/>\n    }<\/p>\n<p>public:<br \/>\n    Connection(EventLoop *loop, uint64_t conn_id, int sockfd)<br \/>\n        : _conn_id(conn_id),<br \/>\n          _sockfd(sockfd),<br \/>\n          _enable_inactive_release(false),<br \/>\n          _loop(loop),<br \/>\n          _statu(CONNECTING),<br \/>\n          _socket(_sockfd),<br \/>\n          _channel(loop, _sockfd)<br \/>\n    {<br \/>\n        _channel.SetCloseCallback(std::bind(&amp;Connection::HandleClose, this));<br \/>\n        _channel.SetEventCallback(std::bind(&amp;Connection::HandleEvent, this));<br \/>\n        _channel.SetReadCallback(std::bind(&amp;Connection::HandleRead, this));<br \/>\n        _channel.SetWriteCallback(std::bind(&amp;Connection::HandleWrite, this));<br \/>\n        _channel.SetErrorCallback(std::bind(&amp;Connection::HandleError, this));<br \/>\n    }<br \/>\n    ~Connection()<br \/>\n    {<br \/>\n        DBG_LOG(&#034;RELEASE CONNECTION:%p&#034;, this);<br \/>\n    }<br \/>\n    int Fd() \/\/ \u83b7\u53d6\u7ba1\u7406\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26<br \/>\n    {<br \/>\n        return _sockfd;<br \/>\n    }<br \/>\n    int Id() \/\/ \u83b7\u53d6\u8fde\u63a5\u7684ID<br \/>\n    {<br \/>\n        return _conn_id;<br \/>\n    }<br \/>\n    bool Connected() \/\/ \u662f\u5426\u5904\u4e8eConnected\u72b6\u6001<br \/>\n    {<br \/>\n        return (_statu &#061;&#061; CONNECTED);<br \/>\n    }<br \/>\n    void SetContext(const Any &amp;context) \/\/ \u8bbe\u7f6e\u4e0a\u4e0b\u6587&#8211;\u8fde\u63a5\u5efa\u7acb\u5b8c\u6210\u65f6<br \/>\n    {<br \/>\n        _context &#061; context;<br \/>\n    }<br \/>\n    Any *GetContext() \/\/ \u83b7\u53d6\u4e0a\u4e0b\u6587&#xff0c;\u8fd4\u56de\u7684\u662f\u6307\u9488<br \/>\n    {<br \/>\n        return &amp;_context;<br \/>\n    }<\/p>\n<p>    void SetConnectedCallback(const ConnectedCallback &amp;cb)<br \/>\n    {<br \/>\n        _connected_callback &#061; cb;<br \/>\n    }<br \/>\n    void SetMessageCallback(const MessageCallback &amp;cb)<br \/>\n    {<br \/>\n        _message_callback &#061; cb;<br \/>\n    }<br \/>\n    void SetClosedCallback(const ClosedCallback &amp;cb)<br \/>\n    {<br \/>\n        _closed_callback &#061; cb;<br \/>\n    }<br \/>\n    void SetAnyEventCallback(const AnyEventCallback &amp;cb)<br \/>\n    {<br \/>\n        _event_callback &#061; cb;<br \/>\n    }<br \/>\n    void SetSrvClosedCallback(const ClosedCallback &amp;cb)<br \/>\n    {<br \/>\n        _server_closed_callback &#061; cb;<br \/>\n    }<br \/>\n    void Established() \/\/ \u8fde\u63a5\u5efa\u7acb\u5c31\u7eea\u540e&#xff0c;\u8fdb\u884cChannel\u56de\u8c03\u8bbe\u7f6e&#xff0c;\u542f\u52a8\u8bfb\u76d1\u63a7&#8211;\u8fde\u63a5\u5efa\u7acb\u5b8c\u6210\u65f6\u8fdb\u884c\u8c03\u7528<br \/>\n    {<br \/>\n        _loop-&gt;RunInLoop(std::bind(&amp;Connection::EstablishedInLoop, this));<br \/>\n    }<br \/>\n    void Send(const char *data, size_t len) \/\/ \u53d1\u9001\u6570\u636e&#xff0c;\u5c06\u6570\u636e\u653e\u5230\u53d1\u9001\u7f13\u51b2\u533a&#xff0c;\u542f\u52a8\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n    {<br \/>\n        \/\/ \u5916\u754c\u4f20\u5165\u7684data&#xff0c;\u53ef\u80fd\u662f\u4e2a\u4e34\u65f6\u7684\u7a7a\u95f4&#xff0c;\u6211\u4eec\u53ea\u662f\u628a\u53d1\u9001\u64cd\u4f5c\u538b\u5165\u4e86\u4efb\u52a1\u6c60&#xff0c;\u6709\u53ef\u80fd\u5e76\u6ca1\u6709\u88ab\u7acb\u5373\u6267\u884c<br \/>\n        \/\/ \u56e0\u6b64\u6709\u53ef\u80fd\u6267\u884c\u7684\u65f6\u5019&#xff0c;data\u6307\u5411\u7684\u7a7a\u95f4\u6709\u53ef\u80fd\u5df2\u7ecf\u88ab\u91ca\u653e\u4e86<br \/>\n        Buffer buf;<br \/>\n        buf.WriteAndPush(data, len);<br \/>\n        _loop-&gt;RunInLoop(std::bind(&amp;Connection::SendInLoop, this, std::move(buf))); \/\/ \u53f3\u503c\u5f15\u7528<br \/>\n        \/\/_loop-&gt;RunInLoop(std::bind(&amp;Connection::SendInLoop, this, data, len));<br \/>\n    }<br \/>\n    void Shutdown() \/\/ \u63d0\u4f9b\u7ed9\u7ec4\u4ef6\u4f7f\u7528\u8005\u7684\u5173\u95ed\u63a5\u53e3&#8211;\u5e76\u4e0d\u5b9e\u9645\u5173\u95ed&#xff0c;\u9700\u8981\u5224\u65ad\u6709\u6ca1\u6709\u4e8b\u4ef6\u5f85\u5904\u7406<br \/>\n    {<br \/>\n        _loop-&gt;RunInLoop(std::bind(&amp;Connection::ShutDownInLoop, this));<br \/>\n    }<br \/>\n    void Release()<br \/>\n    {<br \/>\n        _loop-&gt;QueueInLoop(std::bind(&amp;Connection::ReleaseInLoop, this));<br \/>\n    }<br \/>\n    void EnableInactiveRelease(int sec) \/\/ \u542f\u52a8\u975e\u6d3b\u8dc3\u9500\u6bc1\u5e76\u5b9a\u4e49\u591a\u957f\u65f6\u95f4\u65e0\u901a\u4fe1\u5c31\u662f\u975e\u6d3b\u8dc3<br \/>\n    {<br \/>\n        _loop-&gt;RunInLoop(std::bind(&amp;Connection::EnableInactiveReleaseInLoop, this, sec));<br \/>\n    }<br \/>\n    void CancelInactiveRelease() \/\/ \u53d6\u6d88\u975e\u6d3b\u8dc3\u9500\u6bc1<br \/>\n    {<br \/>\n        _loop-&gt;RunInLoop(std::bind(&amp;Connection::CancelInactiveReleaseInLoop, this));<br \/>\n    }<br \/>\n    \/\/ \u5207\u6362\u534f\u8bae&#xff0c;\u91cd\u7f6e\u4e0a\u4e0b\u6587\u4ee5\u53ca\u9636\u6bb5\u6027\u56de\u8c03\u5904\u7406\u51fd\u6570 &#8212; \u975e\u7ebf\u7a0b\u5b89\u5168\u7684 &#8212; \u8fd9\u4e2a\u63a5\u53e3\u5fc5\u987b\u5728EventLoop\u7ebf\u7a0b\u4e2d\u6267\u884c<br \/>\n    \/\/ \u9632\u5907\u65b0\u7684\u4e8b\u4ef6\u89e6\u53d1\u540e&#xff0c;\u5904\u7406\u7684\u65f6\u5019&#xff0c;\u5207\u6362\u4efb\u52a1\u8fd8\u6ca1\u6709\u88ab\u6267\u884c &#8212; \u4f1a\u5bfc\u81f4\u6570\u636e\u4f7f\u7528\u539f\u534f\u8bae\u5904\u7406\u4e86<br \/>\n    void Upgrade(const Any &amp;context, const ConnectedCallback &amp;conn, const MessageCallback &amp;msg,<br \/>\n                 const ClosedCallback &amp;closed, const AnyEventCallback &amp;event)<br \/>\n    {<br \/>\n        _loop-&gt;AssertInLoop();<br \/>\n        _loop-&gt;RunInLoop(std::bind(&amp;Connection::UpgradeInLoop, this, context, conn, msg, closed, event));<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"%C2%A02.12%20%E7%9B%91%E5%90%AC%E6%8F%8F%E8%BF%B0%E7%AC%A6%E7%AE%A1%E7%90%86Acceptor%E6%A8%A1%E5%9D%97\" style=\"background-color:transparent\">\u00a02.12 \u76d1\u542c\u63cf\u8ff0\u7b26\u7ba1\u7406Acceptor\u6a21\u5757<\/h3>\n<p>Acceptor\u6a21\u5757\u662f\u5bf9Socket\u6a21\u5757&#xff0c;Channel\u6a21\u5757\u7684\u6574\u4f53\u5c01\u88c5&#xff0c;\u5b9e\u73b0\u5bf9\u4e00\u4e2a\u76d1\u542c\u5957\u63a5\u5b57\u7684\u6574\u4f53\u7684\u7ba1\u7406<\/p>\n<p>\u9996\u5148\u8fd9\u662fAcceptor\u7c7b\u7684\u6210\u5458\u53d8\u91cf\u4ecb\u7ecd<\/p>\n<p> Socket _socket;                                  \/\/ \u7528\u4e8e\u521b\u5efa\u76d1\u542c\u5957\u63a5\u5b57<br \/>\nEventLoop *_loop;                                \/\/ \u7528\u4e8e\u5bf9\u76d1\u542c\u5957\u63a5\u5b57\u8fdb\u884c\u4e8b\u4ef6\u76d1\u63a7<br \/>\nChannel _channel;                                \/\/ \u7528\u4e8e\u5bf9\u76d1\u542c\u5957\u63a5\u5b57\u8fdb\u884c\u4e8b\u4ef6\u7ba1\u7406<br \/>\nusing AcceptCallback &#061; std::function&lt;void(int)&gt;; \/\/ \u83b7\u53d6\u5230\u94fe\u63a5\u7684\u56de\u8c03\u51fd\u6570<br \/>\nAcceptCallback _accept_callback; <\/p>\n<p>\u4e0b\u9762\u662f\u5bf9\u5176\u4e2d\u7684\u6210\u5458\u51fd\u6570\u89e3\u91ca<\/p>\n<p>\u76d1\u542c\u5957\u63a5\u5b57\u7684\u8bfb\u4e8b\u4ef6\u5904\u7406\u51fd\u6570&#xff0c;\u83b7\u53d6\u65b0\u94fe\u63a5&#xff0c;\u8c03\u7528_accept_callback\u8fdb\u884c\u65b0\u94fe\u63a5\u5904\u7406<\/p>\n<p> void HandleRead()<br \/>\n{<br \/>\n    \/\/ DBG_LOG(&#034;ACCEPT HANDLE READ&#034;);<br \/>\n    int newfd &#061; _socket.Accept();<br \/>\n    if (newfd &lt; 0)<br \/>\n    {<br \/>\n        return;<br \/>\n    }<br \/>\n    if (_accept_callback)<br \/>\n        _accept_callback(newfd);<br \/>\n} <\/p>\n<p>\u521b\u5efa\u670d\u52a1\u7aef<\/p>\n<p> int CreateServer(int port)<br \/>\n{<br \/>\n    bool ret &#061; _socket.CreateServer(port);<br \/>\n    assert(ret &#061;&#061; true);<br \/>\n    return _socket.Fd();<br \/>\n} <\/p>\n<p>\u7136\u540e\u662fAcceptor\u7684\u521d\u59cb\u5316\u51fd\u6570&#xff0c;\u8fd9\u91cc\u9700\u8981\u6ce8\u610f\u7684\u662f&#xff0c;\u4e0d\u80fd\u5c06\u542f\u52a8\u8bfb\u4e8b\u4ef6\u76d1\u63a7&#xff0c;\u653e\u5230\u6784\u9020\u51fd\u6570\u4e2d&#xff0c;\u5fc5\u987b\u5728\u8bbe\u7f6e\u56de\u8c03\u51fd\u6570\u540e&#xff0c;\u518d\u53bb\u542f\u52a8<\/p>\n<p>\u5426\u5219\u6709\u53ef\u80fd\u9020\u6210\u542f\u52a8\u76d1\u63a7\u540e&#xff0c;\u7acb\u5373\u6709\u4e8b\u4ef6&#xff0c;\u5904\u7406\u7684\u65f6\u5019&#xff0c;\u56de\u8c03\u51fd\u6570\u8fd8\u6ca1\u6709\u88ab\u8bbe\u7f6e&#xff0c;\u65b0\u94fe\u63a5\u5f97\u4e0d\u5230\u5904\u7406&#xff0c;\u4e14\u8d44\u6e90\u6cc4\u9732<\/p>\n<p> Acceptor(EventLoop *loop, int port)<br \/>\n    : _socket(CreateServer(port)),<br \/>\n        _loop(loop),<br \/>\n        _channel(loop, _socket.Fd())<br \/>\n{<br \/>\n    _channel.SetReadCallback(std::bind(&amp;Acceptor::HandleRead, this));<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662f\u8fd9\u4e2a\u7c7b\u7684\u5b8c\u6574\u4ee3\u7801<\/p>\n<p> class Acceptor<br \/>\n{<br \/>\nprivate:<br \/>\n    Socket _socket;                                  \/\/ \u7528\u4e8e\u521b\u5efa\u76d1\u542c\u5957\u63a5\u5b57<br \/>\n    EventLoop *_loop;                                \/\/ \u7528\u4e8e\u5bf9\u76d1\u542c\u5957\u63a5\u5b57\u8fdb\u884c\u4e8b\u4ef6\u76d1\u63a7<br \/>\n    Channel _channel;                                \/\/ \u7528\u4e8e\u5bf9\u76d1\u542c\u5957\u63a5\u5b57\u8fdb\u884c\u4e8b\u4ef6\u7ba1\u7406<br \/>\n    using AcceptCallback &#061; std::function&lt;void(int)&gt;; \/\/ \u83b7\u53d6\u5230\u94fe\u63a5\u7684\u56de\u8c03\u51fd\u6570<br \/>\n    AcceptCallback _accept_callback;<\/p>\n<p>private:<br \/>\n    \/*\u76d1\u542c\u5957\u63a5\u5b57\u7684\u8bfb\u4e8b\u4ef6\u5904\u7406\u51fd\u6570&#8212;\u83b7\u53d6\u65b0\u94fe\u63a5&#xff0c;\u8c03\u7528_accept_callback\u8fdb\u884c\u65b0\u94fe\u63a5\u5904\u7406*\/<br \/>\n    void HandleRead()<br \/>\n    {<br \/>\n        \/\/ DBG_LOG(&#034;ACCEPT HANDLE READ&#034;);<br \/>\n        int newfd &#061; _socket.Accept();<br \/>\n        if (newfd &lt; 0)<br \/>\n        {<br \/>\n            return;<br \/>\n        }<br \/>\n        if (_accept_callback)<br \/>\n            _accept_callback(newfd);<br \/>\n    }<br \/>\n    int CreateServer(int port)<br \/>\n    {<br \/>\n        bool ret &#061; _socket.CreateServer(port);<br \/>\n        assert(ret &#061;&#061; true);<br \/>\n        return _socket.Fd();<br \/>\n    }<\/p>\n<p>public:<br \/>\n    \/*\u4e0d\u80fd\u5c06\u542f\u52a8\u8bfb\u4e8b\u4ef6\u76d1\u63a7&#xff0c;\u653e\u5230\u6784\u9020\u51fd\u6570\u4e2d&#xff0c;\u5fc5\u987b\u5728\u8bbe\u7f6e\u56de\u8c03\u51fd\u6570\u540e&#xff0c;\u518d\u53bb\u542f\u52a8*\/<br \/>\n    \/*\u5426\u5219\u6709\u53ef\u80fd\u9020\u6210\u542f\u52a8\u76d1\u63a7\u540e&#xff0c;\u7acb\u5373\u6709\u4e8b\u4ef6&#xff0c;\u5904\u7406\u7684\u65f6\u5019&#xff0c;\u56de\u8c03\u51fd\u6570\u8fd8\u6ca1\u8bbe\u7f6e&#xff1a;\u65b0\u94fe\u63a5\u5f97\u4e0d\u5230\u5904\u7406&#xff0c;\u4e14\u8d44\u6e90\u6cc4\u9732*\/<br \/>\n    Acceptor(EventLoop *loop, int port)<br \/>\n        : _socket(CreateServer(port)),<br \/>\n          _loop(loop),<br \/>\n          _channel(loop, _socket.Fd())<br \/>\n    {<br \/>\n        _channel.SetReadCallback(std::bind(&amp;Acceptor::HandleRead, this));<br \/>\n    }<br \/>\n    void SetAcceptCallBack(const AcceptCallback &amp;cb)<br \/>\n    {<br \/>\n        _accept_callback &#061; cb;<br \/>\n    }<br \/>\n    void Listen()<br \/>\n    {<br \/>\n        _channel.EnableRead();<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"2.13%20%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%B1%BBTcpServer%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0\" style=\"background-color:transparent\">2.13 \u670d\u52a1\u5668\u7c7bTcpServer\u7c7b\u7684\u5b9e\u73b0<\/h3>\n<p>\u8fd9\u4e2a\u6a21\u5757\u65f6\u4e00\u4e2a\u6574\u4f53Tcp\u670d\u52a1\u5668\u6a21\u5757\u7684\u5c01\u88c5&#xff0c;\u5185\u90e8\u5c01\u88c5\u4e86Acceptor\u6a21\u5757&#xff0c;LoopThreadPool\u6a21\u5757<\/p>\n<p>\u4e0b\u9762\u662f\u5bf9\u5176\u6210\u5458\u53d8\u91cf\u7684\u89e3\u91ca<\/p>\n<p> uint64_t _next_id; \/\/ \u8fd9\u662f\u4e00\u4e2a\u81ea\u52a8\u589e\u957f\u7684\u8fde\u63a5ID<br \/>\nint _timeout;      \/\/ \u8fd9\u662f\u975e\u6d3b\u8dc3\u94fe\u63a5\u7684\u7edf\u8ba1\u65f6\u95f4&#8212;\u591a\u957f\u65f6\u95f4\u65e0\u901a\u4fe1\u5c31\u662f\u975e\u6d3b\u8dc3\u8fde\u63a5<br \/>\nint _port;<br \/>\nbool _enable_inactive_release;                      \/\/ \u662f\u5426\u542f\u52a8\u4e86\u975e\u6d3b\u8dc3\u8fde\u63a5\u8d85\u65f6\u9500\u6bc1\u7684\u5224\u65ad\u6807\u5fd7<br \/>\nAcceptor _acceptor;                                 \/\/ \u8fd9\u662f\u76d1\u542c\u5957\u63a5\u5b57\u7684\u7ba1\u7406\u5bf9\u8c61<br \/>\nEventLoop _baseloop;                                \/\/ \u8fd9\u662f\u4e3b\u7ebf\u7a0b\u7684EventLoop\u5bf9\u8c61&#xff0c;\u8d1f\u8d23\u76d1\u542c\u4e8b\u4ef6\u7684\u5904\u7406<br \/>\nLoopThreadPool _pool;                               \/\/ \u8fd9\u662f\u6211\u4eec\u7684\u4ece\u5c5eEventLoop\u7ebf\u7a0b\u6c60<br \/>\nstd::unordered_map&lt;uint64_t, PtrConnection&gt; _conns; \/\/ \u4fdd\u5b58\u7ba1\u7406\u6240\u6709\u8fde\u63a5\u5bf9\u5e94\u7684shared_ptr\u5bf9\u8c61<\/p>\n<p>using ConnectedCallback &#061; std::function&lt;void(const PtrConnection &amp;)&gt;;<br \/>\nusing MessageCallback &#061; std::function&lt;void(const PtrConnection &amp;, Buffer *)&gt;;<br \/>\nusing ClosedCallback &#061; std::function&lt;void(const PtrConnection &amp;)&gt;;<br \/>\nusing AnyEventCallback &#061; std::function&lt;void(const PtrConnection &amp;)&gt;;<br \/>\nusing Functor &#061; std::function&lt;void()&gt;;<br \/>\nConnectedCallback _connected_callback;<br \/>\nMessageCallback _message_callback;<br \/>\nClosedCallback _closed_callback;<br \/>\nAnyEventCallback _event_callback; <\/p>\n<ul>\n<li>TcpServer\u4e2d\u5305\u542b\u6709\u4e00\u4e2aEventLoop\u5bf9\u8c61&#xff1a;\u4ee5\u5907\u5728\u8d85\u8f7b\u91cf\u4f7f\u7528\u573a\u666f\u4e2d\u4e0d\u9700\u8981EventLoop\u7ebf\u7a0b\u6c60&#xff0c;\u53ea\u9700\u8981\u5728\u4e3b\u7ebf\u7a0b\u4e2d\u5b8c\u6210\u6240\u6709\u64cd\u4f5c\u7684\u60c5\u51b5<\/li>\n<li>TcpServer\u6a21\u5757\u5185\u90e8\u5305\u542b\u6709\u4e00\u4e2aLoopThreadPool\u5bf9\u8c61&#xff1a;\u5176\u5b9e\u5c31\u662fEventLoop\u7ebf\u7a0b\u6c60&#xff0c;\u4e5f\u5c31\u662f\u5b50Reactor\u7ebf\u7a0b\u6c60<\/li>\n<li>TcpServer\u6a21\u5757\u5185\u90e8\u5305\u542b\u6709\u4e00\u4e2aAcceptor\u5bf9\u8c61&#xff1a;\u4e00\u4e2aTcpServer\u670d\u52a1\u5668&#xff0c;\u5fc5\u7136\u5bf9\u5e94\u6709\u4e00\u4e2a\u76d1\u542c\u5957\u63a5\u5b57&#xff0c;\u80fd\u591f\u5b8c\u6210\u83b7\u53d6\u5ba2\u6237\u7aef\u65b0\u94fe\u63a5&#xff0c;\u5e76\u5904\u7406\u4efb\u52a1<\/li>\n<li>TcpServer\u6a21\u5757\u5185\u90e8\u5305\u542b\u6709\u4e00\u4e2astd::shared_ptr&lt;Connection&gt;\u7684hash\u8868&#xff1a;\u4fdd\u5b58\u4e86\u6240\u6709\u7684\u65b0\u5efa\u8fde\u63a5\u5bf9\u5e94\u7684Connection\u3002\u9700\u8981\u6ce8\u610f\u7684\u662f&#xff0c;\u6240\u6709\u7684Connection\u4f7f\u7528shared_ptr\u8fdb\u884c\u7ba1\u7406&#xff0c;\u8fd9\u6837\u80fd\u591f\u4fdd\u8bc1\u5728hash\u8868\u4e2d\u5220\u9664\u4e86Connection\u7684\u4fe1\u606f\u540e&#xff0c;\u5728shared_ptr\u8ba1\u6570\u5668\u4e3a0\u7684\u60c5\u51b5\u4e0b\u5b8c\u6210\u5bf9Connection\u8d44\u6e90\u7684\u91ca\u653e\u64cd\u4f5c<\/li>\n<\/ul>\n<p> \u63a5\u4e0b\u6765\u662f\u5bf9\u5176\u6210\u5458\u51fd\u6570\u7684\u89e3\u91ca<\/p>\n<p> \u9996\u5148\u662f\u5bf9\u4e3b\u7ebf\u7a0b\u7684EventLoop\u5bf9\u8c61\u6dfb\u52a0\u5b9a\u65f6\u5668<\/p>\n<p> void RunAfterInLoop(const Functor &amp;task, int delay)<br \/>\n{<br \/>\n    _next_id&#043;&#043;;<br \/>\n    _baseloop.TimerAdd(_next_id, delay, task);<br \/>\n} <\/p>\n<p>\u4e3a\u65b0\u94fe\u63a5\u6784\u9020Connection\u8fdb\u884c\u7ba1\u7406<\/p>\n<p>\u6211\u4eec\u4e3a\u6bcf\u4e00\u4e2a\u94fe\u63a5\u521d\u59cb\u5316\u4e00\u4e2aConnection\u7c7b\u8fdb\u884c\u7ba1\u7406&#xff0c;\u7136\u540e\u8bbe\u7f6e\u5404\u79cd\u56de\u8c03\u51fd\u6570&#xff0c;\u6700\u540e\u5c06\u8fd9\u4e2a\u94fe\u63a5\u52a0\u5165\u5230unordered_map\u4e2d<\/p>\n<p> void NewConnection(int fd)<br \/>\n{<br \/>\n    \/\/ DBG_LOG(&#034;NEWCONNECTION FUNCTION&#034;);<br \/>\n    _next_id&#043;&#043;;<br \/>\n    PtrConnection conn(new Connection(_pool.NextLoop(), _next_id, fd));<br \/>\n    conn-&gt;SetMessageCallback(_message_callback);     \/\/ \u4e3a\u901a\u884c\u5957\u63a5\u5b57\u8bbe\u7f6e\u53ef\u8bfb\u4e8b\u4ef6\u7684\u56de\u8c03\u51fd\u6570<br \/>\n    conn-&gt;SetClosedCallback(_closed_callback);       \/\/ \u5173\u95ed\u4e8b\u4ef6\u7684\u56de\u8c03\u51fd\u6570<br \/>\n    conn-&gt;SetConnectedCallback(_connected_callback); \/\/ \u9519\u8bef\u4e8b\u4ef6\u7684\u56de\u8c03\u51fd\u6570<br \/>\n    conn-&gt;SetAnyEventCallback(_event_callback);<br \/>\n    conn-&gt;SetSrvClosedCallback(std::bind(&amp;TcpServer::RemoveConnection, this, std::placeholders::_1));<br \/>\n    if (_enable_inactive_release)<br \/>\n        conn-&gt;EnableInactiveRelease(_timeout); \/\/ \u542f\u52a8\u975e\u6d3b\u8dc3\u8d85\u65f6\u9500\u6bc1<br \/>\n    conn-&gt;Established();                       \/\/ \u5c31\u7eea\u521d\u59cb\u5316<br \/>\n    _conns.insert(std::make_pair(_next_id, conn));<br \/>\n} <\/p>\n<p>\u79fb\u9664\u8fd9\u4e2a\u94fe\u63a5&#xff0c;\u53ea\u9700\u8981\u4ece_conns\u8fd9\u4e2aunordered_map\u4e2d\u79fb\u9664\u5373\u53ef<\/p>\n<p> void RemoveConnectionInLoop(const PtrConnection &amp;conn)<br \/>\n{<br \/>\n    int id &#061; conn-&gt;Id();<br \/>\n    auto it &#061; _conns.find(id);<br \/>\n    if (it !&#061; _conns.end())<br \/>\n    {<br \/>\n        _conns.erase(it);<br \/>\n    }<br \/>\n} <\/p>\n<p>\u628a\u8fd9\u4e2a\u79fb\u9664Connection\u7684\u4efb\u52a1\u653e\u5230_baseloop\u4e2d\u6267\u884c\u907f\u514d\u4e86\u7ebf\u7a0b\u5b89\u5168\u95ee\u9898<\/p>\n<p> \/\/ \u4ece\u7ba1\u7406Connection\u7684_conns\u4e2d\u79fb\u9664\u8fde\u63a5\u4fe1\u606f<br \/>\nvoid RemoveConnection(const PtrConnection &amp;conn)<br \/>\n{<br \/>\n    _baseloop.RunInLoop(std::bind(&amp;TcpServer::RemoveConnectionInLoop, this, conn));<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662f\u8fd9\u4e2a\u7c7b\u7684\u5b8c\u6574\u4ee3\u7801<\/p>\n<p> class TcpServer<br \/>\n{<br \/>\nprivate:<br \/>\n    uint64_t _next_id; \/\/ \u8fd9\u662f\u4e00\u4e2a\u81ea\u52a8\u589e\u957f\u7684\u8fde\u63a5ID<br \/>\n    int _timeout;      \/\/ \u8fd9\u662f\u975e\u6d3b\u8dc3\u94fe\u63a5\u7684\u7edf\u8ba1\u65f6\u95f4&#8212;\u591a\u957f\u65f6\u95f4\u65e0\u901a\u4fe1\u5c31\u662f\u975e\u6d3b\u8dc3\u8fde\u63a5<br \/>\n    int _port;<br \/>\n    bool _enable_inactive_release;                      \/\/ \u662f\u5426\u542f\u52a8\u4e86\u975e\u6d3b\u8dc3\u8fde\u63a5\u8d85\u65f6\u9500\u6bc1\u7684\u5224\u65ad\u6807\u5fd7<br \/>\n    Acceptor _acceptor;                                 \/\/ \u8fd9\u662f\u76d1\u542c\u5957\u63a5\u5b57\u7684\u7ba1\u7406\u5bf9\u8c61<br \/>\n    EventLoop _baseloop;                                \/\/ \u8fd9\u662f\u4e3b\u7ebf\u7a0b\u7684EventLoop\u5bf9\u8c61&#xff0c;\u8d1f\u8d23\u76d1\u542c\u4e8b\u4ef6\u7684\u5904\u7406<br \/>\n    LoopThreadPool _pool;                               \/\/ \u8fd9\u662f\u6211\u4eec\u7684\u4ece\u5c5eEventLoop\u7ebf\u7a0b\u6c60<br \/>\n    std::unordered_map&lt;uint64_t, PtrConnection&gt; _conns; \/\/ \u4fdd\u5b58\u7ba1\u7406\u6240\u6709\u8fde\u63a5\u5bf9\u5e94\u7684shared_ptr\u5bf9\u8c61<\/p>\n<p>    using ConnectedCallback &#061; std::function&lt;void(const PtrConnection &amp;)&gt;;<br \/>\n    using MessageCallback &#061; std::function&lt;void(const PtrConnection &amp;, Buffer *)&gt;;<br \/>\n    using ClosedCallback &#061; std::function&lt;void(const PtrConnection &amp;)&gt;;<br \/>\n    using AnyEventCallback &#061; std::function&lt;void(const PtrConnection &amp;)&gt;;<br \/>\n    using Functor &#061; std::function&lt;void()&gt;;<br \/>\n    ConnectedCallback _connected_callback;<br \/>\n    MessageCallback _message_callback;<br \/>\n    ClosedCallback _closed_callback;<br \/>\n    AnyEventCallback _event_callback;<\/p>\n<p>private:<br \/>\n    void RunAfterInLoop(const Functor &amp;task, int delay)<br \/>\n    {<br \/>\n        _next_id&#043;&#043;;<br \/>\n        _baseloop.TimerAdd(_next_id, delay, task);<br \/>\n    }<br \/>\n    \/\/ \u4e3a\u65b0\u8fde\u63a5\u6784\u9020Connection\u8fdb\u884c\u7ba1\u7406<br \/>\n    void NewConnection(int fd)<br \/>\n    {<br \/>\n        \/\/ DBG_LOG(&#034;NEWCONNECTION FUNCTION&#034;);<br \/>\n        _next_id&#043;&#043;;<br \/>\n        PtrConnection conn(new Connection(_pool.NextLoop(), _next_id, fd));<br \/>\n        conn-&gt;SetMessageCallback(_message_callback);     \/\/ \u4e3a\u901a\u884c\u5957\u63a5\u5b57\u8bbe\u7f6e\u53ef\u8bfb\u4e8b\u4ef6\u7684\u56de\u8c03\u51fd\u6570<br \/>\n        conn-&gt;SetClosedCallback(_closed_callback);       \/\/ \u5173\u95ed\u4e8b\u4ef6\u7684\u56de\u8c03\u51fd\u6570<br \/>\n        conn-&gt;SetConnectedCallback(_connected_callback); \/\/ \u9519\u8bef\u4e8b\u4ef6\u7684\u56de\u8c03\u51fd\u6570<br \/>\n        conn-&gt;SetAnyEventCallback(_event_callback);<br \/>\n        conn-&gt;SetSrvClosedCallback(std::bind(&amp;TcpServer::RemoveConnection, this, std::placeholders::_1));<br \/>\n        if (_enable_inactive_release)<br \/>\n            conn-&gt;EnableInactiveRelease(_timeout); \/\/ \u542f\u52a8\u975e\u6d3b\u8dc3\u8d85\u65f6\u9500\u6bc1<br \/>\n        conn-&gt;Established();                       \/\/ \u5c31\u7eea\u521d\u59cb\u5316<br \/>\n        _conns.insert(std::make_pair(_next_id, conn));<br \/>\n    }<br \/>\n    void RemoveConnectionInLoop(const PtrConnection &amp;conn)<br \/>\n    {<br \/>\n        int id &#061; conn-&gt;Id();<br \/>\n        auto it &#061; _conns.find(id);<br \/>\n        if (it !&#061; _conns.end())<br \/>\n        {<br \/>\n            _conns.erase(it);<br \/>\n        }<br \/>\n    }<br \/>\n    \/\/ \u4ece\u7ba1\u7406Connection\u7684_conns\u4e2d\u79fb\u9664\u8fde\u63a5\u4fe1\u606f<br \/>\n    void RemoveConnection(const PtrConnection &amp;conn)<br \/>\n    {<br \/>\n        _baseloop.RunInLoop(std::bind(&amp;TcpServer::RemoveConnectionInLoop, this, conn));<br \/>\n    }<\/p>\n<p>public:<br \/>\n    TcpServer(int port)<br \/>\n        : _port(port),<br \/>\n          _next_id(0),<br \/>\n          _enable_inactive_release(false),<br \/>\n          _acceptor(&amp;_baseloop, port),<br \/>\n          _pool(&amp;_baseloop)<br \/>\n    {<br \/>\n        _acceptor.SetAcceptCallBack(std::bind(&amp;TcpServer::NewConnection, this, std::placeholders::_1));<br \/>\n        _acceptor.Listen(); \/\/ \u5f00\u59cb\u76d1\u542c&#xff0c;\u6302\u5230_baseloop\u4e0a\u9762\u53bb<br \/>\n    }<br \/>\n    void SetThreadCount(int count) \/\/ \u8bbe\u7f6e\u7ebf\u7a0b\u6c60\u7684\u6570\u91cf<br \/>\n    {<br \/>\n        return _pool.SetThreadCount(count);<br \/>\n    }<br \/>\n    void SetConnectedCallback(const ConnectedCallback &amp;cb)<br \/>\n    {<br \/>\n        _connected_callback &#061; cb;<br \/>\n    }<br \/>\n    void SetMessageCallback(const MessageCallback &amp;cb)<br \/>\n    {<br \/>\n        _message_callback &#061; cb;<br \/>\n    }<br \/>\n    void SetClosedCallback(const ClosedCallback &amp;cb)<br \/>\n    {<br \/>\n        _closed_callback &#061; cb;<br \/>\n    }<br \/>\n    void SetAnyEventCallback(const AnyEventCallback &amp;cb)<br \/>\n    {<br \/>\n        _event_callback &#061; cb;<br \/>\n    }<br \/>\n    void EnableInactiveRelease(int timeout)<br \/>\n    {<br \/>\n        _timeout &#061; timeout;<br \/>\n        _enable_inactive_release &#061; true;<br \/>\n    }<br \/>\n    \/\/ \u591a\u5c11\u79d2\u4e4b\u540e\u6267\u884c\u4e00\u4e2a\u4efb\u52a1&#xff0c;\u7528\u4e8e\u6dfb\u52a0\u4e00\u4e2a\u5b9a\u65f6\u4efb\u52a1<br \/>\n    void RunAfter(const Functor &amp;task, int delay)<br \/>\n    {<br \/>\n        _baseloop.RunInLoop(std::bind(&amp;TcpServer::RunAfterInLoop, this, task, delay));<br \/>\n    }<br \/>\n    \/\/ \u9700\u8981\u6ce8\u610f\u7684\u662f&#xff0c;_pool.Create();\u8fd9\u4e2a\u8c03\u7528\u51fd\u6570\u53ea\u80fd\u53d1\u5728start\u51fd\u6570\u4e4b\u4e2d&#xff0c;<br \/>\n    \/\/ \u4e0d\u80fd\u653e\u5728\u7c7b\u7684\u521d\u59cb\u5316\u51fd\u6570\u4e2d&#xff0c;\u5426\u5219\u4f1a\u9020\u6210\u8d8a\u754c\u8bbf\u95ee<br \/>\n    void Start()<br \/>\n    {<br \/>\n        _pool.Create();    \/\/ \u521b\u5efa\u7ebf\u7a0b\u6c60\u4e2d\u7684\u4ece\u5c5e\u7ebf\u7a0b<br \/>\n        _baseloop.Start(); \/\/ \u5f00\u59cb\u53bb\u5904\u7406\u4e8b\u4ef6\u4e86<br \/>\n    }<br \/>\n}; <\/p>\n<h2 id=\"3.HTTP%E5%8D%8F%E8%AE%AE%E6%94%AF%E6%8C%81%E6%A8%A1%E5%9D%97%E5%AE%9E%E7%8E%B0\">3.HTTP\u534f\u8bae\u652f\u6301\u6a21\u5757\u5b9e\u73b0<\/h2>\n<h3 id=\"3.1%20Util%E5%AE%9E%E7%94%A8%E5%B7%A5%E5%85%B7%E7%B1%BB%E5%AE%9E%E7%8E%B0\">3.1 Util\u5b9e\u7528\u5de5\u5177\u7c7b\u5b9e\u73b0<\/h3>\n<p>\u9996\u5148\u6211\u4eec\u8981\u5199\u4e00\u4e2a\u5b57\u7b26\u4e32\u5206\u5272\u51fd\u6570\u51fa\u6765&#xff0c;\u8fd9\u4e2a\u51fd\u6570\u6709\u4e09\u4e2a\u53c2\u6570&#xff0c;\u5206\u522b\u662f\u9700\u8981\u88ab\u5206\u5272\u7684\u5b57\u7b26\u4e32&#xff0c;\u88ab\u5206\u5272\u7684\u76ee\u6807\u5b57\u7b26\u4e32&#xff0c;\u5206\u5272\u540e\u7684\u5b57\u7b26\u4e32\u653e\u5165\u7684\u4f4d\u7f6e<\/p>\n<p>\u9996\u5148\u521b\u5efa\u4e00\u4e2a\u53d8\u91cfoffset\u8868\u793a\u4ece0\u4f4d\u7f6e\u5f00\u59cb&#xff0c;\u7136\u540e\u8fdb\u5165\u5faa\u73af&#xff0c;\u6211\u4eec\u4f7f\u7528string\u91cc\u9762\u63d0\u4f9b\u7684find\u51fd\u6570\u5206\u522b\u4f20\u5165\u9700\u8981\u67e5\u627e\u7684\u5b50\u4e32\u548c\u4ece\u54ea\u91cc\u5f00\u59cb\u67e5\u627eoffset&#xff0c;\u5e76\u4e14\u63a5\u53d7\u8fd4\u56de\u503c\u3002\u5f53\u8fd4\u56de\u503c\u662fstd::string::npos&#xff0c;\u8868\u793a\u6ca1\u6709\u627e\u5230\u3002\u5982\u679cpos &#061;&#061; offset&#xff0c;\u8bf4\u660e\u627e\u5230\u4e86&#xff0c;\u4f46\u662f\u4e24\u4e2a\u4f4d\u7f6e\u4e4b\u95f4\u4e0d\u5b58\u5728\u5b50\u4e32&#xff0c;\u76f4\u63a5\u8ba9offset\u8df3\u8fc7\u67e5\u627e\u7684\u5b57\u7b26\u4e32&#xff0c;\u8df3\u8fc7\u672c\u6b21\u5faa\u73af\u3002\u5982\u679cpos\u548coffset\u4e0d\u76f8\u7b49&#xff0c;\u5c31\u76f4\u63a5\u628apos\u4e0eoffset\u4e4b\u95f4\u7684\u5b50\u4e32\u4f20\u5165\u5230arry\u4e2d\u3002\u7ecf\u8fc7\u5faa\u73af\u4e4b\u540e&#xff0c;\u6700\u540e\u8fd4\u56dearry\u7684\u5927\u5c0f&#xff0c;\u5373\u5b50\u4e32\u7684\u6570\u91cf<\/p>\n<p> static size_t Split(const std::string &amp;src, const std::string &amp;sep, std::vector&lt;std::string&gt; *arry)<br \/>\n{<br \/>\n    size_t offset &#061; 0;<\/p>\n<p>    while (offset &lt; src.size())<br \/>\n    {<br \/>\n        size_t pos &#061; src.find(sep, offset); \/\/ \u5728src\u5b57\u7b26\u4e32\u504f\u79fb\u91cfoffset\u5904&#xff0c;\u5f00\u59cb\u5411\u540e\u67e5\u627esep\u5b57\u7b26\/\u5b50\u4e32&#xff0c;\u8fd4\u56de\u67e5\u627e\u5230\u7684\u4f4d\u7f6e<br \/>\n        if (pos &#061;&#061; std::string::npos)<br \/>\n        {<br \/>\n            \/\/ \u6ca1\u6709\u627e\u5230\u7279\u5b9a\u5b57\u7b26<br \/>\n            if (pos &#061;&#061; src.size())<br \/>\n                break;<br \/>\n            arry-&gt;push_back(src.substr(offset));<br \/>\n            return arry-&gt;size();<br \/>\n        }<br \/>\n        if (pos &#061;&#061; offset)<br \/>\n        {<br \/>\n            offset &#061; pos &#043; sep.size();<br \/>\n            continue;<br \/>\n        } \/\/ \u5f53\u524d\u5b50\u4e32\u662f\u7a7a\u7684&#xff0c;\u6ca1\u6709\u5185\u5bb9<br \/>\n        arry-&gt;push_back(src.substr(offset, pos &#8211; offset));<br \/>\n        offset &#061; pos &#043; sep.size();<br \/>\n    }<br \/>\n    return arry-&gt;size();<br \/>\n} <\/p>\n<p>\u7136\u540e\u5c31\u662f\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6240\u6709\u5185\u5bb9&#xff0c;\u5c06\u8bfb\u53d6\u5230\u7684\u5185\u5bb9\u653e\u5230buffer\u4e2d<\/p>\n<p>\u4f7f\u7528std::ifstream &#xff0c;\u4f20\u5165\u6587\u4ef6\u7684\u540d\u5b57\u5e76\u4e14\u4ee5\u4e8c\u8fdb\u5236\u7684\u65b9\u5f0f\u8bfb\u53d6<\/p>\n<p>\u5c06\u6587\u4ef6\u6307\u9488\u8df3\u8f6c\u5230\u672b\u5c3e\u4e4b\u540e&#xff0c;\u4f7f\u7528tellg\u51fd\u6570\u6765\u627e\u5230\u6587\u4ef6\u7684\u5927\u5c0f<\/p>\n<p>\u627e\u5230\u6587\u4ef6\u5927\u5c0f\u4e4b\u540e\u518d\u6b21\u4f7f\u7528seekg\u628a\u6587\u4ef6\u6307\u9488\u653e\u5230\u8d77\u59cb\u4f4d\u7f6e<\/p>\n<p>\u628a\u8bfb\u53d6\u5230\u7684\u6570\u636e\u653e\u5165\u5230buf\u5f53\u4e2d&#xff0c;\u5173\u95ed\u6253\u5f00\u7684\u6587\u4ef6\u6d41<\/p>\n<p> static bool ReadFile(const std::string &amp;filename, std::string *buf)<br \/>\n{<br \/>\n    std::ifstream ifs(filename, std::ios::binary);<br \/>\n    if (ifs.is_open() &#061;&#061; false)<br \/>\n    {<br \/>\n        ERR_LOG(&#034;OPEN %s FILE FAILED!!&#034;, filename.c_str());<br \/>\n        return false;<br \/>\n    }<br \/>\n    size_t fsize &#061; 0;<br \/>\n    \/\/ \u6587\u4ef6\u6307\u9488\u8df3\u8f6c\u5230\u672b\u5c3e<br \/>\n    ifs.seekg(0, ifs.end);<br \/>\n    fsize &#061; ifs.tellg();   \/\/ \u83b7\u53d6\u5f53\u524d\u8bfb\u5199\u4f4d\u7f6e\u76f8\u5bf9\u4e8e\u8d77\u59cb\u4f4d\u7f6e\u7684\u504f\u79fb\u91cf&#xff0c;\u4ece\u672b\u5c3e\u504f\u79fb\u521a\u597d\u5c31\u662f\u6587\u4ef6\u5927\u5c0f<br \/>\n    ifs.seekg(0, ifs.beg); \/\/ \u8df3\u8f6c\u5230\u8d77\u59cb\u4f4d\u7f6e<br \/>\n    buf-&gt;resize(fsize);    \/\/ \u5f00\u8f9f\u6587\u4ef6\u5927\u5c0f\u7684\u7a7a\u95f4<br \/>\n    ifs.read(&amp;(*buf)[0], fsize);<br \/>\n    if (ifs.good() &#061;&#061; false)<br \/>\n    {<br \/>\n        \/\/ \u8bfb\u53d6\u5931\u8d25<br \/>\n        ERR_LOG(&#034;READ %s FILE FAILED!!&#034;, filename.c_str());<br \/>\n        ifs.close();<br \/>\n        return false;<br \/>\n    }<br \/>\n    ifs.close();<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u5411\u6587\u4ef6\u4e2d\u5199\u5165\u6570\u636e<\/p>\n<p>\u9996\u5148\u9700\u8981\u6253\u5f00\u6587\u4ef6&#xff0c;\u4ee5\u4e8c\u8fdb\u5236\u548c\u622a\u65ad\u65b9\u5f0f\u8bfb\u53d6&#xff0c;\u7136\u540e\u4f7f\u7528write\u51fd\u6570\u5c06buf\u4e2d\u7684\u5185\u5bb9\u5199\u5230\u8fd9\u4e2a\u6587\u4ef6\u5f53\u4e2d&#xff0c;\u6700\u540e\u5173\u95ed\u6587\u4ef6\u6d41<\/p>\n<p> static bool WriteFile(const std::string &amp;filename, const std::string &amp;buf)<br \/>\n{<br \/>\n    std::ofstream ofs(filename, std::ios::binary | std::ios::trunc); \/\/ trunc\u4ee3\u8868\u622a\u65ad<br \/>\n    if (ofs.is_open() &#061;&#061; false)<br \/>\n    {<br \/>\n        ERR_LOG(&#034;READ %s FILE FAILED!!&#034;, filename.c_str());<br \/>\n        return false;<br \/>\n    }<br \/>\n    ofs.write(buf.c_str(), buf.size());<br \/>\n    if (ofs.good() &#061;&#061; false)<br \/>\n    {<br \/>\n        ERR_LOG(&#034;WRITE %s FILE FAILED!&#034;, filename.c_str());<br \/>\n        ofs.close();<br \/>\n        return false;<br \/>\n    }<br \/>\n    ofs.close();<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u8fd9\u91cc\u7b80\u5355\u4ecb\u7ecd\u4e00\u4e0bURL\u7f16\u7801&#xff0c;\u5b83\u7684\u4f5c\u7528\u662f\u907f\u514dURL\u4e2d\u7684\u8d44\u6e90\u8def\u5f84\u4e0e\u67e5\u8be2\u5b57\u7b26\u4e32\u4e2d\u7684\u7279\u6b8a\u5b57\u7b26\u4e0eHTTP\u8bf7\u6c42\u4e2d\u7684\u7279\u6b8a\u5b57\u7b26\u4ea7\u751f\u6b67\u4e49\u3002<\/p>\n<p>\u7f16\u7801\u683c\u5f0f&#xff1a;\u5c06\u7279\u6b8a\u5b57\u7b26\u7684ASCII\u503c&#xff0c;\u8f6c\u6362\u4e3a\u4e24\u4e2a16\u8fdb\u5236\u5b57\u7b26<\/p>\n<p>\u4e0d\u7f16\u7801\u7684\u7279\u6b8a\u5b57\u7b26 RFC3986\u6587\u6863\u89c4\u5b9a.-_~\u5b57\u6bcd&#xff0c;\u6570\u5b57\u5c5e\u4e8e\u7edd\u5bf9\u4e0d\u7f16\u7801\u5b57\u7b26&#xff0c;\u7f16\u7801\u683c\u5f0f%HH<\/p>\n<p>W3C\u6587\u6863\u4e2d\u89c4\u5b9a\u67e5\u8be2\u5b57\u7b26\u4e32\u4e2d\u7684\u7a7a\u683c&#xff0c;\u9700\u8981\u88ab\u7f16\u7801\u4e3a &#043;&#xff0c;\u89e3\u7801\u5219\u662f &#043; \u8f6c\u5316\u4e3a\u7a7a\u683c<\/p>\n<p>\u6bd4\u5982&#xff1a;<\/p>\n<ul>\n<li>\u539f\u59cb\u5b57\u7b26\u4e32&#xff1a;Hello World!<\/li>\n<li>\u7f16\u7801\u540e&#xff1a;Hello%20World%21<\/li>\n<\/ul>\n<p> static std::string UrlEncode(const std::string url, bool convert_space_to_plus)<br \/>\n{<br \/>\n    std::string res;<br \/>\n    for (auto &amp;c : url)<br \/>\n    {<br \/>\n        if (c &#061;&#061; &#039;.&#039; || c &#061;&#061; &#039;-&#039; || c &#061;&#061; &#039;_&#039; || c &#061;&#061; &#039;~&#039; || isalnum(c))<br \/>\n        {<br \/>\n            res &#043;&#061; c;<br \/>\n            continue;<br \/>\n        }<br \/>\n        if (c &#061;&#061; &#039; &#039; &amp;&amp; convert_space_to_plus &#061;&#061; true)<br \/>\n        {<br \/>\n            res &#043;&#061; &#039;&#043;&#039;;<br \/>\n            continue;<br \/>\n        }<br \/>\n        \/\/ \u5269\u4e0b\u7684\u5b57\u7b26\u90fd\u662f\u9700\u8981\u7f16\u7801\u79f0\u4e3a%HH\u7684\u683c\u5f0f\u7684<br \/>\n        char tmp[4] &#061; {0};<br \/>\n        snprintf(tmp, 4, &#034;%%%02X&#034;, c);<br \/>\n        res &#043;&#061; tmp;<br \/>\n    }<br \/>\n    return res;<br \/>\n} <\/p>\n<p>\u5c06\u5341\u516d\u8fdb\u5236\u5b57\u7b26\u8f6c\u6362\u4e3a\u5bf9\u5e94\u7684\u6574\u6570\u503c<\/p>\n<p> static char HEXTOI(char c)<br \/>\n{<br \/>\n    if (c &gt;&#061; &#039;0&#039; &amp;&amp; c &lt;&#061; &#039;9&#039;)<br \/>\n    {<br \/>\n        \/\/ \u6570\u5b57\u5b57\u7b26<br \/>\n        return c &#8211; &#039;0&#039;;<br \/>\n    }<br \/>\n    else if (c &gt;&#061; &#039;a&#039; &amp;&amp; c &lt;&#061; &#039;z&#039;)<br \/>\n    {<br \/>\n        return c &#8211; &#039;a&#039; &#043; 10;<br \/>\n    }<br \/>\n    else if (c &gt;&#061; &#039;A&#039; &amp;&amp; c &lt;&#061; &#039;Z&#039;)<br \/>\n    {<br \/>\n        return c &#8211; &#039;A&#039; &#043; 10;<br \/>\n    }<br \/>\n    return -1;<br \/>\n} <\/p>\n<p>\u6709URL\u7f16\u7801\u5f53\u7136\u4e5f\u6709URL\u89e3\u7801&#xff0c;\u5f53\u6211\u4eec\u9047\u5230\u4e86%&#xff0c;\u6211\u4eec\u9700\u8981\u67e5\u770b\u767e\u5206\u53f7\u540e\u9762\u7684\u7b2c\u4e00\u4e2a\u6570\u5b57\u548c\u7b2c\u4e8c\u4e2a\u6570\u5b57&#xff0c;\u5c06\u7b2c\u4e00\u4e2a\u6570\u5b57\u5de6\u79fb4\u4f4d&#xff0c;\u76f8\u5f53\u4e8e\u76f4\u63a5\u4e58\u4ee516&#xff0c;\u7136\u540e\u52a0\u4e0a\u7b2c\u4e8c\u4e2a\u6570\u5b57\u5373\u53ef<\/p>\n<p> static std::string UrlDecode(const std::string url, bool convert_space_to_space)<br \/>\n{<br \/>\n    \/\/ \u9047\u5230%&#xff0c;\u5219\u5c06\u7d27\u968f\u5176\u540e\u7684\u4e24\u4e2a\u5b57\u7b26&#xff0c;\u8f6c\u5316\u4e3a\u6570\u5b57&#xff0c;\u7b2c\u4e00\u4e2a\u6570\u5b57\u5de6\u79fb\u56db\u4f4d&#xff0c;\u7136\u540e\u52a0\u4e0a\u7b2c\u4e8c\u4e2a\u6570\u5b57<br \/>\n    \/\/ eg&#xff1a;%2b &#061; 2 * 2^4 &#043; b(\u8f6c\u5316\u4e3a\u5341\u8fdb\u5236)<br \/>\n    std::string res;<br \/>\n    for (int i &#061; 0; i &lt; url.size(); i&#043;&#043;)<br \/>\n    {<br \/>\n        if (url[i] &#061;&#061; &#039;&#043;&#039; &amp;&amp; convert_space_to_space &#061;&#061; true)<br \/>\n        {<br \/>\n            res &#043;&#061; &#039; &#039;;<br \/>\n            continue;<br \/>\n        }<br \/>\n        if (url[i] &#061;&#061; &#039;%&#039; &amp;&amp; i &#043; 2 &lt; url.size())<br \/>\n        {<br \/>\n            char v1 &#061; HEXTOI(url[i &#043; 1]);<br \/>\n            char v2 &#061; HEXTOI(url[i &#043; 2]);<br \/>\n            char v &#061; (v1 &lt;&lt; 4) &#043; v2;<br \/>\n            res &#043;&#061; v;<br \/>\n            i &#043;&#061; 2;<br \/>\n            continue;<br \/>\n        }<br \/>\n        res &#043;&#061; url[i];<br \/>\n    }<br \/>\n    return res;<br \/>\n} <\/p>\n<p>\u6211\u4eec\u4e5f\u9700\u8981\u901a\u8fc7\u76f8\u5e94\u7684\u72b6\u6001\u7801\u83b7\u53d6\u76f8\u5e94\u7684\u72b6\u6001\u63cf\u8ff0\u4fe1\u606f<\/p>\n<p> static std::string StatuDesc(int statu)<br \/>\n{<\/p>\n<p>    auto it &#061; _statu_msg.find(statu);<br \/>\n    if (it !&#061; _statu_msg.end())<br \/>\n    {<br \/>\n        return it-&gt;second;<br \/>\n    }<br \/>\n    return &#034;Unknown&#034;;<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u5c06\u4f1a\u5217\u51fa\u72b6\u6001\u7801\u5bf9\u5e94\u7684\u4fe1\u606f<\/p>\n<p> std::unordered_map&lt;int, std::string&gt; _statu_msg &#061; {<br \/>\n    {100, &#034;Continue&#034;},<br \/>\n    {101, &#034;Switching Protocol&#034;},<br \/>\n    {102, &#034;Processing&#034;},<br \/>\n    {103, &#034;Early Hints&#034;},<br \/>\n    {200, &#034;OK&#034;},<br \/>\n    {201, &#034;Created&#034;},<br \/>\n    {202, &#034;Accepted&#034;},<br \/>\n    {203, &#034;Non-Authoritative Information&#034;},<br \/>\n    {204, &#034;No Content&#034;},<br \/>\n    {205, &#034;Reset Content&#034;},<br \/>\n    {206, &#034;Partial Content&#034;},<br \/>\n    {207, &#034;Multi-Status&#034;},<br \/>\n    {208, &#034;Already Reported&#034;},<br \/>\n    {226, &#034;IM Used&#034;},<br \/>\n    {300, &#034;Multiple Choice&#034;},<br \/>\n    {301, &#034;Moved Permanently&#034;},<br \/>\n    {302, &#034;Found&#034;},<br \/>\n    {303, &#034;See Other&#034;},<br \/>\n    {304, &#034;Not Modified&#034;},<br \/>\n    {305, &#034;Use Proxy&#034;},<br \/>\n    {306, &#034;unused&#034;},<br \/>\n    {307, &#034;Temporary Redirect&#034;},<br \/>\n    {308, &#034;Permanent Redirect&#034;},<br \/>\n    {400, &#034;Bad Request&#034;},<br \/>\n    {401, &#034;Unauthorized&#034;},<br \/>\n    {402, &#034;Payment Required&#034;},<br \/>\n    {403, &#034;Forbidden&#034;},<br \/>\n    {404, &#034;Not Found&#034;},<br \/>\n    {405, &#034;Method Not Allowed&#034;},<br \/>\n    {406, &#034;Not Acceptable&#034;},<br \/>\n    {407, &#034;Proxy Authentication Required&#034;},<br \/>\n    {408, &#034;Request Timeout&#034;},<br \/>\n    {409, &#034;Conflict&#034;},<br \/>\n    {410, &#034;Gone&#034;},<br \/>\n    {411, &#034;Length Required&#034;},<br \/>\n    {412, &#034;Precondition Failed&#034;},<br \/>\n    {413, &#034;Payload Too Large&#034;},<br \/>\n    {414, &#034;URI Too Long&#034;},<br \/>\n    {415, &#034;Unsupported Media Type&#034;},<br \/>\n    {416, &#034;Range Not Satisfiable&#034;},<br \/>\n    {417, &#034;Expectation Failed&#034;},<br \/>\n    {418, &#034;I&#039;m a teapot&#034;},<br \/>\n    {421, &#034;Misdirected Request&#034;},<br \/>\n    {422, &#034;Unprocessable Entity&#034;},<br \/>\n    {423, &#034;Locked&#034;},<br \/>\n    {424, &#034;Failed Dependency&#034;},<br \/>\n    {425, &#034;Too Early&#034;},<br \/>\n    {426, &#034;Upgrade Required&#034;},<br \/>\n    {428, &#034;Precondition Required&#034;},<br \/>\n    {429, &#034;Too Many Requests&#034;},<br \/>\n    {431, &#034;Request Header Fields Too Large&#034;},<br \/>\n    {451, &#034;Unavailable For Legal Reasons&#034;},<br \/>\n    {501, &#034;Not Implemented&#034;},<br \/>\n    {502, &#034;Bad Gateway&#034;},<br \/>\n    {503, &#034;Service Unavailable&#034;},<br \/>\n    {504, &#034;Gateway Timeout&#034;},<br \/>\n    {505, &#034;HTTP Version Not Supported&#034;},<br \/>\n    {506, &#034;Variant Also Negotiates&#034;},<br \/>\n    {507, &#034;Insufficient Storage&#034;},<br \/>\n    {508, &#034;Loop Detected&#034;},<br \/>\n    {510, &#034;Not Extended&#034;},<br \/>\n    {511, &#034;Network Authentication Required&#034;}}; <\/p>\n<p>\u7136\u540e\u662f\u6839\u636e\u6587\u4ef6\u540e\u7f00\u540d\u83b7\u53d6mime&#xff0c;\u8fd9\u91cc\u89e3\u91ca\u4e00\u4e0bmime\u662f\u4ec0\u4e48&#xff0c;\u662f\u6307\u901a\u8fc7\u6587\u4ef6\u540d\u7684\u6269\u5c55\u540d\u6765\u786e\u5b9a\u8be5\u6587\u4ef6\u5bf9\u5e94\u7684mime\u7c7b\u578b&#xff0c;mime\u7c7b\u578b\u662f\u4e00\u79cd\u6807\u51c6\u5316\u7684\u6587\u4ef6\u7c7b\u578b\u6807\u8bc6\u65b9\u6cd5&#xff0c;\u7528\u4e8e\u544a\u8bc9\u5ba2\u6237\u7aef\u5982\u6b4c\u5904\u7406\u6216\u89e3\u6790\u6536\u5230\u7684\u6587\u4ef6<\/p>\n<p> std::unordered_map&lt;std::string, std::string&gt; _mime_msg &#061; {<br \/>\n    {&#034;.aac&#034;, &#034;audio\/aac&#034;},<br \/>\n    {&#034;.abw&#034;, &#034;application\/x-abiword&#034;},<br \/>\n    {&#034;.arc&#034;, &#034;application\/x-freearc&#034;},<br \/>\n    {&#034;.avi&#034;, &#034;video\/x-msvideo&#034;},<br \/>\n    {&#034;.azw&#034;, &#034;application\/vnd.amazon.ebook&#034;},<br \/>\n    {&#034;.bin&#034;, &#034;application\/octet-stream&#034;},<br \/>\n    {&#034;.bmp&#034;, &#034;image\/bmp&#034;},<br \/>\n    {&#034;.bz&#034;, &#034;application\/x-bzip&#034;},<br \/>\n    {&#034;.bz2&#034;, &#034;application\/x-bzip2&#034;},<br \/>\n    {&#034;.csh&#034;, &#034;application\/x-csh&#034;},<br \/>\n    {&#034;.css&#034;, &#034;text\/css&#034;},<br \/>\n    {&#034;.csv&#034;, &#034;text\/csv&#034;},<br \/>\n    {&#034;.doc&#034;, &#034;application\/msword&#034;},<br \/>\n    {&#034;.docx&#034;, &#034;application\/vnd.openxmlformats-officedocument.wordprocessingml.document&#034;},<br \/>\n    {&#034;.eot&#034;, &#034;application\/vnd.ms-fontobject&#034;},<br \/>\n    {&#034;.epub&#034;, &#034;application\/epub&#043;zip&#034;},<br \/>\n    {&#034;.gif&#034;, &#034;image\/gif&#034;},<br \/>\n    {&#034;.htm&#034;, &#034;text\/html&#034;},<br \/>\n    {&#034;.html&#034;, &#034;text\/html&#034;},<br \/>\n    {&#034;.ico&#034;, &#034;image\/vnd.microsoft.icon&#034;},<br \/>\n    {&#034;.ics&#034;, &#034;text\/calendar&#034;},<br \/>\n    {&#034;.jar&#034;, &#034;application\/java-archive&#034;},<br \/>\n    {&#034;.jpeg&#034;, &#034;image\/jpeg&#034;},<br \/>\n    {&#034;.jpg&#034;, &#034;image\/jpeg&#034;},<br \/>\n    {&#034;.js&#034;, &#034;text\/javascript&#034;},<br \/>\n    {&#034;.json&#034;, &#034;application\/json&#034;},<br \/>\n    {&#034;.jsonld&#034;, &#034;application\/ld&#043;json&#034;},<br \/>\n    {&#034;.mid&#034;, &#034;audio\/midi&#034;},<br \/>\n    {&#034;.midi&#034;, &#034;audio\/x-midi&#034;},<br \/>\n    {&#034;.mjs&#034;, &#034;text\/javascript&#034;},<br \/>\n    {&#034;.mp3&#034;, &#034;audio\/mpeg&#034;},<br \/>\n    {&#034;.mpeg&#034;, &#034;video\/mpeg&#034;},<br \/>\n    {&#034;.mpkg&#034;, &#034;application\/vnd.apple.installer&#043;xml&#034;},<br \/>\n    {&#034;.odp&#034;, &#034;application\/vnd.oasis.opendocument.presentation&#034;},<br \/>\n    {&#034;.ods&#034;, &#034;application\/vnd.oasis.opendocument.spreadsheet&#034;},<br \/>\n    {&#034;.odt&#034;, &#034;application\/vnd.oasis.opendocument.text&#034;},<br \/>\n    {&#034;.oga&#034;, &#034;audio\/ogg&#034;},<br \/>\n    {&#034;.ogv&#034;, &#034;video\/ogg&#034;},<br \/>\n    {&#034;.ogx&#034;, &#034;application\/ogg&#034;},<br \/>\n    {&#034;.otf&#034;, &#034;font\/otf&#034;},<br \/>\n    {&#034;.png&#034;, &#034;image\/png&#034;},<br \/>\n    {&#034;.pdf&#034;, &#034;application\/pdf&#034;},<br \/>\n    {&#034;.ppt&#034;, &#034;application\/vnd.ms-powerpoint&#034;},<br \/>\n    {&#034;.pptx&#034;, &#034;application\/vnd.openxmlformats-officedocument.presentationml.presentation&#034;},<br \/>\n    {&#034;.rar&#034;, &#034;application\/x-rar-compressed&#034;},<br \/>\n    {&#034;.rtf&#034;, &#034;application\/rtf&#034;},<br \/>\n    {&#034;.sh&#034;, &#034;application\/x-sh&#034;},<br \/>\n    {&#034;.svg&#034;, &#034;image\/svg&#043;xml&#034;},<br \/>\n    {&#034;.swf&#034;, &#034;application\/x-shockwave-flash&#034;},<br \/>\n    {&#034;.tar&#034;, &#034;application\/x-tar&#034;},<br \/>\n    {&#034;.tif&#034;, &#034;image\/tiff&#034;},<br \/>\n    {&#034;.tiff&#034;, &#034;image\/tiff&#034;},<br \/>\n    {&#034;.ttf&#034;, &#034;font\/ttf&#034;},<br \/>\n    {&#034;.txt&#034;, &#034;text\/plain&#034;},<br \/>\n    {&#034;.vsd&#034;, &#034;application\/vnd.visio&#034;},<br \/>\n    {&#034;.wav&#034;, &#034;audio\/wav&#034;},<br \/>\n    {&#034;.weba&#034;, &#034;audio\/webm&#034;},<br \/>\n    {&#034;.webm&#034;, &#034;video\/webm&#034;},<br \/>\n    {&#034;.webp&#034;, &#034;image\/webp&#034;},<br \/>\n    {&#034;.woff&#034;, &#034;font\/woff&#034;},<br \/>\n    {&#034;.woff2&#034;, &#034;font\/woff2&#034;},<br \/>\n    {&#034;.xhtml&#034;, &#034;application\/xhtml&#043;xml&#034;},<br \/>\n    {&#034;.xls&#034;, &#034;application\/vnd.ms-excel&#034;},<br \/>\n    {&#034;.xlsx&#034;, &#034;application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet&#034;},<br \/>\n    {&#034;.xml&#034;, &#034;application\/xml&#034;},<br \/>\n    {&#034;.xul&#034;, &#034;application\/vnd.mozilla.xul&#043;xml&#034;},<br \/>\n    {&#034;.zip&#034;, &#034;application\/zip&#034;},<br \/>\n    {&#034;.3gp&#034;, &#034;video\/3gpp&#034;},<br \/>\n    {&#034;.3g2&#034;, &#034;video\/3gpp2&#034;},<br \/>\n    {&#034;.7z&#034;, &#034;application\/x-7z-compressed&#034;}}; <\/p>\n<p>\u6839\u636e\u6587\u4ef6\u540e\u7f00\u540d\u83b7\u53d6\u6587\u4ef6mime\u7684\u4ee3\u7801\u5982\u4e0b<\/p>\n<p> static std::string ExtMime(const std::string &amp;filename)<br \/>\n{<\/p>\n<p>    \/\/ a.b.txt<br \/>\n    size_t pos &#061; filename.find_last_of(&#039;.&#039;);<br \/>\n    if (pos &#061;&#061; std::string::npos)<br \/>\n    {<br \/>\n        return &#034;application\/octet-stream&#034;;<br \/>\n    }<br \/>\n    std::string ext &#061; filename.substr(pos);<br \/>\n    auto it &#061; _mime_msg.find(ext);<br \/>\n    if (it &#061;&#061; _mime_msg.end())<br \/>\n    {<br \/>\n        return &#034;application\/octet-stream&#034;;<br \/>\n    }<br \/>\n    return it-&gt;second;<br \/>\n} <\/p>\n<p>\u5224\u65ad\u4e00\u4e2a\u6587\u4ef6\u662f\u5426\u662f\u4e00\u4e2a\u666e\u901a\u6587\u4ef6<\/p>\n<p>\u8fd9\u91cc\u9700\u8981\u4f7f\u7528\u5230\u7cfb\u7edf\u8c03\u7528stat\u6765\u83b7\u53d6\u6587\u4ef6\u7684\u72b6\u6001\u4fe1\u606f&#xff0c;\u5e76\u4e14\u9700\u8981\u901a\u8fc7S_ISREG\u5b8f\u6765\u5224\u65ad\u6587\u4ef6\u662f\u5426\u4e3a\u666e\u901a\u6587\u4ef6<\/p>\n<p> static bool IsRegular(const std::string &amp;filename)<br \/>\n{<br \/>\n    struct stat st;<br \/>\n    int ret &#061; stat(filename.c_str(), &amp;st);<br \/>\n    if (ret &lt; 0)<br \/>\n    {<br \/>\n        return false;<br \/>\n    }<br \/>\n    return S_ISREG(st.st_mode);<br \/>\n} <\/p>\n<p>\u68c0\u67e5http\u8bf7\u6c42\u7684\u8d44\u6e90\u8def\u5f84\u7684\u6709\u6548\u6027\u5224\u65ad<\/p>\n<p> static bool ValidPath(const std::string &amp;path)<br \/>\n{<br \/>\n    std::vector&lt;std::string&gt; subdir;<br \/>\n    Split(path, &#034;\/&#034;, &amp;subdir);<br \/>\n    int level &#061; 0;<br \/>\n    for (auto &amp;dir : subdir)<br \/>\n    {<br \/>\n        if (dir &#061;&#061; &#034;..&#034;)<br \/>\n        {<br \/>\n            level&#8211;;<br \/>\n            if (level &lt; 0)<br \/>\n            {<br \/>\n                return false;<br \/>\n            }<br \/>\n            continue;<br \/>\n        }<br \/>\n        level&#043;&#043;;<br \/>\n    }<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662fUtil\u7c7b\u7684\u5b8c\u6574\u4ee3\u7801<\/p>\n<p> class Util<br \/>\n{<br \/>\npublic:<br \/>\n    \/\/ \u5b57\u7b26\u4e32\u5206\u5272\u51fd\u6570&#xff0c;\u5206\u5272\u540e\u7684\u5b50\u4e32\u653e\u5230vector\u91cc\u9762&#xff0c;\u6700\u7ec8\u8fd4\u56de\u5b50\u4e32\u7684\u6570\u91cf<br \/>\n    static size_t Split(const std::string &amp;src, const std::string &amp;sep, std::vector&lt;std::string&gt; *arry)<br \/>\n    {<br \/>\n        size_t offset &#061; 0;<\/p>\n<p>        while (offset &lt; src.size())<br \/>\n        {<br \/>\n            size_t pos &#061; src.find(sep, offset); \/\/ \u5728src\u5b57\u7b26\u4e32\u504f\u79fb\u91cfoffset\u5904&#xff0c;\u5f00\u59cb\u5411\u540e\u67e5\u627esep\u5b57\u7b26\/\u5b50\u4e32&#xff0c;\u8fd4\u56de\u67e5\u627e\u5230\u7684\u4f4d\u7f6e<br \/>\n            if (pos &#061;&#061; std::string::npos)<br \/>\n            {<br \/>\n                \/\/ \u6ca1\u6709\u627e\u5230\u7279\u5b9a\u5b57\u7b26<br \/>\n                if (pos &#061;&#061; src.size())<br \/>\n                    break;<br \/>\n                arry-&gt;push_back(src.substr(offset));<br \/>\n                return arry-&gt;size();<br \/>\n            }<br \/>\n            if (pos &#061;&#061; offset)<br \/>\n            {<br \/>\n                offset &#061; pos &#043; sep.size();<br \/>\n                continue;<br \/>\n            } \/\/ \u5f53\u524d\u5b50\u4e32\u662f\u7a7a\u7684&#xff0c;\u6ca1\u6709\u5185\u5bb9<br \/>\n            arry-&gt;push_back(src.substr(offset, pos &#8211; offset));<br \/>\n            offset &#061; pos &#043; sep.size();<br \/>\n        }<br \/>\n        return arry-&gt;size();<br \/>\n    }<br \/>\n    \/\/ \u8bfb\u53d6\u6587\u4ef6\u6240\u6709\u5185\u5bb9&#xff0c;\u5c06\u8bfb\u53d6\u7684\u5185\u5bb9\u653e\u5230buffer\u4e2d<br \/>\n    static bool ReadFile(const std::string &amp;filename, std::string *buf)<br \/>\n    {<br \/>\n        std::ifstream ifs(filename, std::ios::binary);<br \/>\n        if (ifs.is_open() &#061;&#061; false)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;OPEN %s FILE FAILED!!&#034;, filename.c_str());<br \/>\n            return false;<br \/>\n        }<br \/>\n        size_t fsize &#061; 0;<br \/>\n        \/\/ \u6587\u4ef6\u6307\u9488\u8df3\u8f6c\u5230\u672b\u5c3e<br \/>\n        ifs.seekg(0, ifs.end);<br \/>\n        fsize &#061; ifs.tellg();   \/\/ \u83b7\u53d6\u5f53\u524d\u8bfb\u5199\u4f4d\u7f6e\u76f8\u5bf9\u4e8e\u8d77\u59cb\u4f4d\u7f6e\u7684\u504f\u79fb\u91cf&#xff0c;\u4ece\u672b\u5c3e\u504f\u79fb\u521a\u597d\u5c31\u662f\u6587\u4ef6\u5927\u5c0f<br \/>\n        ifs.seekg(0, ifs.beg); \/\/ \u8df3\u8f6c\u5230\u8d77\u59cb\u4f4d\u7f6e<br \/>\n        buf-&gt;resize(fsize);    \/\/ \u5f00\u8f9f\u6587\u4ef6\u5927\u5c0f\u7684\u7a7a\u95f4<br \/>\n        ifs.read(&amp;(*buf)[0], fsize);<br \/>\n        if (ifs.good() &#061;&#061; false)<br \/>\n        {<br \/>\n            \/\/ \u8bfb\u53d6\u5931\u8d25<br \/>\n            ERR_LOG(&#034;READ %s FILE FAILED!!&#034;, filename.c_str());<br \/>\n            ifs.close();<br \/>\n            return false;<br \/>\n        }<br \/>\n        ifs.close();<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ \u5411\u6587\u4ef6\u5199\u5165\u6570\u636e<br \/>\n    static bool WriteFile(const std::string &amp;filename, const std::string &amp;buf)<br \/>\n    {<br \/>\n        std::ofstream ofs(filename, std::ios::binary | std::ios::trunc); \/\/ trunc\u4ee3\u8868\u622a\u65ad<br \/>\n        if (ofs.is_open() &#061;&#061; false)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;READ %s FILE FAILED!!&#034;, filename.c_str());<br \/>\n            return false;<br \/>\n        }<br \/>\n        ofs.write(buf.c_str(), buf.size());<br \/>\n        if (ofs.good() &#061;&#061; false)<br \/>\n        {<br \/>\n            ERR_LOG(&#034;WRITE %s FILE FAILED!&#034;, filename.c_str());<br \/>\n            ofs.close();<br \/>\n            return false;<br \/>\n        }<br \/>\n        ofs.close();<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ URL\u7f16\u7801&#xff0c;\u907f\u514dURL\u4e2d\u8d44\u6e90\u8def\u5f84\u4e0e\u67e5\u8be2\u5b57\u7b26\u4e32\u4e2d\u7684\u7279\u6b8a\u5b57\u7b26\u4e0eHTTP\u8bf7\u6c42\u4e2d\u7279\u6b8a\u5b57\u7b26\u4ea7\u751f\u6b67\u4e49<br \/>\n    \/\/ \u7f16\u7801\u683c\u5f0f&#xff1a;\u5c06\u7279\u6b8a\u5b57\u7b26\u7684ASCII\u503c&#xff0c;\u8f6c\u6362\u4e3a\u4e24\u4e2a16\u8fdb\u5236\u5b57\u7b26&#xff0c;C&#043;&#043; -&gt; C%2B%2B<br \/>\n    \/\/ \u4e0d\u7f16\u7801\u7684\u7279\u6b8a\u5b57\u7b26 RFC3986\u6587\u6863\u89c4\u5b9a.-_~\u5b57\u6bcd&#xff0c;\u6570\u5b57\u5c5e\u4e8e\u7edd\u5bf9\u4e0d\u7f16\u7801\u5b57\u7b26&#xff0c;\u7f16\u7801\u683c\u5f0f%HH<br \/>\n    \/\/ W3C\u6587\u6863\u4e2d\u89c4\u5b9a\u67e5\u8be2\u5b57\u7b26\u4e32\u4e2d\u7684\u7a7a\u683c&#xff0c;\u9700\u8981\u88ab\u7f16\u7801\u4e3a &#043;&#xff0c;\u89e3\u7801\u5219\u662f &#043; \u8f6c\u5316\u4e3a\u7a7a\u683c<br \/>\n    static std::string UrlEncode(const std::string url, bool convert_space_to_plus)<br \/>\n    {<br \/>\n        std::string res;<br \/>\n        for (auto &amp;c : url)<br \/>\n        {<br \/>\n            if (c &#061;&#061; &#039;.&#039; || c &#061;&#061; &#039;-&#039; || c &#061;&#061; &#039;_&#039; || c &#061;&#061; &#039;~&#039; || isalnum(c))<br \/>\n            {<br \/>\n                res &#043;&#061; c;<br \/>\n                continue;<br \/>\n            }<br \/>\n            if (c &#061;&#061; &#039; &#039; &amp;&amp; convert_space_to_plus &#061;&#061; true)<br \/>\n            {<br \/>\n                res &#043;&#061; &#039;&#043;&#039;;<br \/>\n                continue;<br \/>\n            }<br \/>\n            \/\/ \u5269\u4e0b\u7684\u5b57\u7b26\u90fd\u662f\u9700\u8981\u7f16\u7801\u79f0\u4e3a%HH\u7684\u683c\u5f0f\u7684<br \/>\n            char tmp[4] &#061; {0};<br \/>\n            snprintf(tmp, 4, &#034;%%%02X&#034;, c);<br \/>\n            res &#043;&#061; tmp;<br \/>\n        }<br \/>\n        return res;<br \/>\n    }<br \/>\n    static char HEXTOI(char c)<br \/>\n    {<br \/>\n        if (c &gt;&#061; &#039;0&#039; &amp;&amp; c &lt;&#061; &#039;9&#039;)<br \/>\n        {<br \/>\n            \/\/ \u6570\u5b57\u5b57\u7b26<br \/>\n            return c &#8211; &#039;0&#039;;<br \/>\n        }<br \/>\n        else if (c &gt;&#061; &#039;a&#039; &amp;&amp; c &lt;&#061; &#039;z&#039;)<br \/>\n        {<br \/>\n            return c &#8211; &#039;a&#039; &#043; 10;<br \/>\n        }<br \/>\n        else if (c &gt;&#061; &#039;A&#039; &amp;&amp; c &lt;&#061; &#039;Z&#039;)<br \/>\n        {<br \/>\n            return c &#8211; &#039;A&#039; &#043; 10;<br \/>\n        }<br \/>\n        return -1;<br \/>\n    }<br \/>\n    \/\/ URL\u89e3\u7801<br \/>\n    static std::string UrlDecode(const std::string url, bool convert_space_to_space)<br \/>\n    {<br \/>\n        \/\/ \u9047\u5230%&#xff0c;\u5219\u5c06\u7d27\u968f\u5176\u540e\u7684\u4e24\u4e2a\u5b57\u7b26&#xff0c;\u8f6c\u5316\u4e3a\u6570\u5b57&#xff0c;\u7b2c\u4e00\u4e2a\u6570\u5b57\u5de6\u79fb\u56db\u4f4d&#xff0c;\u7136\u540e\u52a0\u4e0a\u7b2c\u4e8c\u4e2a\u6570\u5b57<br \/>\n        \/\/ eg&#xff1a;%2b &#061; 2 * 2^4 &#043; b(\u8f6c\u5316\u4e3a\u5341\u8fdb\u5236)<br \/>\n        std::string res;<br \/>\n        for (int i &#061; 0; i &lt; url.size(); i&#043;&#043;)<br \/>\n        {<br \/>\n            if (url[i] &#061;&#061; &#039;&#043;&#039; &amp;&amp; convert_space_to_space &#061;&#061; true)<br \/>\n            {<br \/>\n                res &#043;&#061; &#039; &#039;;<br \/>\n                continue;<br \/>\n            }<br \/>\n            if (url[i] &#061;&#061; &#039;%&#039; &amp;&amp; i &#043; 2 &lt; url.size())<br \/>\n            {<br \/>\n                char v1 &#061; HEXTOI(url[i &#043; 1]);<br \/>\n                char v2 &#061; HEXTOI(url[i &#043; 2]);<br \/>\n                char v &#061; (v1 &lt;&lt; 4) &#043; v2;<br \/>\n                res &#043;&#061; v;<br \/>\n                i &#043;&#061; 2;<br \/>\n                continue;<br \/>\n            }<br \/>\n            res &#043;&#061; url[i];<br \/>\n        }<br \/>\n        return res;<br \/>\n    }<br \/>\n    \/\/ \u76f8\u5e94\u72b6\u6001\u7801\u7684\u63cf\u8ff0\u4fe1\u606f\u83b7\u53d6<br \/>\n    static std::string StatuDesc(int statu)<br \/>\n    {<\/p>\n<p>        auto it &#061; _statu_msg.find(statu);<br \/>\n        if (it !&#061; _statu_msg.end())<br \/>\n        {<br \/>\n            return it-&gt;second;<br \/>\n        }<br \/>\n        return &#034;Unknown&#034;;<br \/>\n    }<br \/>\n    \/\/ \u6839\u636e\u6587\u4ef6\u540e\u7f00\u540d\u83b7\u53d6\u6587\u4ef6mime<br \/>\n    static std::string ExtMime(const std::string &amp;filename)<br \/>\n    {<\/p>\n<p>        \/\/ a.b.txt<br \/>\n        size_t pos &#061; filename.find_last_of(&#039;.&#039;);<br \/>\n        if (pos &#061;&#061; std::string::npos)<br \/>\n        {<br \/>\n            return &#034;application\/octet-stream&#034;;<br \/>\n        }<br \/>\n        std::string ext &#061; filename.substr(pos);<br \/>\n        auto it &#061; _mime_msg.find(ext);<br \/>\n        if (it &#061;&#061; _mime_msg.end())<br \/>\n        {<br \/>\n            return &#034;application\/octet-stream&#034;;<br \/>\n        }<br \/>\n        return it-&gt;second;<br \/>\n    }<br \/>\n    \/\/ \u5224\u65ad\u4e00\u4e2a\u6587\u4ef6\u662f\u5426\u662f\u4e00\u4e2a\u76ee\u5f55<br \/>\n    static bool IsDirectory(const std::string &amp;filename)<br \/>\n    {<br \/>\n        struct stat st;<br \/>\n        int ret &#061; stat(filename.c_str(), &amp;st);<br \/>\n        if (ret &lt; 0)<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        return S_ISDIR(st.st_mode);<br \/>\n    }<br \/>\n    \/\/ \u5224\u65ad\u4e00\u4e2a\u6587\u4ef6\u662f\u5426\u662f\u4e00\u4e2a\u666e\u901a\u6587\u4ef6<br \/>\n    static bool IsRegular(const std::string &amp;filename)<br \/>\n    {<br \/>\n        struct stat st;<br \/>\n        int ret &#061; stat(filename.c_str(), &amp;st);<br \/>\n        if (ret &lt; 0)<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        return S_ISREG(st.st_mode);<br \/>\n    }<br \/>\n    \/\/ http\u8bf7\u6c42\u7684\u8d44\u6e90\u8def\u5f84\u6709\u6548\u6027\u5224\u65ad<br \/>\n    \/\/ \/index.html &#8212; \u524d\u9762\u7684\/\u4e5f\u53eb\u505a\u76f8\u5bf9\u76ee\u5f55 \u6620\u5c04\u7684\u662f\u67d0\u4e2a\u670d\u52a1\u5668\u4e0a\u7684\u5b50\u76ee\u5f55<br \/>\n    \/\/ \u60f3\u8868\u8fbe\u7684\u610f\u601d\u5c31\u662f&#xff0c;\u5ba2\u6237\u7aef\u53ea\u80fd\u8bf7\u6c42\u76f8\u5bf9\u6839\u76ee\u5f55\u4e2d\u7684\u8d44\u6e90&#xff0c;\u5176\u4ed6\u5730\u65b9\u5c31\u4e0d\u4e88\u7406\u4f1a<br \/>\n    \/\/ \/..\/login.html\u8fd9\u4e2a\u8def\u5f84\u662f\u5728\u76f8\u5bf9\u6839\u76ee\u5f55\u4e4b\u5916&#xff0c;\u4e0d\u5408\u7406<br \/>\n    static bool ValidPath(const std::string &amp;path)<br \/>\n    {<br \/>\n        std::vector&lt;std::string&gt; subdir;<br \/>\n        Split(path, &#034;\/&#034;, &amp;subdir);<br \/>\n        int level &#061; 0;<br \/>\n        for (auto &amp;dir : subdir)<br \/>\n        {<br \/>\n            if (dir &#061;&#061; &#034;..&#034;)<br \/>\n            {<br \/>\n                level&#8211;;<br \/>\n                if (level &lt; 0)<br \/>\n                {<br \/>\n                    return false;<br \/>\n                }<br \/>\n                continue;<br \/>\n            }<br \/>\n            level&#043;&#043;;<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"3.2%20HttpRequest%20%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0\">3.2 HttpRequest \u7c7b\u7684\u5b9e\u73b0<\/h3>\n<p>\u8fd9\u4e2a\u6a21\u5757\u662fHTTP\u8bf7\u6c42\u6570\u636e\u6a21\u5757&#xff0c;\u7528\u4e8e\u4fdd\u5b58HTTP\u8bf7\u6c42\u6570\u636e\u88ab\u89e3\u6790\u540e\u7684\u5404\u9879\u8bf7\u6c42\u5143\u7d20\u4fe1\u606f<\/p>\n<p>\u5148\u7ed9\u51fa\u4e00\u4e2aHTTP\u8bf7\u6c42\u7684\u4f8b\u5b50<\/p>\n<p> GET \/index.html HTTP\/1.1<br \/>\nHost: example.com<br \/>\nUser-Agent: Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/91.0.4472.124 Safari\/537.36<br \/>\nAccept: text\/html,application\/xhtml&#043;xml,application\/xml;q&#061;0.9,image\/webp,*\/*;q&#061;0.8<br \/>\nAccept-Language: en-US,en;q&#061;0.5<br \/>\nAccept-Encoding: gzip, deflate, br<br \/>\nConnection: keep-alive <\/p>\n<p>\u6839\u636e\u4e0a\u9762\u7684\u8bf7\u6c42&#xff0c;\u6211\u4eec\u53ef\u4ee5\u8bbe\u8ba1\u51fa\u5982\u4e0b\u7684\u6210\u5458\u53d8\u91cf<\/p>\n<p> std::string _method;                                   \/\/ \u8bf7\u6c42\u65b9\u6cd5<br \/>\nstd::string _path;                                     \/\/ \u8d44\u6e90\u8def\u5f84<br \/>\nstd::string _version;                                  \/\/ \u534f\u8bae\u7248\u672c<br \/>\nstd::string _body;                                     \/\/ \u8bf7\u6c42\u6b63\u6587<br \/>\nstd::smatch _matches;                                  \/\/ \u8d44\u6e90\u8def\u5f84\u7684\u6b63\u5219\u63d0\u53d6\u6570\u636e<br \/>\nstd::unordered_map&lt;std::string, std::string&gt; _headers; \/\/ \u5934\u90e8\u5b57\u6bb5<br \/>\nstd::unordered_map&lt;std::string, std::string&gt; _params;  \/\/ \u67e5\u8be2\u5b57\u7b26\u4e32\u901a\u5e38\u6307\u7684\u662f URL \u4e2d\u7684\u67e5\u8be2\u53c2\u6570 <\/p>\n<p>\u7136\u540e\u662f\u5bf9\u5176\u4e2d\u7684\u6210\u5458\u51fd\u6570\u7684\u89e3\u91ca<\/p>\n<p>\u5173\u4e8e\u5bf9\u8fd9\u4e2a\u7c7b\u7684\u521d\u59cb\u5316&#xff0c;\u6211\u4eec\u9ed8\u8ba4\u5c06\u540c\u884c\u534f\u8bae\u7248\u672c\u8bbe\u7f6e\u4e3aHTTP\/1.1<\/p>\n<p> HttpRequest()<br \/>\n    : _version(&#034;HTTP\/1.1&#034;)<br \/>\n{} <\/p>\n<p>\u5bf9\u7c7b\u7684\u6210\u5458\u53d8\u91cf\u8fdb\u884c\u91cd\u7f6e\u7684\u51fd\u6570<\/p>\n<p> void ReSet()<br \/>\n{<br \/>\n    _method.clear();<br \/>\n    _path.clear();<br \/>\n    _version &#061; &#034;HTTP\/1.1&#034;;<br \/>\n    _body.clear();<br \/>\n    std::smatch match;<br \/>\n    _matches.swap(match);<br \/>\n    _headers.clear();<br \/>\n    _params.clear();<br \/>\n} <\/p>\n<p>_headers\u662f\u4e00\u4e2a\u54c8\u5e0c\u8868&#xff0c;\u6211\u4eec\u8bbe\u8ba1\u4e00\u4e2a\u51fd\u6570SetHeader\u6765\u63d2\u5165\u5934\u90e8\u5b57\u6bb5<\/p>\n<p> void SetHeader(std::string &amp;key, std::string &amp;val)<br \/>\n{<br \/>\n    _headers.insert(std::make_pair(key, val));<br \/>\n} <\/p>\n<p>HasHeader\u662f\u7528\u6765\u5224\u65ad\u662f\u5426\u5b58\u5728\u6307\u5b9a\u7684\u5934\u90e8\u5b57\u6bb5&#xff0c;\u5b9e\u73b0\u5b83\u5f88\u7b80\u5355&#xff0c;\u5229\u7528unordered_map\u4e2d\u7684find\u5373\u53ef<\/p>\n<p> bool HasHeader(const std::string &amp;key) const<br \/>\n{<br \/>\n    auto it &#061; _headers.find(key);<br \/>\n    if (it &#061;&#061; _headers.end())<br \/>\n    {<br \/>\n        return false;<br \/>\n    }<br \/>\n    return true;<br \/>\n} <\/p>\n<p>Content-Length\u662f\u5934\u90e8\u5b57\u6bb5\u7684\u4e00\u79cd&#xff0c;\u8868\u793a\u6b63\u6587\u957f\u5ea6&#xff0c;\u901a\u8fc7ContentLength\u51fd\u6570\u6765\u83b7\u53d6\u6b63\u6587\u7684\u957f\u5ea6<\/p>\n<p> size_t ContentLength() const<br \/>\n{<br \/>\n    bool ret &#061; HasHeader(&#034;Content-Length&#034;);<br \/>\n    if (ret &#061;&#061; false)<br \/>\n    {<br \/>\n        return 0;<br \/>\n    }<br \/>\n    std::string clen &#061; GetHeader(&#034;Content-Length&#034;);<br \/>\n    return std::stol(clen);<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662f\u8fd9\u4e2a\u7c7b\u7684\u5168\u90e8\u4ee3\u7801<\/p>\n<p> class HttpRequest<br \/>\n{<br \/>\npublic:<br \/>\n    std::string _method;                                   \/\/ \u8bf7\u6c42\u65b9\u6cd5<br \/>\n    std::string _path;                                     \/\/ \u8d44\u6e90\u8def\u5f84<br \/>\n    std::string _version;                                  \/\/ \u534f\u8bae\u7248\u672c<br \/>\n    std::string _body;                                     \/\/ \u8bf7\u6c42\u6b63\u6587<br \/>\n    std::smatch _matches;                                  \/\/ \u8d44\u6e90\u8def\u5f84\u7684\u6b63\u5219\u63d0\u53d6\u6570\u636e<br \/>\n    std::unordered_map&lt;std::string, std::string&gt; _headers; \/\/ \u5934\u90e8\u5b57\u6bb5<br \/>\n    std::unordered_map&lt;std::string, std::string&gt; _params;  \/\/ \u67e5\u8be2\u5b57\u7b26\u4e32\u901a\u5e38\u6307\u7684\u662f URL \u4e2d\u7684\u67e5\u8be2\u53c2\u6570<br \/>\npublic:<br \/>\n    HttpRequest()<br \/>\n        : _version(&#034;HTTP\/1.1&#034;)<br \/>\n    {<br \/>\n    }<br \/>\n    void ReSet()<br \/>\n    {<br \/>\n        _method.clear();<br \/>\n        _path.clear();<br \/>\n        _version &#061; &#034;HTTP\/1.1&#034;;<br \/>\n        _body.clear();<br \/>\n        std::smatch match;<br \/>\n        _matches.swap(match);<br \/>\n        _headers.clear();<br \/>\n        _params.clear();<br \/>\n    }<br \/>\n    \/\/ \u63d2\u5165\u5934\u90e8\u5b57\u6bb5<br \/>\n    void SetHeader(std::string &amp;key, std::string &amp;val)<br \/>\n    {<br \/>\n        _headers.insert(std::make_pair(key, val));<br \/>\n    }<br \/>\n    \/\/ \u5224\u65ad\u662f\u5426\u5b58\u5728\u6307\u5b9a\u5934\u90e8\u5b57\u6bb5<br \/>\n    bool HasHeader(const std::string &amp;key) const<br \/>\n    {<br \/>\n        auto it &#061; _headers.find(key);<br \/>\n        if (it &#061;&#061; _headers.end())<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ \u83b7\u53d6\u6307\u5b9a\u5934\u90e8\u5b57\u6bb5\u7684\u503c<br \/>\n    std::string GetHeader(const std::string &amp;key) const<br \/>\n    {<br \/>\n        auto it &#061; _headers.find(key);<br \/>\n        if (it &#061;&#061; _headers.end())<br \/>\n        {<br \/>\n            return &#034;&#034;;<br \/>\n        }<br \/>\n        return it-&gt;second;<br \/>\n    }<br \/>\n    \/\/ \u63d2\u5165\u67e5\u8be2\u5b57\u7b26\u4e32<br \/>\n    void SetParam(const std::string &amp;key, const std::string &amp;val)<br \/>\n    {<br \/>\n        _params.insert(std::make_pair(key, val));<br \/>\n    }<br \/>\n    \/\/ \u5224\u65ad\u662f\u5426\u6709\u67d0\u4e2a\u6307\u5b9a\u7684\u67e5\u8be2\u5b57\u7b26\u4e32<br \/>\n    bool HasParam(const std::string &amp;key) const<br \/>\n    {<br \/>\n        auto it &#061; _params.find(key);<br \/>\n        if (it &#061;&#061; _params.end())<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ \u83b7\u53d6\u6307\u5b9a\u7684\u67e5\u8be2\u5b57\u7b26\u4e32<br \/>\n    std::string GetParam(const std::string &amp;key) const<br \/>\n    {<br \/>\n        auto it &#061; _params.find(key);<br \/>\n        if (it &#061;&#061; _params.end())<br \/>\n        {<br \/>\n            return &#034;&#034;;<br \/>\n        }<br \/>\n        return it-&gt;second;<br \/>\n    }<br \/>\n    \/\/ \u83b7\u53d6\u6b63\u6587\u957f\u5ea6<br \/>\n    size_t ContentLength() const<br \/>\n    {<br \/>\n        bool ret &#061; HasHeader(&#034;Content-Length&#034;);<br \/>\n        if (ret &#061;&#061; false)<br \/>\n        {<br \/>\n            return 0;<br \/>\n        }<br \/>\n        std::string clen &#061; GetHeader(&#034;Content-Length&#034;);<br \/>\n        return std::stol(clen);<br \/>\n    }<br \/>\n    \/\/ \u5224\u65ad\u662f\u5426\u4e3a\u77ed\u8fde\u63a5<br \/>\n    bool Close() const<br \/>\n    {<br \/>\n        \/\/ \u6ca1\u6709Connection\u5b57\u6bb5\u6216\u8005\u6709Connection\u4f46\u662f\u503c\u662ffalse&#xff0c;\u5219\u90fd\u662f\u77ed\u8fde\u63a5&#xff0c;\u5426\u5219\u662f\u957f\u8fde\u63a5<br \/>\n        \/\/ DBG_LOG(&#034;%d&#034;, HasHeader(&#034;Connection&#034;) &#061;&#061; true);<br \/>\n        \/\/ DBG_LOG(&#034;%d&#034;, GetHeader(&#034;Connection&#034;) &#061;&#061; &#034;keep-alive&#034;);<br \/>\n        \/\/ DBG_LOG(&#034;[%s]&#034;, GetHeader(&#034;Connection&#034;).c_str());<br \/>\n        if (HasHeader(&#034;Connection&#034;) &#061;&#061; true &amp;&amp; GetHeader(&#034;Connection&#034;) &#061;&#061; &#034;keep-alive&#034;)<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<br \/>\n};<\/p>\n<h3 id=\"3.3%20HttpResponse%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0\">3.3 HttpResponse\u7c7b\u7684\u5b9e\u73b0<\/h3>\n<p>\u8fd9\u4e2a\u6a21\u5757\u662fHTTP\u54cd\u5e94\u6570\u636e\u6a21\u5757&#xff0c;\u7528\u4e8e\u4e1a\u52a1\u5904\u7406\u540e\u8bbe\u7f6e\u5e76\u4fdd\u5b58HTTp\u54cd\u5e94\u6570\u636e\u7684\u5404\u9879\u5143\u7d20\u4fe1\u606f&#xff0c;\u6700\u7ec8\u4f1a\u88ab\u6309\u7167HTTP\u534f\u8bae\u54cd\u5e94\u683c\u5f0f\u6210\u4e3a\u54cd\u5e94\u4fe1\u606f\u53d1\u9001\u7ed9\u5ba2\u6237\u7aef<\/p>\n<p>\u4e0b\u9762\u662f\u4e00\u4e2aHTTP\u54cd\u5e94\u7684\u4f8b\u5b50<\/p>\n<p>HTTP\/1.1 200 OK<br \/>\nDate: Sun, 18 May 2025 05:37:15 GMT<br \/>\nServer: Apache\/2.4.41 (Ubuntu)<br \/>\nContent-Type: text\/html; charset&#061;UTF-8<br \/>\nContent-Length: 1256<br \/>\nConnection: keep-alive<\/p>\n<p>&lt;!DOCTYPE html&gt;<br \/>\n&lt;html&gt;<br \/>\n&lt;head&gt;<br \/>\n    &lt;title&gt;Example Page&lt;\/title&gt;<br \/>\n&lt;\/head&gt;<br \/>\n&lt;body&gt;<br \/>\n    &lt;h1&gt;Welcome to the Example Page&lt;\/h1&gt;<br \/>\n    &lt;p&gt;This is a simple HTML page returned by the server.&lt;\/p&gt;<br \/>\n&lt;\/body&gt;<br \/>\n&lt;\/html&gt; <\/p>\n<p>\u4e0b\u9762\u7684\u6210\u5458\u53d8\u91cf\u5c31\u662f\u7528\u6765\u4fdd\u5b58\u4e0a\u9762\u793a\u4f8b\u62a5\u6587\u7684\u4fe1\u606f<\/p>\n<p> int _statu;<br \/>\nbool _redirect_flag;<br \/>\nstd::string _body;<br \/>\nstd::string _redirect_url;<br \/>\nstd::unordered_map&lt;std::string, std::string&gt; _headers; <\/p>\n<p>\u8fd9\u91cc\u6709\u4e00\u4e2a\u6210\u5458\u53d8\u91cf\u9700\u8981\u89e3\u91ca\u4e00\u4e0b<\/p>\n<p>_redirect_flag&#xff1a;\u8fd9\u662f\u4e00\u4e2a\u8868\u793a\u662f\u5426\u91cd\u5b9a\u5411\u7684\u53d8\u91cf&#xff0c;\u5728Web\u5f00\u53d1\u4e2d&#xff0c;HTTP\u91cd\u5b9a\u5411\u662f\u6307\u670d\u52a1\u5668\u8fd4\u56de\u4e00\u4e2a\u7279\u6b8a\u7684\u54cd\u5e94&#xff08;\u6bd4\u5982\u72b6\u6001\u78013XX&#xff09;&#xff0c;\u8868\u793a\u6307\u793a\u5ba2\u6237\u7aef\u8bbf\u95ee\u53e6\u4e00\u4e2aURL<\/p>\n<p> \u7136\u540e\u5c31\u662f\u5bf9\u5176\u6210\u5458\u51fd\u6570\u7684\u89e3\u91ca<\/p>\n<p> \u6709\u65f6\u5019\u6211\u4eec\u9700\u8981\u91cd\u5b9a\u5411\u8fde\u63a5SetRedirect<\/p>\n<p> void SetRedirect(const std::string &amp;url, int statu &#061; 302)<br \/>\n{<br \/>\n    _statu &#061; statu;<br \/>\n    _redirect_flag &#061; true;<br \/>\n    _redirect_url &#061; url;<br \/>\n} <\/p>\n<p>\u7136\u540e\u5c31\u662f\u67e5\u770b\u8fd9\u4e2a\u94fe\u63a5\u662f\u957f\u8fde\u63a5\u8fd8\u662f\u77ed\u8fde\u63a5&#xff0c;\u6211\u4eec\u53ea\u9700\u8981\u67e5\u770bConnection\u5b57\u6bb5&#xff0c;\u5982\u679c\u8fd9\u4e2a\u5b57\u6bb5\u7684value\u503c\u662fkeep-alive\u8868\u793a\u662f\u957f\u8fde\u63a5<\/p>\n<p> bool Close()<br \/>\n{<br \/>\n    \/\/ \u6ca1\u6709Connection\u5b57\u6bb5\u6216\u8005\u6709Connection\u4f46\u662f\u503c\u662ffalse&#xff0c;\u5219\u90fd\u662f\u77ed\u8fde\u63a5&#xff0c;\u5426\u5219\u662f\u957f\u8fde\u63a5<br \/>\n    if (HasHeader(&#034;Connection&#034;) &#061;&#061; true &amp;&amp; GetHeader(&#034;Connection&#034;) &#061;&#061; &#034;keep-alive&#034;)<br \/>\n    {<br \/>\n        return false;<br \/>\n    }<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662f\u8fd9\u4e2a\u7c7b\u7684\u5168\u90e8\u4ee3\u7801<\/p>\n<p> class HttpResponse<br \/>\n{<br \/>\npublic:<br \/>\n    int _statu;<br \/>\n    bool _redirect_flag;<br \/>\n    std::string _body;<br \/>\n    \/\/ \u91cd\u5b9a\u5411<br \/>\n    \/\/ \u5728Web\u5f00\u53d1\u4e2d&#xff0c;HTTP \u91cd\u5b9a\u5411\u662f\u6307\u670d\u52a1\u5668\u8fd4\u56de\u4e00\u4e2a\u7279\u6b8a\u7684\u54cd\u5e94&#xff08;\u72b6\u6001\u78013xx&#xff09;&#xff0c;<br \/>\n    \/\/ \u6307\u793a\u5ba2\u6237\u7aef&#xff08;\u5982\u6d4f\u89c8\u5668&#xff09;\u8bbf\u95ee\u53e6\u4e00\u4e2aURL\u3002<br \/>\n    std::string _redirect_url;<br \/>\n    std::unordered_map&lt;std::string, std::string&gt; _headers;<\/p>\n<p>public:<br \/>\n    HttpResponse()<br \/>\n        : _redirect_flag(false),<br \/>\n          _statu(200)<br \/>\n    {<br \/>\n    }<br \/>\n    HttpResponse(int statu)<br \/>\n        : _redirect_flag(false),<br \/>\n          _statu(statu)<br \/>\n    {<br \/>\n    }<br \/>\n    void ReSet()<br \/>\n    {<br \/>\n        _statu &#061; 200;<br \/>\n        _redirect_flag &#061; false;<br \/>\n        _body.clear();<br \/>\n        _redirect_url.clear();<br \/>\n        _headers.clear();<br \/>\n    }<br \/>\n    \/\/ \u63d2\u5165\u5934\u90e8\u5b57\u6bb5<br \/>\n    void SetHeader(const std::string &amp;key, const std::string &amp;val)<br \/>\n    {<br \/>\n        _headers.insert(std::make_pair(key, val));<br \/>\n    }<br \/>\n    \/\/ \u5224\u65ad\u662f\u5426\u5b58\u5728\u6307\u5b9a\u5934\u90e8\u5b57\u6bb5<br \/>\n    bool HasHeader(const std::string &amp;key)<br \/>\n    {<br \/>\n        auto it &#061; _headers.find(key);<br \/>\n        if (it &#061;&#061; _headers.end())<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ \u83b7\u53d6\u6307\u5b9a\u5934\u90e8\u5b57\u6bb5\u7684\u503c<br \/>\n    std::string GetHeader(const std::string &amp;key)<br \/>\n    {<br \/>\n        auto it &#061; _headers.find(key);<br \/>\n        if (it &#061;&#061; _headers.end())<br \/>\n        {<br \/>\n            return &#034;&#034;;<br \/>\n        }<br \/>\n        return it-&gt;second;<br \/>\n    }<br \/>\n    void SetContent(const std::string &amp;body, const std::string &amp;type &#061; &#034;text\/html&#034;)<br \/>\n    {<br \/>\n        _body &#061; body;<br \/>\n        SetHeader(&#034;Content-Type&#034;, type);<br \/>\n    }<br \/>\n    void SetRedirect(const std::string &amp;url, int statu &#061; 302)<br \/>\n    {<br \/>\n        _statu &#061; statu;<br \/>\n        _redirect_flag &#061; true;<br \/>\n        _redirect_url &#061; url;<br \/>\n    }<br \/>\n    bool Close()<br \/>\n    {<br \/>\n        \/\/ \u6ca1\u6709Connection\u5b57\u6bb5\u6216\u8005\u6709Connection\u4f46\u662f\u503c\u662ffalse&#xff0c;\u5219\u90fd\u662f\u77ed\u8fde\u63a5&#xff0c;\u5426\u5219\u662f\u957f\u8fde\u63a5<br \/>\n        if (HasHeader(&#034;Connection&#034;) &#061;&#061; true &amp;&amp; GetHeader(&#034;Connection&#034;) &#061;&#061; &#034;keep-alive&#034;)<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"3.4%20HttpContext%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0\">3.4 HttpContext\u7c7b\u7684\u5b9e\u73b0<\/h3>\n<p>\u8fd9\u4e2a\u6a21\u5757\u662f\u4e00\u4e2aHTTP\u8bf7\u6c42\u63a5\u53d7\u7684\u4e0a\u4e0b\u6587\u6a21\u5757&#xff0c;\u4e3b\u8981\u662f\u4e3a\u4e86\u9632\u6b62\u518d\u4e00\u6b21\u63a5\u6536\u7684\u6570\u636e\u4e2d&#xff0c;\u4e0d\u662f\u4e00\u4e2a\u5b8c\u6574\u7684HTTP\u8bf7\u6c42&#xff0c;\u5219\u89e3\u6790\u8fc7\u7a0b\u5e76\u672a\u5b8c\u6210&#xff0c;\u65e0\u6cd5\u8fdb\u884c\u5b8c\u6574\u7684\u8bf7\u6c42\u5904\u7406&#xff0c;\u9700\u8981\u5728\u4e0b\u6b21\u63a5\u53d7\u5230\u65b0\u6570\u636e\u540e\u7ee7\u7eed\u6839\u636e\u4e0a\u4e0b\u6587\u8fdb\u884c\u89e3\u6790&#xff0c;\u6700\u7ec8\u5f97\u5230\u4e00\u4e2aHttpRequest\u8bf7\u6c42\u4fe1\u606f\u5bf9\u8c61&#xff0c;\u56e0\u6b64\u5728\u8bf7\u6c42\u6570\u636e\u7684\u63a5\u53d7\u4ee5\u53ca\u89e3\u6790\u90e8\u5206\u9700\u8981\u4e00\u4e2a\u4e0a\u4e0b\u6587\u6765\u8fdb\u884c\u63a7\u5236\u63a5\u6536\u548c\u5904\u7406\u8282\u594f<\/p>\n<p>\u9996\u5148\u63a5\u6536\u5bf9\u5e94\u591a\u79cd\u72b6\u6001\u7801&#xff0c;\u8fd9\u91cc\u51c6\u5907\u4e86\u4e94\u79cd<\/p>\n<p> typedef enum<br \/>\n{<br \/>\n    RECV_HTTP_ERROR,<br \/>\n    RECV_HTTP_LINE,<br \/>\n    RECV_HTTP_HEAD,<br \/>\n    RECV_HTTP_BODY,<br \/>\n    RECV_HTTP_OVER<br \/>\n} HttpRecvStatu; <\/p>\n<p>\u7136\u540e\u5c31\u662f\u8fd9\u4e2a\u7c7b\u5bf9\u5e94\u7684\u6210\u5458\u53d8\u91cf<\/p>\n<p> int _resp_statu;           \/\/ \u76f8\u5e94\u72b6\u6001\u7801<br \/>\nHttpRecvStatu _recv_statu; \/\/ \u5f53\u524d\u63a5\u6536\u53ca\u89e3\u6790\u7684\u9636\u6bb5\u72b6\u6001<br \/>\nHttpRequest _request;      \/\/ \u5df2\u7ecf\u89e3\u6790\u5f97\u5230\u7684\u8bf7\u6c42\u4fe1\u606f <\/p>\n<p>\u4e0b\u9762\u662f\u5176\u5bf9\u5e94\u7684\u6210\u5458\u51fd\u6570<\/p>\n<p> \u6211\u4eec\u9700\u8981\u5bf9\u8bf7\u6c42\u884c\u8fdb\u884c\u89e3\u6790&#xff0c;\u4f7f\u7528ParseHttpLine\u51fd\u6570&#xff0c;\u4f20\u5165\u7684\u53c2\u6570\u4e3astring\u7c7b\u578b\u7684\u8bf7\u6c42\u884c<\/p>\n<li>\u4f7f\u7528std::smatch\u6765\u5b58\u50a8\u6b63\u5219\u8868\u8fbe\u5f0f\u5339\u914d\u7ed3\u679c<\/li>\n<li>\u8bbe\u7f6e\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u5339\u914d\u89c4\u5219&#xff0c;\u524d\u6587\u5df2\u7ecf\u4ecb\u7ecd\u4e86\u5982\u4f55\u53bb\u5339\u914d\u8bf7\u6c42\u884c<\/li>\n<li>\u4f7f\u7528regex_match\u53bb\u5339\u914d&#xff0c;\u628a\u7ed3\u679c\u5b58\u50a8\u5728matches\u4e2d<\/li>\n<li>matches[0]\u5b58\u50a8\u7684\u662f\u539f\u59cb\u5b57\u7b26\u4e32&#xff0c;\u6240\u4ee5\u83b7\u53d6\u5176\u8bf7\u6c42\u65b9\u6cd5\u3001\u8d44\u6e90\u8def\u5f84\u3001\u67e5\u8be2\u5b57\u7b26\u4e32\u3001\u534f\u8bae\u7248\u672c\u5206\u522b\u8981\u5728matches\u76841 2 3 4\u83b7\u53d6<\/li>\n<p> bool ParseHttpLine(const std::string &amp;line)<br \/>\n{<br \/>\n    \/\/ std::cout &lt;&lt; &#034;string &#034; &lt;&lt; line &lt;&lt; std::endl;<br \/>\n    std::smatch matches;<br \/>\n    std::regex e(&#034;(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\\\\\\\?(.*))? (HTTP\/1\\\\\\\\.[01])(?:\\\\n|\\\\r\\\\n)?&#034;, std::regex::icase);<br \/>\n    bool ret &#061; std::regex_match(line, matches, e);<br \/>\n    if (ret &#061;&#061; false)<br \/>\n    {<br \/>\n        std::cout &lt;&lt; line &lt;&lt; std::endl;<br \/>\n        \/\/ std::cout &lt;&lt; &#034;ParseHttpLine 1 error&#034; &lt;&lt; std::endl;<br \/>\n        _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n        _resp_statu &#061; 400;<br \/>\n        return false;<br \/>\n    }<br \/>\n    \/\/ \u8bf7\u6c42\u65b9\u6cd5\u7684\u83b7\u53d6<br \/>\n    _request._method &#061; matches[1];<br \/>\n    std::transform(_request._method.begin(), _request._method.end(), _request._method.begin(), ::toupper);<br \/>\n    \/\/ \u8d44\u6e90\u8def\u5f84\u7684\u83b7\u53d6&#xff0c;\u9700\u8981\u8fdb\u884cURL\u89e3\u7801\u64cd\u4f5c&#xff0c;\u4f46\u662f\u4e0d\u9700\u8981&#043;\u8f6c\u7a7a\u683c<br \/>\n    _request._path &#061; Util::UrlDecode(matches[2], false);<br \/>\n    \/\/ \u534f\u8bae\u7248\u672c\u7684\u83b7\u53d6<br \/>\n    _request._version &#061; matches[4];<br \/>\n    \/\/ \u67e5\u8be2\u5b57\u7b26\u4e32\u7684\u8bfb\u53d6\u4e0e\u5904\u7406<br \/>\n    std::vector&lt;std::string&gt; query_string_arry;<br \/>\n    std::string query_string &#061; matches[3];<br \/>\n    \/\/ \u67e5\u8be2\u5b57\u7b26\u4e32\u7684\u683c\u5f0f key&#061;value&amp;key&#061;value&#8230; ,\u5148\u4ee5&amp;\u7b26\u53f7\u8fdb\u884c\u5206\u5272&#xff0c;\u5f97\u5230\u5404\u4e2a\u5b50\u4e32<br \/>\n    Util::Split(query_string, &#034;&amp;&#034;, &amp;query_string_arry);<br \/>\n    \/\/ \u9488\u5bf9\u5404\u4e2a\u5b50\u4e32&#xff0c;\u4ee5 &#061; \u7b26\u53f7\u8fdb\u884c\u5206\u5272&#xff0c;\u5f97\u5230key \u548c val&#xff0c;\u5f97\u5230\u4e4b\u540e\u4e5f\u9700\u8981\u8fdb\u884cURL\u89e3\u7801<br \/>\n    for (auto &amp;str : query_string_arry)<br \/>\n    {<br \/>\n        size_t pos &#061; str.find(&#034;&#061;&#034;);<br \/>\n        if (pos &#061;&#061; std::string::npos)<br \/>\n        {<br \/>\n            \/\/ \u6ca1\u6709\u627e\u5230<br \/>\n            \/\/ std::cout &lt;&lt; &#034;ParseHttpLine 2 error&#034; &lt;&lt; std::endl;<br \/>\n            _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n            _resp_statu &#061; 400;<br \/>\n            return false;<br \/>\n        }<br \/>\n        std::string key &#061; Util::UrlDecode(str.substr(0, pos), true);<br \/>\n        std::string val &#061; Util::UrlDecode(str.substr(pos &#043; 1), true);<br \/>\n        _request.SetParam(key, val);<br \/>\n    }<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u63a5\u6536\u8bf7\u6c42\u884c\u7684\u903b\u8f91\u8f83\u4e3a\u7b80\u5355&#xff0c;\u4e0d\u591a\u8d58\u8ff0<\/p>\n<p> bool RecvHttpLine(Buffer *buf)<br \/>\n{<br \/>\n    if (_recv_statu !&#061; RECV_HTTP_LINE)<br \/>\n        return false;<br \/>\n    \/\/ 1.\u83b7\u53d6\u4e00\u884c\u6570\u636e<br \/>\n    std::string line &#061; buf-&gt;GetLineAndPop();<br \/>\n    \/\/ std::cout &lt;&lt; line &lt;&lt; &#034; &#034; &lt;&lt; &#034;RecvHttpLine&#034; &lt;&lt; std::endl;<br \/>\n    \/\/  2.\u9700\u8981\u8003\u8651\u7684\u4e00\u4e9b\u8981\u7d20&#xff1a;\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u83b7\u53d6\u7684\u4e00\u884c\u6570\u636e\u8d85\u5927<br \/>\n    if (line.size() &#061;&#061; 0)<br \/>\n    {<br \/>\n        \/\/ \u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u5219\u9700\u8981\u5224\u65ad\u7f13\u51b2\u533a\u4e2d\u7684\u53ef\u8bfb\u6570\u636e\u957f\u5ea6&#xff0c;\u5982\u679c\u5f88\u957f\u4e86\u90fd\u4e0d\u8db3\u4e00\u884c&#xff0c;\u8fd9\u662f\u6709\u95ee\u9898\u7684<br \/>\n        if (buf-&gt;ReadAbleSize() &gt; MAX_LINE)<br \/>\n        {<br \/>\n            _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n            _resp_statu &#061; 414; \/\/ URI TOO LONG<br \/>\n            return false;<br \/>\n        }<br \/>\n        \/\/ \u7f13\u51b2\u533a\u4e2d\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u4f46\u662f\u4e5f\u4e0d\u591a&#xff0c;\u5c31\u7b49\u7b49\u65b0\u6570\u636e\u7684\u5230\u6765<br \/>\n        return true;<br \/>\n    }<br \/>\n    if (line.size() &gt; MAX_LINE)<br \/>\n    {<br \/>\n        _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n        _resp_statu &#061; 414; \/\/ URI TOO LONG<br \/>\n        return false;<br \/>\n    }<br \/>\n    bool ret &#061; ParseHttpLine(line);<br \/>\n    if (ret &#061;&#061; false)<br \/>\n    {<br \/>\n        return false;<br \/>\n    }<br \/>\n    \/\/ buf-&gt;MoveReadOffset(line.size());<br \/>\n    _recv_statu &#061; RECV_HTTP_HEAD;<br \/>\n    return true;<br \/>\n    \/\/ return ParseHttpLine(line);<br \/>\n} <\/p>\n<p>\u63a5\u53d7\u8bf7\u6c42\u5934&#xff0c;\u4e00\u884c\u4e00\u884c\u5730\u53d6\u51fakey:value\u7c7b\u578b\u7684\u6570\u636e&#xff0c;\u76f4\u5230\u9047\u5230\u7a7a\u884c\u505c\u6b62<\/p>\n<p> bool RecvHttpHead(Buffer *buf)<br \/>\n{<br \/>\n    if (_recv_statu !&#061; RECV_HTTP_HEAD)<br \/>\n        return false;<br \/>\n    \/\/ \u4e00\u884c\u4e00\u884c\u53d6\u51fa\u6570\u636e&#xff0c;\u76f4\u5230\u9047\u5230\u7a7a\u884c\u4e3a\u6b62<br \/>\n    \/\/ \u5e76\u4e14\u5934\u90e8\u7684\u683c\u5f0f\u4e3akey:val\\\\r\\\\nkey:val\\\\r\\\\n<br \/>\n    while (1)<br \/>\n    {<br \/>\n        \/\/  1.\u83b7\u53d6\u4e00\u884c\u6570\u636e<br \/>\n        std::string line &#061; buf-&gt;GetLineAndPop();<br \/>\n        \/\/ std::cout &lt;&lt; &#034;RecvHttpHead &#034; &lt;&lt; line &lt;&lt; std::endl;<br \/>\n        \/\/  2.\u9700\u8981\u8003\u8651\u7684\u4e00\u4e9b\u8981\u7d20&#xff1a;\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u83b7\u53d6\u7684\u4e00\u884c\u6570\u636e\u8d85\u5927<br \/>\n        if (line.size() &#061;&#061; 0)<br \/>\n        {<br \/>\n            \/\/ \u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u5219\u9700\u8981\u5224\u65ad\u7f13\u51b2\u533a\u4e2d\u7684\u53ef\u8bfb\u6570\u636e\u957f\u5ea6&#xff0c;\u5982\u679c\u5f88\u957f\u4e86\u90fd\u4e0d\u8db3\u4e00\u884c&#xff0c;\u8fd9\u662f\u6709\u95ee\u9898\u7684<br \/>\n            if (buf-&gt;ReadAbleSize() &gt; MAX_LINE)<br \/>\n            {<br \/>\n                _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n                _resp_statu &#061; 414; \/\/ URI TOO LONG<br \/>\n                return false;<br \/>\n            }<br \/>\n            \/\/ \u7f13\u51b2\u533a\u4e2d\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u4f46\u662f\u4e5f\u4e0d\u591a&#xff0c;\u5c31\u7b49\u7b49\u65b0\u6570\u636e\u7684\u5230\u6765<br \/>\n            return true;<br \/>\n        }<br \/>\n        if (line.size() &gt; MAX_LINE)<br \/>\n        {<br \/>\n            _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n            _resp_statu &#061; 414; \/\/ URI TOO LONG<br \/>\n            return false;<br \/>\n        }<br \/>\n        if (line &#061;&#061; &#034;\\\\n&#034; || line &#061;&#061; &#034;\\\\r\\\\n&#034;)<br \/>\n        {<br \/>\n            break;<br \/>\n        }<br \/>\n        bool ret &#061; ParseHttpHead(line);<br \/>\n        if (ret &#061;&#061; false)<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n    }<br \/>\n    _recv_statu &#061; RECV_HTTP_BODY;<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u89e3\u6790\u8bf7\u6c42\u5934&#xff0c;\u628a\u5192\u53f7\u52a0\u7a7a\u683c&#xff08;: &#xff09;\u4f5c\u4e3a\u5206\u9694\u7b26\u53bb\u627e\u5176key\u548cvalue\u503c&#xff0c;\u5e76\u8fdb\u884c\u5b58\u50a8<\/p>\n<p> bool ParseHttpHead(std::string &amp;line)<br \/>\n{<br \/>\n    if (line.back() &#061;&#061; &#039;\\\\n&#039;)<br \/>\n        line.pop_back(); \/\/ \u672b\u5c3e\u662f\u6362\u884c&#xff0c;\u5219\u53bb\u6389<br \/>\n    if (line.back() &#061;&#061; &#039;\\\\r&#039;)<br \/>\n        line.pop_back(); \/\/ \u6709\u56de\u8f66&#xff0c;\u5219\u53bb\u6389<br \/>\n    size_t pos &#061; line.find(&#034;: &#034;);<br \/>\n    if (pos &#061;&#061; std::string::npos)<br \/>\n    {<br \/>\n        \/\/ std::cout &lt;&lt; &#034;ParseHttpHead error&#034; &lt;&lt; std::endl;<br \/>\n        _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n        _resp_statu &#061; 400;<br \/>\n        return false;<br \/>\n    }<br \/>\n    std::string key &#061; line.substr(0, pos);<br \/>\n    std::string val &#061; line.substr(pos &#043; 2);<br \/>\n    _request.SetHeader(key, val);<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u63a5\u6536\u6b63\u6587\u90e8\u5206&#xff0c;\u4e3b\u8981\u5206\u4e3a\u4e09\u6b65<\/p>\n<li>\u63a5\u6536\u6b63\u6587\u957f\u5ea6<\/li>\n<li>\u83b7\u53d6\u5f53\u524d\u5df2\u7ecf\u63a5\u6536\u4e86\u591a\u5c11\u6b63\u6587<\/li>\n<li>\u63a5\u6536\u6b63\u6587\u653e\u5230body\u4e2d<\/li>\n<p> bool ParseHttpHead(std::string &amp;line)<br \/>\n{<br \/>\n    if (line.back() &#061;&#061; &#039;\\\\n&#039;)<br \/>\n        line.pop_back(); \/\/ \u672b\u5c3e\u662f\u6362\u884c&#xff0c;\u5219\u53bb\u6389<br \/>\n    if (line.back() &#061;&#061; &#039;\\\\r&#039;)<br \/>\n        line.pop_back(); \/\/ \u6709\u56de\u8f66&#xff0c;\u5219\u53bb\u6389<br \/>\n    size_t pos &#061; line.find(&#034;: &#034;);<br \/>\n    if (pos &#061;&#061; std::string::npos)<br \/>\n    {<br \/>\n        \/\/ std::cout &lt;&lt; &#034;ParseHttpHead error&#034; &lt;&lt; std::endl;<br \/>\n        _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n        _resp_statu &#061; 400;<br \/>\n        return false;<br \/>\n    }<br \/>\n    std::string key &#061; line.substr(0, pos);<br \/>\n    std::string val &#061; line.substr(pos &#043; 2);<br \/>\n    _request.SetHeader(key, val);<br \/>\n    return true;<br \/>\n}<br \/>\nbool RecvHttpBody(Buffer *buf)<br \/>\n{<br \/>\n    if (_recv_statu !&#061; RECV_HTTP_BODY)<br \/>\n        return false;<br \/>\n    \/\/ 1.\u83b7\u53d6\u6b63\u6587\u957f\u5ea6<br \/>\n    size_t content_length &#061; _request.ContentLength();<br \/>\n    if (content_length &#061;&#061; 0)<br \/>\n    {<br \/>\n        \/\/ \u6ca1\u6709\u6b63\u6587&#xff0c;\u5219\u8bf7\u6c42\u63a5\u6536\u8bf7\u6c42\u5b8c\u6bd5<br \/>\n        _recv_statu &#061; RECV_HTTP_OVER;<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ 2.\u5f53\u524d\u5df2\u7ecf\u63a5\u6536\u4e86\u591a\u5c11\u6b63\u6587&#xff0c;\u5176\u5b9e\u5c31\u662f\u5f80_request._body\u4e2d\u653e\u4e86\u591a\u5c11\u6570\u636e<br \/>\n    size_t real_len &#061; content_length &#8211; _request._body.size(); \/\/ \u5b9e\u9645\u8fd8\u9700\u8981\u63a5\u53d7\u7684\u6b63\u6587\u957f\u5ea6<br \/>\n    \/\/ 3.\u63a5\u6536\u6b63\u6587\u653e\u5230body\u4e2d&#xff0c;\u4f46\u662f\u4e5f\u8981\u8003\u8651\u5f53\u524d\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u662f\u5426\u662f\u5168\u90e8\u7684\u6b63\u6587<br \/>\n    \/\/ 3.1\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e&#xff0c;\u5305\u542b\u4e86\u5f53\u524d\u8bf7\u6c42\u7684\u6240\u6709\u6b63\u6587&#xff0c;\u53d6\u51fa\u6240\u9700\u7684\u6570\u636e<br \/>\n    if (buf-&gt;ReadAbleSize() &gt;&#061; real_len)<br \/>\n    {<br \/>\n        _request._body.append(buf-&gt;ReadPosition(), real_len);<br \/>\n        buf-&gt;MoveReadOffset(real_len);<br \/>\n        _recv_statu &#061; RECV_HTTP_OVER;<br \/>\n        return true;<br \/>\n    }<\/p>\n<p>    \/\/ 3.2\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e&#xff0c;\u65e0\u6cd5\u6ee1\u8db3\u5f53\u524d\u6b63\u6587\u7684\u9700\u8981&#xff0c;\u6570\u636e\u4e0d\u8db3&#xff0c;\u53d6\u51fa\u6570\u636e&#xff0c;\u7136\u540e\u7b49\u5f85\u65b0\u6570\u636e\u5230\u6765<br \/>\n    _request._body.append(buf-&gt;ReadPosition(), buf-&gt;ReadAbleSize());<br \/>\n    buf-&gt;MoveReadOffset(buf-&gt;ReadAbleSize());<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u63a5\u6536\u5e76\u89e3\u6790Http\u8bf7\u6c42&#xff0c;\u6211\u4eec\u4f7f\u7528RecvHttpRequest\u51fd\u6570&#xff0c;\u7136\u540e\u4f7f\u7528switch\u5173\u952e\u5b57&#xff0c;\u901a\u8fc7\u72b6\u6001\u7801\u6765\u5224\u65ad\u505a\u4ec0\u4e48\u4e8b\u60c5<\/p>\n<p> void RecvHttpRequest(Buffer *buf)<br \/>\n{<br \/>\n    \/\/ buf-&gt;TestPrint();<br \/>\n    \/\/  \u4e0d\u540c\u7684\u72b6\u6001&#xff0c;\u505a\u4e0d\u540c\u7684\u4e8b\u60c5<br \/>\n    \/\/  \u4e0d\u9700\u8981\u52a0\u5165break&#xff0c;\u5b8c\u6210\u4e00\u6b65\u540e\u76f4\u63a5\u8fdb\u884c\u4e0b\u4e00\u6b65<br \/>\n    switch (_recv_statu)<br \/>\n    {<br \/>\n    case RECV_HTTP_LINE:<br \/>\n        RecvHttpLine(buf);<br \/>\n    case RECV_HTTP_HEAD:<br \/>\n        RecvHttpHead(buf);<br \/>\n    case RECV_HTTP_BODY:<br \/>\n        RecvHttpBody(buf);<br \/>\n    }<br \/>\n    return;<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662f\u5168\u90e8\u4ee3\u7801<\/p>\n<p> typedef enum<br \/>\n{<br \/>\n    RECV_HTTP_ERROR,<br \/>\n    RECV_HTTP_LINE,<br \/>\n    RECV_HTTP_HEAD,<br \/>\n    RECV_HTTP_BODY,<br \/>\n    RECV_HTTP_OVER<br \/>\n} HttpRecvStatu;<\/p>\n<p>#define MAX_LINE 8192 \/\/ \u901a\u5e38\u8bbe\u7f6e\u4e3a8kb<br \/>\nclass HttpContext<br \/>\n{<br \/>\nprivate:<br \/>\n    int _resp_statu;           \/\/ \u76f8\u5e94\u72b6\u6001\u7801<br \/>\n    HttpRecvStatu _recv_statu; \/\/ \u5f53\u524d\u63a5\u6536\u53ca\u89e3\u6790\u7684\u9636\u6bb5\u72b6\u6001<br \/>\n    HttpRequest _request;      \/\/ \u5df2\u7ecf\u89e3\u6790\u5f97\u5230\u7684\u8bf7\u6c42\u4fe1\u606f<br \/>\nprivate:<br \/>\n    \/\/ \u89e3\u6790\u8bf7\u6c42\u884c<br \/>\n    bool ParseHttpLine(const std::string &amp;line)<br \/>\n    {<br \/>\n        \/\/ std::cout &lt;&lt; &#034;string &#034; &lt;&lt; line &lt;&lt; std::endl;<br \/>\n        std::smatch matches;<br \/>\n        std::regex e(&#034;(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\\\\\\\?(.*))? (HTTP\/1\\\\\\\\.[01])(?:\\\\n|\\\\r\\\\n)?&#034;, std::regex::icase);<br \/>\n        bool ret &#061; std::regex_match(line, matches, e);<br \/>\n        if (ret &#061;&#061; false)<br \/>\n        {<br \/>\n            std::cout &lt;&lt; line &lt;&lt; std::endl;<br \/>\n            \/\/ std::cout &lt;&lt; &#034;ParseHttpLine 1 error&#034; &lt;&lt; std::endl;<br \/>\n            _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n            _resp_statu &#061; 400;<br \/>\n            return false;<br \/>\n        }<br \/>\n        \/\/ \u8bf7\u6c42\u65b9\u6cd5\u7684\u83b7\u53d6<br \/>\n        _request._method &#061; matches[1];<br \/>\n        std::transform(_request._method.begin(), _request._method.end(), _request._method.begin(), ::toupper);<br \/>\n        \/\/ \u8d44\u6e90\u8def\u5f84\u7684\u83b7\u53d6&#xff0c;\u9700\u8981\u8fdb\u884cURL\u89e3\u7801\u64cd\u4f5c&#xff0c;\u4f46\u662f\u4e0d\u9700\u8981&#043;\u8f6c\u7a7a\u683c<br \/>\n        _request._path &#061; Util::UrlDecode(matches[2], false);<br \/>\n        \/\/ \u534f\u8bae\u7248\u672c\u7684\u83b7\u53d6<br \/>\n        _request._version &#061; matches[4];<br \/>\n        \/\/ \u67e5\u8be2\u5b57\u7b26\u4e32\u7684\u8bfb\u53d6\u4e0e\u5904\u7406<br \/>\n        std::vector&lt;std::string&gt; query_string_arry;<br \/>\n        std::string query_string &#061; matches[3];<br \/>\n        \/\/ \u67e5\u8be2\u5b57\u7b26\u4e32\u7684\u683c\u5f0f key&#061;value&amp;key&#061;value&#8230; ,\u5148\u4ee5&amp;\u7b26\u53f7\u8fdb\u884c\u5206\u5272&#xff0c;\u5f97\u5230\u5404\u4e2a\u5b50\u4e32<br \/>\n        Util::Split(query_string, &#034;&amp;&#034;, &amp;query_string_arry);<br \/>\n        \/\/ \u9488\u5bf9\u5404\u4e2a\u5b50\u4e32&#xff0c;\u4ee5 &#061; \u7b26\u53f7\u8fdb\u884c\u5206\u5272&#xff0c;\u5f97\u5230key \u548c val&#xff0c;\u5f97\u5230\u4e4b\u540e\u4e5f\u9700\u8981\u8fdb\u884cURL\u89e3\u7801<br \/>\n        for (auto &amp;str : query_string_arry)<br \/>\n        {<br \/>\n            size_t pos &#061; str.find(&#034;&#061;&#034;);<br \/>\n            if (pos &#061;&#061; std::string::npos)<br \/>\n            {<br \/>\n                \/\/ \u6ca1\u6709\u627e\u5230<br \/>\n                \/\/ std::cout &lt;&lt; &#034;ParseHttpLine 2 error&#034; &lt;&lt; std::endl;<br \/>\n                _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n                _resp_statu &#061; 400;<br \/>\n                return false;<br \/>\n            }<br \/>\n            std::string key &#061; Util::UrlDecode(str.substr(0, pos), true);<br \/>\n            std::string val &#061; Util::UrlDecode(str.substr(pos &#043; 1), true);<br \/>\n            _request.SetParam(key, val);<br \/>\n        }<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ \u63a5\u6536\u8bf7\u6c42\u884c<br \/>\n    bool RecvHttpLine(Buffer *buf)<br \/>\n    {<br \/>\n        if (_recv_statu !&#061; RECV_HTTP_LINE)<br \/>\n            return false;<br \/>\n        \/\/ 1.\u83b7\u53d6\u4e00\u884c\u6570\u636e<br \/>\n        std::string line &#061; buf-&gt;GetLineAndPop();<br \/>\n        \/\/ std::cout &lt;&lt; line &lt;&lt; &#034; &#034; &lt;&lt; &#034;RecvHttpLine&#034; &lt;&lt; std::endl;<br \/>\n        \/\/  2.\u9700\u8981\u8003\u8651\u7684\u4e00\u4e9b\u8981\u7d20&#xff1a;\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u83b7\u53d6\u7684\u4e00\u884c\u6570\u636e\u8d85\u5927<br \/>\n        if (line.size() &#061;&#061; 0)<br \/>\n        {<br \/>\n            \/\/ \u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u5219\u9700\u8981\u5224\u65ad\u7f13\u51b2\u533a\u4e2d\u7684\u53ef\u8bfb\u6570\u636e\u957f\u5ea6&#xff0c;\u5982\u679c\u5f88\u957f\u4e86\u90fd\u4e0d\u8db3\u4e00\u884c&#xff0c;\u8fd9\u662f\u6709\u95ee\u9898\u7684<br \/>\n            if (buf-&gt;ReadAbleSize() &gt; MAX_LINE)<br \/>\n            {<br \/>\n                _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n                _resp_statu &#061; 414; \/\/ URI TOO LONG<br \/>\n                return false;<br \/>\n            }<br \/>\n            \/\/ \u7f13\u51b2\u533a\u4e2d\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u4f46\u662f\u4e5f\u4e0d\u591a&#xff0c;\u5c31\u7b49\u7b49\u65b0\u6570\u636e\u7684\u5230\u6765<br \/>\n            return true;<br \/>\n        }<br \/>\n        if (line.size() &gt; MAX_LINE)<br \/>\n        {<br \/>\n            _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n            _resp_statu &#061; 414; \/\/ URI TOO LONG<br \/>\n            return false;<br \/>\n        }<br \/>\n        bool ret &#061; ParseHttpLine(line);<br \/>\n        if (ret &#061;&#061; false)<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        \/\/ buf-&gt;MoveReadOffset(line.size());<br \/>\n        _recv_statu &#061; RECV_HTTP_HEAD;<br \/>\n        return true;<br \/>\n        \/\/ return ParseHttpLine(line);<br \/>\n    }<br \/>\n    bool RecvHttpHead(Buffer *buf)<br \/>\n    {<br \/>\n        if (_recv_statu !&#061; RECV_HTTP_HEAD)<br \/>\n            return false;<br \/>\n        \/\/ \u4e00\u884c\u4e00\u884c\u53d6\u51fa\u6570\u636e&#xff0c;\u76f4\u5230\u9047\u5230\u7a7a\u884c\u4e3a\u6b62<br \/>\n        \/\/ \u5e76\u4e14\u5934\u90e8\u7684\u683c\u5f0f\u4e3akey:val\\\\r\\\\nkey:val\\\\r\\\\n<br \/>\n        while (1)<br \/>\n        {<br \/>\n            \/\/  1.\u83b7\u53d6\u4e00\u884c\u6570\u636e<br \/>\n            std::string line &#061; buf-&gt;GetLineAndPop();<br \/>\n            \/\/ std::cout &lt;&lt; &#034;RecvHttpHead &#034; &lt;&lt; line &lt;&lt; std::endl;<br \/>\n            \/\/  2.\u9700\u8981\u8003\u8651\u7684\u4e00\u4e9b\u8981\u7d20&#xff1a;\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u83b7\u53d6\u7684\u4e00\u884c\u6570\u636e\u8d85\u5927<br \/>\n            if (line.size() &#061;&#061; 0)<br \/>\n            {<br \/>\n                \/\/ \u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u5219\u9700\u8981\u5224\u65ad\u7f13\u51b2\u533a\u4e2d\u7684\u53ef\u8bfb\u6570\u636e\u957f\u5ea6&#xff0c;\u5982\u679c\u5f88\u957f\u4e86\u90fd\u4e0d\u8db3\u4e00\u884c&#xff0c;\u8fd9\u662f\u6709\u95ee\u9898\u7684<br \/>\n                if (buf-&gt;ReadAbleSize() &gt; MAX_LINE)<br \/>\n                {<br \/>\n                    _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n                    _resp_statu &#061; 414; \/\/ URI TOO LONG<br \/>\n                    return false;<br \/>\n                }<br \/>\n                \/\/ \u7f13\u51b2\u533a\u4e2d\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u4f46\u662f\u4e5f\u4e0d\u591a&#xff0c;\u5c31\u7b49\u7b49\u65b0\u6570\u636e\u7684\u5230\u6765<br \/>\n                return true;<br \/>\n            }<br \/>\n            if (line.size() &gt; MAX_LINE)<br \/>\n            {<br \/>\n                _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n                _resp_statu &#061; 414; \/\/ URI TOO LONG<br \/>\n                return false;<br \/>\n            }<br \/>\n            if (line &#061;&#061; &#034;\\\\n&#034; || line &#061;&#061; &#034;\\\\r\\\\n&#034;)<br \/>\n            {<br \/>\n                break;<br \/>\n            }<br \/>\n            bool ret &#061; ParseHttpHead(line);<br \/>\n            if (ret &#061;&#061; false)<br \/>\n            {<br \/>\n                return false;<br \/>\n            }<br \/>\n        }<br \/>\n        _recv_statu &#061; RECV_HTTP_BODY;<br \/>\n        return true;<br \/>\n    }<br \/>\n    bool ParseHttpHead(std::string &amp;line)<br \/>\n    {<br \/>\n        if (line.back() &#061;&#061; &#039;\\\\n&#039;)<br \/>\n            line.pop_back(); \/\/ \u672b\u5c3e\u662f\u6362\u884c&#xff0c;\u5219\u53bb\u6389<br \/>\n        if (line.back() &#061;&#061; &#039;\\\\r&#039;)<br \/>\n            line.pop_back(); \/\/ \u6709\u56de\u8f66&#xff0c;\u5219\u53bb\u6389<br \/>\n        size_t pos &#061; line.find(&#034;: &#034;);<br \/>\n        if (pos &#061;&#061; std::string::npos)<br \/>\n        {<br \/>\n            \/\/ std::cout &lt;&lt; &#034;ParseHttpHead error&#034; &lt;&lt; std::endl;<br \/>\n            _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n            _resp_statu &#061; 400;<br \/>\n            return false;<br \/>\n        }<br \/>\n        std::string key &#061; line.substr(0, pos);<br \/>\n        std::string val &#061; line.substr(pos &#043; 2);<br \/>\n        _request.SetHeader(key, val);<br \/>\n        return true;<br \/>\n    }<br \/>\n    bool RecvHttpBody(Buffer *buf)<br \/>\n    {<br \/>\n        if (_recv_statu !&#061; RECV_HTTP_BODY)<br \/>\n            return false;<br \/>\n        \/\/ 1.\u83b7\u53d6\u6b63\u6587\u957f\u5ea6<br \/>\n        size_t content_length &#061; _request.ContentLength();<br \/>\n        if (content_length &#061;&#061; 0)<br \/>\n        {<br \/>\n            \/\/ \u6ca1\u6709\u6b63\u6587&#xff0c;\u5219\u8bf7\u6c42\u63a5\u6536\u8bf7\u6c42\u5b8c\u6bd5<br \/>\n            _recv_statu &#061; RECV_HTTP_OVER;<br \/>\n            return true;<br \/>\n        }<br \/>\n        \/\/ 2.\u5f53\u524d\u5df2\u7ecf\u63a5\u6536\u4e86\u591a\u5c11\u6b63\u6587&#xff0c;\u5176\u5b9e\u5c31\u662f\u5f80_request._body\u4e2d\u653e\u4e86\u591a\u5c11\u6570\u636e<br \/>\n        size_t real_len &#061; content_length &#8211; _request._body.size(); \/\/ \u5b9e\u9645\u8fd8\u9700\u8981\u63a5\u53d7\u7684\u6b63\u6587\u957f\u5ea6<br \/>\n        \/\/ 3.\u63a5\u6536\u6b63\u6587\u653e\u5230body\u4e2d&#xff0c;\u4f46\u662f\u4e5f\u8981\u8003\u8651\u5f53\u524d\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u662f\u5426\u662f\u5168\u90e8\u7684\u6b63\u6587<br \/>\n        \/\/ 3.1\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e&#xff0c;\u5305\u542b\u4e86\u5f53\u524d\u8bf7\u6c42\u7684\u6240\u6709\u6b63\u6587&#xff0c;\u53d6\u51fa\u6240\u9700\u7684\u6570\u636e<br \/>\n        if (buf-&gt;ReadAbleSize() &gt;&#061; real_len)<br \/>\n        {<br \/>\n            _request._body.append(buf-&gt;ReadPosition(), real_len);<br \/>\n            buf-&gt;MoveReadOffset(real_len);<br \/>\n            _recv_statu &#061; RECV_HTTP_OVER;<br \/>\n            return true;<br \/>\n        }<\/p>\n<p>        \/\/ 3.2\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e&#xff0c;\u65e0\u6cd5\u6ee1\u8db3\u5f53\u524d\u6b63\u6587\u7684\u9700\u8981&#xff0c;\u6570\u636e\u4e0d\u8db3&#xff0c;\u53d6\u51fa\u6570\u636e&#xff0c;\u7136\u540e\u7b49\u5f85\u65b0\u6570\u636e\u5230\u6765<br \/>\n        _request._body.append(buf-&gt;ReadPosition(), buf-&gt;ReadAbleSize());<br \/>\n        buf-&gt;MoveReadOffset(buf-&gt;ReadAbleSize());<br \/>\n        return true;<br \/>\n    }<\/p>\n<p>public:<br \/>\n    HttpContext()<br \/>\n        : _resp_statu(200),<br \/>\n          _recv_statu(RECV_HTTP_LINE)<br \/>\n    {<br \/>\n    }<br \/>\n    void ReSet()<br \/>\n    {<br \/>\n        _resp_statu &#061; 200;<br \/>\n        _recv_statu &#061; RECV_HTTP_LINE;<br \/>\n        _request.ReSet();<br \/>\n    }<br \/>\n    int RespStatu()<br \/>\n    {<br \/>\n        return _resp_statu;<br \/>\n    }<br \/>\n    HttpRecvStatu RecvStatu()<br \/>\n    {<br \/>\n        return _recv_statu;<br \/>\n    }<br \/>\n    HttpRequest &amp;Request()<br \/>\n    {<br \/>\n        return _request;<br \/>\n    }<br \/>\n    \/\/ \u63a5\u6536\u5e76\u89e3\u6790Http\u8bf7\u6c42<br \/>\n    void RecvHttpRequest(Buffer *buf)<br \/>\n    {<br \/>\n        \/\/ buf-&gt;TestPrint();<br \/>\n        \/\/  \u4e0d\u540c\u7684\u72b6\u6001&#xff0c;\u505a\u4e0d\u540c\u7684\u4e8b\u60c5<br \/>\n        \/\/  \u4e0d\u9700\u8981\u52a0\u5165break&#xff0c;\u5b8c\u6210\u4e00\u6b65\u540e\u76f4\u63a5\u8fdb\u884c\u4e0b\u4e00\u6b65<br \/>\n        switch (_recv_statu)<br \/>\n        {<br \/>\n        case RECV_HTTP_LINE:<br \/>\n            RecvHttpLine(buf);<br \/>\n        case RECV_HTTP_HEAD:<br \/>\n            RecvHttpHead(buf);<br \/>\n        case RECV_HTTP_BODY:<br \/>\n            RecvHttpBody(buf);<br \/>\n        }<br \/>\n        return;<br \/>\n    }<br \/>\n}; <\/p>\n<h3 id=\"3.5%20HttpServer%E7%B1%BB%E7%9A%84%E5%AE%9E%E7%8E%B0\">3.5 HttpServer\u7c7b\u7684\u5b9e\u73b0<\/h3>\n<ul>\n<li>\u8fd9\u4e2a\u6a21\u5757\u65f6\u6700\u7ec8\u7ed9\u7ec4\u4ef6\u4f7f\u7528\u8005\u63d0\u4f9b\u7684HTTP\u670d\u52a1\u5668\u6a21\u5757&#xff0c;\u7528\u7b80\u5355\u7684\u63a5\u53e3\u5b9e\u73b0HTTP\u670d\u52a1\u5668\u7684\u642d\u5efa<\/li>\n<li>HttpServer\u6a21\u5757\u5185\u90e8\u5305\u542b\u6709\u4e00\u4e2aTcpServer\u5bf9\u8c61&#xff1a;TcpServer\u5bf9\u8c61\u5b9e\u73b0\u670d\u52a1\u5668\u7684\u642d\u5efa<\/li>\n<li>HttpServer\u6a21\u5757\u5185\u90e8\u5305\u542b\u6709\u4e24\u4e2a\u63d0\u4f9b\u7ed9TcpServer\u5bf9\u8c61\u7684\u63a5\u53e3&#xff1a;\u8fde\u63a5\u5efa\u7acb\u6210\u529f\u8bbe\u7f6e\u4e0a\u4e0b\u6587\u63a5\u53e3&#xff0c;\u6570\u636e\u5904\u7406\u63a5\u53e3<\/li>\n<li>HttpServer\u6a21\u5757\u5185\u90e8\u5305\u542b\u6709\u4e00\u4e2ahash-map\u8868\u5b58\u50a8\u8bf7\u6c42\u4e8e\u5904\u7406\u51fd\u6570\u7684\u6620\u5c04\u8868&#xff1a;\u7ec4\u4ef6\u4f7f\u7528\u8005\u5411HttpServer\u8bbe\u7f6e\u90a3\u4e9b\u8bf7\u6c42\u5e94\u8be5\u4f7f\u7528\u90a3\u4e9b\u51fd\u6570\u8fdb\u884c\u5904\u7406&#xff0c;\u7b49TcpServer\u6536\u5230\u5bf9\u5e94\u7684\u8bf7\u6c42\u5c31\u4f1a\u4f7f\u7528\u5bf9\u5e94\u7684\u51fd\u6570\u8fdb\u884c\u5b9e\u73b0<\/li>\n<\/ul>\n<p>\u9996\u5148\u662f\u5176\u6210\u5458\u53d8\u91cf<\/p>\n<p> using Handler &#061; std::function&lt;void(const HttpRequest &amp;, HttpResponse *)&gt;;<br \/>\nusing Handlers &#061; std::vector&lt;std::pair&lt;std::regex, Handler&gt;&gt;;<br \/>\nHandlers _get_route;<br \/>\nHandlers _post_route;<br \/>\nHandlers _put_route;<br \/>\nHandlers _delete_route;<br \/>\nstd::string _basedir; \/\/ \u9759\u6001\u8d44\u6e90\u6839\u76ee\u5f55<br \/>\nTcpServer _server; <\/p>\n<p>\u7136\u540e\u5c31\u662f\u5176\u6210\u5458\u51fd\u6570<\/p>\n<p> \u5173\u4e8e\u5bf9\u9519\u8bef\u7684\u5904\u7406ErrorHandler&#xff0c;\u6211\u4eec\u4f7f\u7528\u7b80\u5355\u7684Html\u5199\u4e00\u4e2a\u9875\u9762\u653e\u5230string\u4e2d&#xff0c;\u7136\u540e\u653e\u5165rsp\u5373\u53ef<\/p>\n<p> void ErrorHandler(const HttpRequest &amp;req, HttpResponse *rsp)<br \/>\n{<br \/>\n    \/\/ 1.\u7ec4\u7ec7\u4e00\u4e2a\u9519\u8bef\u5c55\u793a\u9875\u9762<br \/>\n    std::string body;<br \/>\n    body &#043;&#061; &#034;&lt;html&gt;&#034;;<br \/>\n    body &#043;&#061; &#034;&lt;head&gt;&#034;;<br \/>\n    body &#043;&#061; &#034;&lt;meta http-equiv&#061;&#039;Content-Type&#039; content&#061;&#039;text\/html;charset&#061;utf-8&#039;&gt;&#034;;<br \/>\n    body &#043;&#061; &#034;&lt;\/head&gt;&#034;;<br \/>\n    body &#043;&#061; &#034;&lt;body&gt;&#034;;<br \/>\n    body &#043;&#061; &#034;&lt;h1&gt;&#034;;<br \/>\n    body &#043;&#061; std::to_string(rsp-&gt;_statu);<br \/>\n    body &#043;&#061; &#034; &#034;;<br \/>\n    body &#043;&#061; Util::StatuDesc(rsp-&gt;_statu);<br \/>\n    body &#043;&#061; &#034;&lt;\/h1&gt;&#034;;<br \/>\n    body &#043;&#061; &#034;&lt;\/body&gt;&#034;;<br \/>\n    body &#043;&#061; &#034;&lt;\/html&gt;&#034;;<br \/>\n    \/\/ 2.\u5c06\u9875\u9762\u6570\u636e&#xff0c;\u5f53\u505a\u54cd\u5e94\u6b63\u6587&#xff0c;\u653e\u5165rsp\u4e2d<br \/>\n    rsp-&gt;SetContent(body, &#034;text\/html&#034;);<br \/>\n} <\/p>\n<p>\u5c06HttpResponse\u4e2d\u7684\u8981\u7d20\u6309\u7167http\u534f\u8bae\u683c\u5f0f\u8fdb\u884c\u7ec4\u7ec7\u53d1\u9001<\/p>\n<p> void WriteResponse(const PtrConnection &amp;conn, const HttpRequest &amp;req, HttpResponse &amp;rsp)<br \/>\n{<br \/>\n    \/\/ 1.\u5148\u5b8c\u5584\u5934\u90e8\u5b57\u6bb5<br \/>\n    \/\/ req\u662fconst&#xff0c;\u8c03\u7528\u7684Close\u4e5f\u5fc5\u987b\u662fconst\u7c7b\u578b<br \/>\n    if (req.Close() &#061;&#061; true)<br \/>\n    {<br \/>\n        rsp.SetHeader(&#034;Connection&#034;, &#034;close&#034;);<br \/>\n    }<br \/>\n    else<br \/>\n    {<br \/>\n        rsp.SetHeader(&#034;Connection&#034;, &#034;keep-alive&#034;);<br \/>\n    }<br \/>\n    if (rsp._body.empty() &#061;&#061; false &amp;&amp; rsp.HasHeader(&#034;Content-Length&#034;) &#061;&#061; false)<br \/>\n    {<br \/>\n        rsp.SetHeader(&#034;Content-Length&#034;, std::to_string(rsp._body.size()));<br \/>\n    }<br \/>\n    if (rsp._body.empty() &#061;&#061; false &amp;&amp; rsp.HasHeader(&#034;Content-Type&#034;) &#061;&#061; false)<br \/>\n    {<br \/>\n        rsp.SetHeader(&#034;Content-Type&#034;, &#034;application\/octet-stream&#034;); \/\/ \u4e8c\u8fdb\u5236\u6d41<br \/>\n    }<br \/>\n    if (rsp._redirect_flag &#061;&#061; true)<br \/>\n    {<br \/>\n        rsp.SetHeader(&#034;Location&#034;, rsp._redirect_url);<br \/>\n    }<br \/>\n    \/\/ 2.\u5c06rsp\u7684\u8981\u7d20&#xff0c;\u6309\u7167http\u534f\u8bae\u8fdb\u884c\u7ec4\u7ec7<br \/>\n    std::stringstream rsp_str;<br \/>\n    rsp_str &lt;&lt; req._version &lt;&lt; &#034; &#034; &lt;&lt; std::to_string(rsp._statu) &lt;&lt; &#034; &#034; &lt;&lt; Util::StatuDesc(rsp._statu) &lt;&lt; &#034;\\\\r\\\\n&#034;;<br \/>\n    for (auto &amp;head : rsp._headers)<br \/>\n    {<br \/>\n        rsp_str &lt;&lt; head.first &lt;&lt; &#034;:&#034; &lt;&lt; head.second &lt;&lt; &#034;\\\\r\\\\n&#034;;<br \/>\n    }<br \/>\n    rsp_str &lt;&lt; &#034;\\\\r\\\\n&#034;;<br \/>\n    rsp_str &lt;&lt; rsp._body;<br \/>\n    \/\/ 3.\u53d1\u9001\u6570\u636e<br \/>\n    conn-&gt;Send(rsp_str.str().c_str(), rsp_str.str().size());<br \/>\n} <\/p>\n<p>\u5224\u65ad\u662f\u5426\u4e3a\u9759\u6001\u8d44\u6e90&#xff0c;\u5206\u4e3a\u56db\u4e2a\u6b65\u9aa4<\/p>\n<p> bool IsFileHandler(const HttpRequest &amp;req)<br \/>\n{<br \/>\n    \/\/ 1.\u5fc5\u987b\u8bbe\u7f6e\u4e86\u9759\u6001\u8d44\u6e90\u6839\u76ee\u5f55<br \/>\n    if (_basedir.empty())<br \/>\n    {<br \/>\n        return false;<br \/>\n    }<br \/>\n    \/\/ 2.\u8bf7\u6c42\u65b9\u6cd5\u5fc5\u987b\u662fGET\u6216\u8005HEAD<br \/>\n    if (req._method !&#061; &#034;GET&#034; &amp;&amp; req._method !&#061; &#034;HEAD&#034;)<br \/>\n    {<br \/>\n        return false;<br \/>\n    }<br \/>\n    \/\/ 3.\u8bf7\u6c42\u7684\u8d44\u6e90\u8def\u5f84\u5fc5\u987b\u662f\u4e00\u4e2a\u5408\u6cd5\u8def\u5f84<br \/>\n    if (Util::ValidPath(req._path) &#061;&#061; false)<br \/>\n    {<br \/>\n        return false;<br \/>\n    }<br \/>\n    \/\/ 4.\u8bf7\u6c42\u7684\u8d44\u6e90\u5fc5\u987b\u5b58\u5728<br \/>\n    \/\/ \u76f4\u63a5\u8bf7\u6c42\u6839\u76ee\u5f55\u662f\u6bd4\u8f83\u7279\u6b8a\u7684&#xff0c;\u6b64\u65f6\u76f4\u63a5\u8ffd\u52a0\u5230\u9996\u9875<br \/>\n    \/\/ \u4e0d\u8981\u5fd8\u8bb0\u524d\u7f00\u7684\u76f8\u5bf9\u6839\u76ee\u5f55<br \/>\n    std::string req_path &#061; _basedir &#043; req._path; \/\/ \u907f\u514d\u76f4\u63a5\u4fee\u6539\u8bf7\u6c42\u7684\u8d44\u6e90\u8def\u5f84<br \/>\n    if (req_path.back() &#061;&#061; &#039;\/&#039;)<br \/>\n    {<br \/>\n        req_path &#043;&#061; &#034;index.html&#034;;<br \/>\n    }<br \/>\n    if (Util::IsRegular(req_path) &#061;&#061; false)<br \/>\n    {<br \/>\n        return false;<br \/>\n    }<br \/>\n    \/\/ req._path &#061; req_path; \/\/\u5982\u679c\u8bf7\u6c42\u5c31\u662f\u9759\u6001\u8d44\u6e90\u8bf7\u6c42&#xff0c;\u5219\u6709\u53ef\u80fd\u9700\u8981\u8ffd\u52a0index.html<br \/>\n    return true;<br \/>\n} <\/p>\n<p>\u9759\u6001\u8d44\u6e90\u8bf7\u6c42\u5904\u7406\u51fd\u6570&#xff0c;\u5c06\u9759\u6001\u8d44\u6e90\u6587\u4ef6\u7684\u6570\u636e\u8bfb\u53d6\u51fa\u6765&#xff0c;\u653e\u5230rsp\u7684_body&#xff0c;\u5e76\u8bbe\u7f6emime<\/p>\n<p> void FileHandler(const HttpRequest &amp;req, HttpResponse *rsp)<br \/>\n{<br \/>\n    std::string req_path &#061; _basedir &#043; req._path; \/\/ \u907f\u514d\u76f4\u63a5\u4fee\u6539\u8bf7\u6c42\u7684\u8d44\u6e90\u8def\u5f84<br \/>\n    if (req_path.back() &#061;&#061; &#039;\/&#039;)<br \/>\n    {<br \/>\n        req_path &#043;&#061; &#034;index.html&#034;;<br \/>\n    }<br \/>\n    bool ret &#061; Util::ReadFile(req_path, &amp;rsp-&gt;_body);<br \/>\n    if (ret &#061;&#061; false)<br \/>\n    {<br \/>\n        return;<br \/>\n    }<br \/>\n    std::string mime &#061; Util::ExtMime(req_path);<br \/>\n    rsp-&gt;SetHeader(&#034;Content-Type&#034;, mime);<br \/>\n    return;<br \/>\n} <\/p>\n<p>\u8bf7\u6c42\u5f53\u7136\u4e5f\u6709\u529f\u80fd\u6027\u8bf7\u6c42<\/p>\n<p> void Dispatcher(HttpRequest &amp;req, HttpResponse *rsp, Handlers &amp;handlers)<br \/>\n{<br \/>\n    \/\/ \u5728\u5bf9\u5e94\u8bf7\u6c42\u65b9\u6cd5\u7684\u8def\u7531\u8868\u4e2d&#xff0c;\u67e5\u627e\u662f\u54e6\u5426\u542b\u6709\u5bf9\u5e94\u8d44\u6e90\u8bf7\u6c42\u7684\u5904\u7406\u51fd\u6570&#xff0c;\u6709\u5219\u8c03\u7528&#xff0c;\u6ca1\u6709\u5219\u8fd4\u56de404<br \/>\n    \/\/ \u601d\u60f3&#xff1a;\u8def\u7531\u8868\u5b58\u50a8\u7684\u662f\u952e\u503c\u5bf9 &#8212; \u6b63\u5219\u8868\u8fbe\u5f0f &amp; \u5904\u7406\u51fd\u6570<br \/>\n    \/\/ \u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f&#xff0c;\u5bf9\u8bf7\u6c42\u7684\u8d44\u6e90\u8def\u5f84\u8fdb\u884c\u6b63\u5219\u5339\u914d&#xff0c;\u5339\u914d\u6210\u529f\u5c31\u662f\u6709\u5bf9\u5e94\u51fd\u6570\u8fdb\u884c\u5904\u7406<br \/>\n    for (auto &amp;handler : handlers)<br \/>\n    {<br \/>\n        const std::regex &amp;re &#061; handler.first;<br \/>\n        const Handler &amp;functor &#061; handler.second;<br \/>\n        \/\/ std::cout &lt;&lt; &#034;\u8fdb\u5165\u4e86\u8fd9\u91cc&#034; &lt;&lt; std::endl;<br \/>\n        \/\/ std::cout &lt;&lt; &#034;req._path&#034; &lt;&lt; req._path &lt;&lt; &#034;req._matches&#034; &lt;&lt; req._matches[1] &lt;&lt; std::endl;<br \/>\n        \/\/ std::cout &lt;&lt; &#034;req._path&#034; &lt;&lt; req._path &lt;&lt;std::endl;<br \/>\n        bool ret &#061; std::regex_match(req._path, req._matches, re);<br \/>\n        if (ret &#061;&#061; false)<br \/>\n        {<br \/>\n            continue;<br \/>\n        }<br \/>\n        return functor(req, rsp); \/\/ \u4f20\u5165\u8bf7\u6c42\u4fe1\u606f&#xff0c;\u548c\u7a7a\u7684rsp\u6267\u884c\u5904\u7406\u51fd\u6570<br \/>\n        \/\/ std::cout &lt;&lt; &#034;\u5230\u8fd9\u91cc\u6ca1\u6709\u51fa\u9519&#034; &lt;&lt; std::endl;<br \/>\n    }<br \/>\n    \/\/ std::cout &lt;&lt; &#034;\u6539\u6210404&#034; &lt;&lt; std::endl;<br \/>\n    rsp-&gt;_statu &#061; 404;<br \/>\n} <\/p>\n<p>\u8def\u7531\u67e5\u627e\u5339\u914d\u51fd\u6570&#xff0c;\u4e3b\u8981\u662f\u7528\u6765\u8fdb\u884c\u67e5\u627e\u65f6\u9759\u6001\u8d44\u6e90\u8fd8\u662f\u52a8\u6001\u8d44\u6e90&#xff0c;\u7136\u540e\u6267\u884c\u5bf9\u5e94\u7684\u5904\u7406&#xff0c;\u5982\u679c\u90fd\u4e0d\u662f\u5219\u8fd4\u56de404<\/p>\n<p> \/\/ \u8def\u7531\u67e5\u627e\u5339\u914d<br \/>\nvoid Route(HttpRequest &amp;req, HttpResponse *rsp)<br \/>\n{<br \/>\n    \/\/ 1.\u5bf9\u8bf7\u6c42\u8d44\u6e90\u8fdb\u884c\u5206\u8fa8&#xff0c;\u662f\u4e00\u4e2a\u9759\u6001\u8d44\u6e90\u8bf7\u6c42&#xff0c;\u8fd8\u662f\u4e00\u4e2a\u529f\u80fd\u6027\u8bf7\u6c42<br \/>\n    \/\/ \u9759\u6001\u8d44\u6e90\u8bf7\u6c42&#xff0c;\u5219\u8fdb\u884c\u9759\u6001\u8d44\u6e90\u5904\u7406<br \/>\n    \/\/ \u529f\u80fd\u6027\u8bf7\u6c42&#xff0c;\u5219\u9700\u8981\u901a\u8fc7\u51e0\u4e2a\u8bf7\u6c42\u8def\u7531\u8868\u6765\u786e\u5b9a\u662f\u5426\u6709\u5904\u7406\u51fd\u6570<br \/>\n    \/\/ \u65e2\u4e0d\u662f\u9759\u6001\u8d44\u6e90\u8bf7\u6c42&#xff0c;\u4e5f\u4e0d\u662f\u529f\u80fd\u6027\u5904\u7406\u8bf7\u6c42&#xff0c;\u5219\u8fd4\u56de404<br \/>\n    if (IsFileHandler(req) &#061;&#061; true)<br \/>\n    {<br \/>\n        \/\/ \u662f\u4e00\u4e2a\u9759\u6001\u8d44\u6e90\u8bf7\u6c42&#xff0c;\u5219\u8fdb\u884c\u9759\u6001\u8d44\u6e90\u8bf7\u6c42\u7684\u5904\u7406<br \/>\n        \/\/ std::cout &lt;&lt; &#034;\u8fdb\u5165\u4e86\u8fd9\u91cc&#034; &lt;&lt; std::endl;<br \/>\n        return FileHandler(req, rsp);<br \/>\n    }<br \/>\n    \/\/ HEAD\u4e0eGET\u7c7b\u4f3c&#xff0c;\u53ea\u4e0d\u8fc7\u4e0d\u8981\u54cd\u5e94\u6b63\u6587<br \/>\n    \/\/ std::cout &lt;&lt; &#034;req._method&#034; &lt;&lt; req._method &lt;&lt; std::endl;<br \/>\n    if (req._method &#061;&#061; &#034;GET&#034; || req._method &#061;&#061; &#034;HEAD&#034;)<br \/>\n    {<br \/>\n        \/\/ std::cout &lt;&lt; &#034;\u4f7f\u7528\u4e86GET\u8c03\u7528\u51fd\u6570\u6dfb\u52a0\u5904\u7406&#034; &lt;&lt; std::endl;<br \/>\n        return Dispatcher(req, rsp, _get_route);<br \/>\n    }<br \/>\n    else if (req._method &#061;&#061; &#034;POST&#034;)<br \/>\n    {<br \/>\n        return Dispatcher(req, rsp, _post_route);<br \/>\n    }<br \/>\n    else if (req._method &#061;&#061; &#034;PUT&#034;)<br \/>\n    {<br \/>\n        return Dispatcher(req, rsp, _put_route);<br \/>\n    }<br \/>\n    else if (req._method &#061;&#061; &#034;DELETE&#034;)<br \/>\n    {<br \/>\n        return Dispatcher(req, rsp, _delete_route);<br \/>\n    }<br \/>\n    rsp-&gt;_statu &#061; 405; \/\/ METHOD NOT ALLOWED<br \/>\n} <\/p>\n<p>\u8bbe\u7f6e\u4e0a\u4e0b\u6587\u7684\u51fd\u6570OnConnected<\/p>\n<p> void OnConnected(const PtrConnection &amp;conn)<br \/>\n{<br \/>\n    conn-&gt;SetContext(HttpContext());<br \/>\n    DBG_LOG(&#034;NEW CONNECTION %p&#034;, conn.get());<br \/>\n}<br \/>\n\/\/ \u7f13\u51b2\u533a\u6570\u636e\u89e3\u6790 &#043; \u5904\u7406<br \/>\nvoid OnMessage(const PtrConnection &amp;conn, Buffer *buffer)<br \/>\n{<br \/>\n    while (buffer-&gt;ReadAbleSize() &gt; 0) \/\/ \u6709\u6570\u636e\u5c31\u7ee7\u7eed\u5904\u7406<br \/>\n    {<br \/>\n        \/\/ 1.\u83b7\u53d6\u4e0a\u4e0b\u6587<br \/>\n        HttpContext *context &#061; conn-&gt;GetContext()-&gt;get&lt;HttpContext&gt;();<br \/>\n        \/\/ 2.\u901a\u8fc7\u4e0a\u4e0b\u6587\u5bf9\u7f13\u51b2\u533a\u6570\u636e\u8fdb\u884c\u89e3\u6790&#xff0c;\u5f97\u5230HttpRequest\u5bf9\u8c61<br \/>\n        \/\/ 1.\u5982\u679c\u7f13\u51b2\u533a\u7684\u6570\u636e\u89e3\u6790\u51fa\u9519&#xff0c;\u5c31\u76f4\u63a5\u56de\u590d\u51fa\u9519\u54cd\u5e94<br \/>\n        \/\/ 2.\u5982\u679c\u89e3\u6790\u6b63\u5e38&#xff0c;\u4e14\u8bf7\u6c42\u5df2\u7ecf\u83b7\u53d6\u5b8c\u6bd5&#xff0c;\u624d\u5f00\u59cb\u53bb\u8fdb\u884c\u5904\u7406<br \/>\n        context-&gt;RecvHttpRequest(buffer);<br \/>\n        HttpRequest &amp;req &#061; context-&gt;Request();<br \/>\n        HttpResponse rsp(context-&gt;RespStatu());<br \/>\n        if (context-&gt;RespStatu() &gt;&#061; 400)<br \/>\n        {<br \/>\n            \/\/ \u51fa\u9519\u4e86&#xff0c;\u5173\u95ed\u8fde\u63a5<br \/>\n            ErrorHandler(req, &amp;rsp);       \/\/ \u586b\u5145\u4e00\u4e2a\u9519\u8bef\u663e\u793a\u9875\u9762\u6570\u636e\u5230rsp\u4e2d<br \/>\n            WriteResponse(conn, req, rsp); \/\/ \u7ec4\u7ec7\u54cd\u5e94\u53d1\u9001\u7ed9\u5ba2\u6237\u7aef<\/p>\n<p>            context-&gt;ReSet(); \/\/&#xff01;&#xff01;&#xff01;\u91cd\u8981\u4ee3\u7801\u884c&#xff01;&#xff01;&#xff01;\u5982\u679c\u4e0d\u6e05\u7a7a\u72b6\u6001\u7684\u8bdd&#xff0c;\u4ed6\u7684\u72b6\u6001\u7801\u4f1a\u4e00\u76f4\u5728400\u591a&#xff0c;\u5bfc\u81f4\u4e0d\u65ad\u7ed9\u5ba2\u6237\u7aef\u53d1\u9001\u51fa\u9519\u4fe1\u606f<br \/>\n            buffer-&gt;MoveReadOffset(buffer-&gt;ReadAbleSize()); \/\/\u51fa\u9519\u4e86\u628a\u7f13\u51b2\u533a\u6e05\u7a7a\u4e0d\u518d\u5904\u7406<\/p>\n<p>            conn-&gt;Shutdown(); \/\/ \u5173\u95ed\u8fde\u63a5<br \/>\n            return;<br \/>\n        }<br \/>\n        if (context-&gt;RecvStatu() !&#061; RECV_HTTP_OVER)<br \/>\n        {<br \/>\n            \/\/ \u5f53\u524d\u8bf7\u6c42\u8fd8\u6ca1\u6709\u63a5\u53d7\u5b8c\u6574&#xff0c;\u5219\u9000\u51fa&#xff0c;\u7b49\u5230\u65b0\u6570\u636e\u5230\u6765\u518d\u91cd\u65b0\u5904\u7406<br \/>\n            return;<br \/>\n        }<\/p>\n<p>        \/\/ 3.\u8bf7\u6c42\u8def\u7531 &#043; \u4e1a\u52a1\u5904\u7406<br \/>\n        Route(req, &amp;rsp);<br \/>\n        \/\/ 4.\u5bf9HttpResponse\u8fdb\u884c\u7ec4\u7ec7\u53d1\u9001<br \/>\n        \/\/DBG_LOG(&#034;%s&#034;, rsp._body.c_str());<br \/>\n        WriteResponse(conn, req, rsp);<br \/>\n        \/\/ 5.\u91cd\u7f6e\u4e0a\u4e0b\u6587<br \/>\n        context-&gt;ReSet();<br \/>\n        \/\/ 5.\u6839\u636e\u957f\u77ed\u8fde\u63a5\u5224\u65ad\u662f\u5426\u8fde\u63a5\u6216\u8005\u7ee7\u7eed\u5904\u7406<br \/>\n        if (rsp.Close() &#061;&#061; true) \/\/ \u77ed\u8fde\u63a5<br \/>\n        {<br \/>\n            conn-&gt;Shutdown();<br \/>\n        }<br \/>\n    }<br \/>\n    return;<br \/>\n} <\/p>\n<p>\u4e0b\u9762\u662f\u8fd9\u4e2a\u7c7b\u7684\u5b8c\u6574\u4ee3\u7801<\/p>\n<p> class HttpServer<br \/>\n{<br \/>\npublic:<br \/>\n    using Handler &#061; std::function&lt;void(const HttpRequest &amp;, HttpResponse *)&gt;;<br \/>\n    using Handlers &#061; std::vector&lt;std::pair&lt;std::regex, Handler&gt;&gt;;<br \/>\n    Handlers _get_route;<br \/>\n    Handlers _post_route;<br \/>\n    Handlers _put_route;<br \/>\n    Handlers _delete_route;<br \/>\n    std::string _basedir; \/\/ \u9759\u6001\u8d44\u6e90\u6839\u76ee\u5f55<br \/>\n    TcpServer _server;<\/p>\n<p>private:<br \/>\n    void ErrorHandler(const HttpRequest &amp;req, HttpResponse *rsp)<br \/>\n    {<br \/>\n        \/\/ 1.\u7ec4\u7ec7\u4e00\u4e2a\u9519\u8bef\u5c55\u793a\u9875\u9762<br \/>\n        std::string body;<br \/>\n        body &#043;&#061; &#034;&lt;html&gt;&#034;;<br \/>\n        body &#043;&#061; &#034;&lt;head&gt;&#034;;<br \/>\n        body &#043;&#061; &#034;&lt;meta http-equiv&#061;&#039;Content-Type&#039; content&#061;&#039;text\/html;charset&#061;utf-8&#039;&gt;&#034;;<br \/>\n        body &#043;&#061; &#034;&lt;\/head&gt;&#034;;<br \/>\n        body &#043;&#061; &#034;&lt;body&gt;&#034;;<br \/>\n        body &#043;&#061; &#034;&lt;h1&gt;&#034;;<br \/>\n        body &#043;&#061; std::to_string(rsp-&gt;_statu);<br \/>\n        body &#043;&#061; &#034; &#034;;<br \/>\n        body &#043;&#061; Util::StatuDesc(rsp-&gt;_statu);<br \/>\n        body &#043;&#061; &#034;&lt;\/h1&gt;&#034;;<br \/>\n        body &#043;&#061; &#034;&lt;\/body&gt;&#034;;<br \/>\n        body &#043;&#061; &#034;&lt;\/html&gt;&#034;;<br \/>\n        \/\/ 2.\u5c06\u9875\u9762\u6570\u636e&#xff0c;\u5f53\u505a\u54cd\u5e94\u6b63\u6587&#xff0c;\u653e\u5165rsp\u4e2d<br \/>\n        rsp-&gt;SetContent(body, &#034;text\/html&#034;);<br \/>\n    }<br \/>\n    \/\/ \u5c06HttpResponse\u4e2d\u7684\u8981\u7d20\u6309\u7167http\u534f\u8bae\u683c\u5f0f\u8fdb\u884c\u7ec4\u7ec7&#xff0c;\u53d1\u9001<br \/>\n    void WriteResponse(const PtrConnection &amp;conn, const HttpRequest &amp;req, HttpResponse &amp;rsp)<br \/>\n    {<br \/>\n        \/\/ 1.\u5148\u5b8c\u5584\u5934\u90e8\u5b57\u6bb5<br \/>\n        \/\/ req\u662fconst&#xff0c;\u8c03\u7528\u7684Close\u4e5f\u5fc5\u987b\u662fconst\u7c7b\u578b<br \/>\n        if (req.Close() &#061;&#061; true)<br \/>\n        {<br \/>\n            rsp.SetHeader(&#034;Connection&#034;, &#034;close&#034;);<br \/>\n        }<br \/>\n        else<br \/>\n        {<br \/>\n            rsp.SetHeader(&#034;Connection&#034;, &#034;keep-alive&#034;);<br \/>\n        }<br \/>\n        if (rsp._body.empty() &#061;&#061; false &amp;&amp; rsp.HasHeader(&#034;Content-Length&#034;) &#061;&#061; false)<br \/>\n        {<br \/>\n            rsp.SetHeader(&#034;Content-Length&#034;, std::to_string(rsp._body.size()));<br \/>\n        }<br \/>\n        if (rsp._body.empty() &#061;&#061; false &amp;&amp; rsp.HasHeader(&#034;Content-Type&#034;) &#061;&#061; false)<br \/>\n        {<br \/>\n            rsp.SetHeader(&#034;Content-Type&#034;, &#034;application\/octet-stream&#034;); \/\/ \u4e8c\u8fdb\u5236\u6d41<br \/>\n        }<br \/>\n        if (rsp._redirect_flag &#061;&#061; true)<br \/>\n        {<br \/>\n            rsp.SetHeader(&#034;Location&#034;, rsp._redirect_url);<br \/>\n        }<br \/>\n        \/\/ 2.\u5c06rsp\u7684\u8981\u7d20&#xff0c;\u6309\u7167http\u534f\u8bae\u8fdb\u884c\u7ec4\u7ec7<br \/>\n        std::stringstream rsp_str;<br \/>\n        rsp_str &lt;&lt; req._version &lt;&lt; &#034; &#034; &lt;&lt; std::to_string(rsp._statu) &lt;&lt; &#034; &#034; &lt;&lt; Util::StatuDesc(rsp._statu) &lt;&lt; &#034;\\\\r\\\\n&#034;;<br \/>\n        for (auto &amp;head : rsp._headers)<br \/>\n        {<br \/>\n            rsp_str &lt;&lt; head.first &lt;&lt; &#034;:&#034; &lt;&lt; head.second &lt;&lt; &#034;\\\\r\\\\n&#034;;<br \/>\n        }<br \/>\n        rsp_str &lt;&lt; &#034;\\\\r\\\\n&#034;;<br \/>\n        rsp_str &lt;&lt; rsp._body;<br \/>\n        \/\/ 3.\u53d1\u9001\u6570\u636e<br \/>\n        conn-&gt;Send(rsp_str.str().c_str(), rsp_str.str().size());<br \/>\n    }<br \/>\n    \/\/ \u5224\u65ad\u662f\u5426\u4e3a\u9759\u6001\u8d44\u6e90<br \/>\n    bool IsFileHandler(const HttpRequest &amp;req)<br \/>\n    {<br \/>\n        \/\/ 1.\u5fc5\u987b\u8bbe\u7f6e\u4e86\u9759\u6001\u8d44\u6e90\u6839\u76ee\u5f55<br \/>\n        if (_basedir.empty())<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        \/\/ 2.\u8bf7\u6c42\u65b9\u6cd5\u5fc5\u987b\u662fGET\u6216\u8005HEAD<br \/>\n        if (req._method !&#061; &#034;GET&#034; &amp;&amp; req._method !&#061; &#034;HEAD&#034;)<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        \/\/ 3.\u8bf7\u6c42\u7684\u8d44\u6e90\u8def\u5f84\u5fc5\u987b\u662f\u4e00\u4e2a\u5408\u6cd5\u8def\u5f84<br \/>\n        if (Util::ValidPath(req._path) &#061;&#061; false)<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        \/\/ 4.\u8bf7\u6c42\u7684\u8d44\u6e90\u5fc5\u987b\u5b58\u5728<br \/>\n        \/\/ \u76f4\u63a5\u8bf7\u6c42\u6839\u76ee\u5f55\u662f\u6bd4\u8f83\u7279\u6b8a\u7684&#xff0c;\u6b64\u65f6\u76f4\u63a5\u8ffd\u52a0\u5230\u9996\u9875<br \/>\n        \/\/ \u4e0d\u8981\u5fd8\u8bb0\u524d\u7f00\u7684\u76f8\u5bf9\u6839\u76ee\u5f55<br \/>\n        std::string req_path &#061; _basedir &#043; req._path; \/\/ \u907f\u514d\u76f4\u63a5\u4fee\u6539\u8bf7\u6c42\u7684\u8d44\u6e90\u8def\u5f84<br \/>\n        if (req_path.back() &#061;&#061; &#039;\/&#039;)<br \/>\n        {<br \/>\n            req_path &#043;&#061; &#034;index.html&#034;;<br \/>\n        }<br \/>\n        if (Util::IsRegular(req_path) &#061;&#061; false)<br \/>\n        {<br \/>\n            return false;<br \/>\n        }<br \/>\n        \/\/ req._path &#061; req_path; \/\/\u5982\u679c\u8bf7\u6c42\u5c31\u662f\u9759\u6001\u8d44\u6e90\u8bf7\u6c42&#xff0c;\u5219\u6709\u53ef\u80fd\u9700\u8981\u8ffd\u52a0index.html<br \/>\n        return true;<br \/>\n    }<br \/>\n    \/\/ \u9759\u6001\u8d44\u6e90\u8bf7\u6c42\u5904\u7406 &#8212; \u5c06\u9759\u6001\u8d44\u6e90\u6587\u4ef6\u7684\u6570\u636e\u8bfb\u53d6\u51fa\u6765&#xff0c;\u653e\u5230rsp\u7684_body&#xff0c;\u5e76\u8bbe\u7f6emime<br \/>\n    void FileHandler(const HttpRequest &amp;req, HttpResponse *rsp)<br \/>\n    {<br \/>\n        std::string req_path &#061; _basedir &#043; req._path; \/\/ \u907f\u514d\u76f4\u63a5\u4fee\u6539\u8bf7\u6c42\u7684\u8d44\u6e90\u8def\u5f84<br \/>\n        if (req_path.back() &#061;&#061; &#039;\/&#039;)<br \/>\n        {<br \/>\n            req_path &#043;&#061; &#034;index.html&#034;;<br \/>\n        }<br \/>\n        bool ret &#061; Util::ReadFile(req_path, &amp;rsp-&gt;_body);<br \/>\n        if (ret &#061;&#061; false)<br \/>\n        {<br \/>\n            return;<br \/>\n        }<br \/>\n        std::string mime &#061; Util::ExtMime(req_path);<br \/>\n        rsp-&gt;SetHeader(&#034;Content-Type&#034;, mime);<br \/>\n        return;<br \/>\n    }<br \/>\n    \/\/ \u529f\u80fd\u6027\u8bf7\u6c42\u7684\u5206\u7c7b\u5904\u7406<br \/>\n    void Dispatcher(HttpRequest &amp;req, HttpResponse *rsp, Handlers &amp;handlers)<br \/>\n    {<br \/>\n        \/\/ \u5728\u5bf9\u5e94\u8bf7\u6c42\u65b9\u6cd5\u7684\u8def\u7531\u8868\u4e2d&#xff0c;\u67e5\u627e\u662f\u54e6\u5426\u542b\u6709\u5bf9\u5e94\u8d44\u6e90\u8bf7\u6c42\u7684\u5904\u7406\u51fd\u6570&#xff0c;\u6709\u5219\u8c03\u7528&#xff0c;\u6ca1\u6709\u5219\u8fd4\u56de404<br \/>\n        \/\/ \u601d\u60f3&#xff1a;\u8def\u7531\u8868\u5b58\u50a8\u7684\u662f\u952e\u503c\u5bf9 &#8212; \u6b63\u5219\u8868\u8fbe\u5f0f &amp; \u5904\u7406\u51fd\u6570<br \/>\n        \/\/ \u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f&#xff0c;\u5bf9\u8bf7\u6c42\u7684\u8d44\u6e90\u8def\u5f84\u8fdb\u884c\u6b63\u5219\u5339\u914d&#xff0c;\u5339\u914d\u6210\u529f\u5c31\u662f\u6709\u5bf9\u5e94\u51fd\u6570\u8fdb\u884c\u5904\u7406<br \/>\n        for (auto &amp;handler : handlers)<br \/>\n        {<br \/>\n            const std::regex &amp;re &#061; handler.first;<br \/>\n            const Handler &amp;functor &#061; handler.second;<br \/>\n            \/\/ std::cout &lt;&lt; &#034;\u8fdb\u5165\u4e86\u8fd9\u91cc&#034; &lt;&lt; std::endl;<br \/>\n            \/\/ std::cout &lt;&lt; &#034;req._path&#034; &lt;&lt; req._path &lt;&lt; &#034;req._matches&#034; &lt;&lt; req._matches[1] &lt;&lt; std::endl;<br \/>\n            \/\/ std::cout &lt;&lt; &#034;req._path&#034; &lt;&lt; req._path &lt;&lt;std::endl;<br \/>\n            bool ret &#061; std::regex_match(req._path, req._matches, re);<br \/>\n            if (ret &#061;&#061; false)<br \/>\n            {<br \/>\n                continue;<br \/>\n            }<br \/>\n            return functor(req, rsp); \/\/ \u4f20\u5165\u8bf7\u6c42\u4fe1\u606f&#xff0c;\u548c\u7a7a\u7684rsp\u6267\u884c\u5904\u7406\u51fd\u6570<br \/>\n            \/\/ std::cout &lt;&lt; &#034;\u5230\u8fd9\u91cc\u6ca1\u6709\u51fa\u9519&#034; &lt;&lt; std::endl;<br \/>\n        }<br \/>\n        \/\/ std::cout &lt;&lt; &#034;\u6539\u6210404&#034; &lt;&lt; std::endl;<br \/>\n        rsp-&gt;_statu &#061; 404;<br \/>\n    }<br \/>\n    \/\/ \u8def\u7531\u67e5\u627e\u5339\u914d<br \/>\n    void Route(HttpRequest &amp;req, HttpResponse *rsp)<br \/>\n    {<br \/>\n        \/\/ 1.\u5bf9\u8bf7\u6c42\u8d44\u6e90\u8fdb\u884c\u5206\u8fa8&#xff0c;\u662f\u4e00\u4e2a\u9759\u6001\u8d44\u6e90\u8bf7\u6c42&#xff0c;\u8fd8\u662f\u4e00\u4e2a\u529f\u80fd\u6027\u8bf7\u6c42<br \/>\n        \/\/ \u9759\u6001\u8d44\u6e90\u8bf7\u6c42&#xff0c;\u5219\u8fdb\u884c\u9759\u6001\u8d44\u6e90\u5904\u7406<br \/>\n        \/\/ \u529f\u80fd\u6027\u8bf7\u6c42&#xff0c;\u5219\u9700\u8981\u901a\u8fc7\u51e0\u4e2a\u8bf7\u6c42\u8def\u7531\u8868\u6765\u786e\u5b9a\u662f\u5426\u6709\u5904\u7406\u51fd\u6570<br \/>\n        \/\/ \u65e2\u4e0d\u662f\u9759\u6001\u8d44\u6e90\u8bf7\u6c42&#xff0c;\u4e5f\u4e0d\u662f\u529f\u80fd\u6027\u5904\u7406\u8bf7\u6c42&#xff0c;\u5219\u8fd4\u56de404<br \/>\n        if (IsFileHandler(req) &#061;&#061; true)<br \/>\n        {<br \/>\n            \/\/ \u662f\u4e00\u4e2a\u9759\u6001\u8d44\u6e90\u8bf7\u6c42&#xff0c;\u5219\u8fdb\u884c\u9759\u6001\u8d44\u6e90\u8bf7\u6c42\u7684\u5904\u7406<br \/>\n            \/\/ std::cout &lt;&lt; &#034;\u8fdb\u5165\u4e86\u8fd9\u91cc&#034; &lt;&lt; std::endl;<br \/>\n            return FileHandler(req, rsp);<br \/>\n        }<br \/>\n        \/\/ HEAD\u4e0eGET\u7c7b\u4f3c&#xff0c;\u53ea\u4e0d\u8fc7\u4e0d\u8981\u54cd\u5e94\u6b63\u6587<br \/>\n        \/\/ std::cout &lt;&lt; &#034;req._method&#034; &lt;&lt; req._method &lt;&lt; std::endl;<br \/>\n        if (req._method &#061;&#061; &#034;GET&#034; || req._method &#061;&#061; &#034;HEAD&#034;)<br \/>\n        {<br \/>\n            \/\/ std::cout &lt;&lt; &#034;\u4f7f\u7528\u4e86GET\u8c03\u7528\u51fd\u6570\u6dfb\u52a0\u5904\u7406&#034; &lt;&lt; std::endl;<br \/>\n            return Dispatcher(req, rsp, _get_route);<br \/>\n        }<br \/>\n        else if (req._method &#061;&#061; &#034;POST&#034;)<br \/>\n        {<br \/>\n            return Dispatcher(req, rsp, _post_route);<br \/>\n        }<br \/>\n        else if (req._method &#061;&#061; &#034;PUT&#034;)<br \/>\n        {<br \/>\n            return Dispatcher(req, rsp, _put_route);<br \/>\n        }<br \/>\n        else if (req._method &#061;&#061; &#034;DELETE&#034;)<br \/>\n        {<br \/>\n            return Dispatcher(req, rsp, _delete_route);<br \/>\n        }<br \/>\n        rsp-&gt;_statu &#061; 405; \/\/ METHOD NOT ALLOWED<br \/>\n    }<br \/>\n    \/\/ \u8bbe\u7f6e\u4e0a\u4e0b\u6587<br \/>\n    void OnConnected(const PtrConnection &amp;conn)<br \/>\n    {<br \/>\n        conn-&gt;SetContext(HttpContext());<br \/>\n        DBG_LOG(&#034;NEW CONNECTION %p&#034;, conn.get());<br \/>\n    }<br \/>\n    \/\/ \u7f13\u51b2\u533a\u6570\u636e\u89e3\u6790 &#043; \u5904\u7406<br \/>\n    void OnMessage(const PtrConnection &amp;conn, Buffer *buffer)<br \/>\n    {<br \/>\n        while (buffer-&gt;ReadAbleSize() &gt; 0) \/\/ \u6709\u6570\u636e\u5c31\u7ee7\u7eed\u5904\u7406<br \/>\n        {<br \/>\n            \/\/ 1.\u83b7\u53d6\u4e0a\u4e0b\u6587<br \/>\n            HttpContext *context &#061; conn-&gt;GetContext()-&gt;get&lt;HttpContext&gt;();<br \/>\n            \/\/ 2.\u901a\u8fc7\u4e0a\u4e0b\u6587\u5bf9\u7f13\u51b2\u533a\u6570\u636e\u8fdb\u884c\u89e3\u6790&#xff0c;\u5f97\u5230HttpRequest\u5bf9\u8c61<br \/>\n            \/\/ 1.\u5982\u679c\u7f13\u51b2\u533a\u7684\u6570\u636e\u89e3\u6790\u51fa\u9519&#xff0c;\u5c31\u76f4\u63a5\u56de\u590d\u51fa\u9519\u54cd\u5e94<br \/>\n            \/\/ 2.\u5982\u679c\u89e3\u6790\u6b63\u5e38&#xff0c;\u4e14\u8bf7\u6c42\u5df2\u7ecf\u83b7\u53d6\u5b8c\u6bd5&#xff0c;\u624d\u5f00\u59cb\u53bb\u8fdb\u884c\u5904\u7406<br \/>\n            context-&gt;RecvHttpRequest(buffer);<br \/>\n            HttpRequest &amp;req &#061; context-&gt;Request();<br \/>\n            HttpResponse rsp(context-&gt;RespStatu());<br \/>\n            if (context-&gt;RespStatu() &gt;&#061; 400)<br \/>\n            {<br \/>\n                \/\/ \u51fa\u9519\u4e86&#xff0c;\u5173\u95ed\u8fde\u63a5<br \/>\n                ErrorHandler(req, &amp;rsp);       \/\/ \u586b\u5145\u4e00\u4e2a\u9519\u8bef\u663e\u793a\u9875\u9762\u6570\u636e\u5230rsp\u4e2d<br \/>\n                WriteResponse(conn, req, rsp); \/\/ \u7ec4\u7ec7\u54cd\u5e94\u53d1\u9001\u7ed9\u5ba2\u6237\u7aef<\/p>\n<p>                context-&gt;ReSet(); \/\/&#xff01;&#xff01;&#xff01;\u91cd\u8981\u4ee3\u7801\u884c&#xff01;&#xff01;&#xff01;\u5982\u679c\u4e0d\u6e05\u7a7a\u72b6\u6001\u7684\u8bdd&#xff0c;\u4ed6\u7684\u72b6\u6001\u7801\u4f1a\u4e00\u76f4\u5728400\u591a&#xff0c;\u5bfc\u81f4\u4e0d\u65ad\u7ed9\u5ba2\u6237\u7aef\u53d1\u9001\u51fa\u9519\u4fe1\u606f<br \/>\n                buffer-&gt;MoveReadOffset(buffer-&gt;ReadAbleSize()); \/\/\u51fa\u9519\u4e86\u628a\u7f13\u51b2\u533a\u6e05\u7a7a\u4e0d\u518d\u5904\u7406<\/p>\n<p>                conn-&gt;Shutdown(); \/\/ \u5173\u95ed\u8fde\u63a5<br \/>\n                return;<br \/>\n            }<br \/>\n            if (context-&gt;RecvStatu() !&#061; RECV_HTTP_OVER)<br \/>\n            {<br \/>\n                \/\/ \u5f53\u524d\u8bf7\u6c42\u8fd8\u6ca1\u6709\u63a5\u53d7\u5b8c\u6574&#xff0c;\u5219\u9000\u51fa&#xff0c;\u7b49\u5230\u65b0\u6570\u636e\u5230\u6765\u518d\u91cd\u65b0\u5904\u7406<br \/>\n                return;<br \/>\n            }<\/p>\n<p>            \/\/ 3.\u8bf7\u6c42\u8def\u7531 &#043; \u4e1a\u52a1\u5904\u7406<br \/>\n            Route(req, &amp;rsp);<br \/>\n            \/\/ 4.\u5bf9HttpResponse\u8fdb\u884c\u7ec4\u7ec7\u53d1\u9001<br \/>\n            \/\/DBG_LOG(&#034;%s&#034;, rsp._body.c_str());<br \/>\n            WriteResponse(conn, req, rsp);<br \/>\n            \/\/ 5.\u91cd\u7f6e\u4e0a\u4e0b\u6587<br \/>\n            context-&gt;ReSet();<br \/>\n            \/\/ 5.\u6839\u636e\u957f\u77ed\u8fde\u63a5\u5224\u65ad\u662f\u5426\u8fde\u63a5\u6216\u8005\u7ee7\u7eed\u5904\u7406<br \/>\n            if (rsp.Close() &#061;&#061; true) \/\/ \u77ed\u8fde\u63a5<br \/>\n            {<br \/>\n                conn-&gt;Shutdown();<br \/>\n            }<br \/>\n        }<br \/>\n        return;<br \/>\n    }<\/p>\n<p>public:<br \/>\n    HttpServer(int port, int timeout &#061; DEFAULT_TIMEOUT)<br \/>\n        : _server(port)<br \/>\n    {<br \/>\n        _server.EnableInactiveRelease(timeout);<br \/>\n        _server.SetConnectedCallback(std::bind(&amp;HttpServer::OnConnected, this, std::placeholders::_1));<br \/>\n        _server.SetMessageCallback(std::bind(&amp;HttpServer::OnMessage, this, std::placeholders::_1, std::placeholders::_2));<br \/>\n    }<br \/>\n    void SetBaseDir(const std::string &amp;path)<br \/>\n    {<br \/>\n        int ret &#061; Util::IsDirectory(path);<br \/>\n        assert(ret &#061;&#061; true);<br \/>\n        _basedir &#061; path;<br \/>\n    }<br \/>\n    \/*\u8bbe\u7f6e\/\u6dfb\u52a0\u8bf7\u6c42(\u8bf7\u6c42\u7684\u6b63\u5219\u8868\u8fbe\u5f0f)\u4e0e\u5904\u7406\u51fd\u6570\u7684\u6620\u5c04\u5173\u7cfb*\/<br \/>\n    void Get(const std::string &amp;patten, const Handler &amp;handler)<br \/>\n    {<br \/>\n        _get_route.push_back(std::make_pair(std::regex(patten), handler));<br \/>\n    }<br \/>\n    void Post(const std::string &amp;patten, const Handler &amp;handler)<br \/>\n    {<br \/>\n        _post_route.push_back(std::make_pair(std::regex(patten), handler));<br \/>\n    }<br \/>\n    void Put(const std::string &amp;patten, const Handler &amp;handler)<br \/>\n    {<br \/>\n        _put_route.push_back(std::make_pair(std::regex(patten), handler));<br \/>\n    }<br \/>\n    void Delete(const std::string &amp;patten, const Handler &amp;handler)<br \/>\n    {<br \/>\n        _delete_route.push_back(std::make_pair(std::regex(patten), handler));<br \/>\n    }<br \/>\n    void SetThreadCount(int count)<br \/>\n    {<br \/>\n        _server.SetThreadCount(count);<br \/>\n    }<br \/>\n    void Listen()<br \/>\n    {<br \/>\n        _server.Start();<br \/>\n    }<br \/>\n}; <\/p>\n<h2 id=\"4.%E7%BB%93%E8%AF%AD\">4.\u7ed3\u8bed<\/h2>\n<p>\u4ee3\u7801\u8fde\u63a5\u5982\u4e0blesson41 \u00b7 \u5f20\u5bb6\u5174\/Linux &#8211; \u7801\u4e91 &#8211; \u5f00\u6e90\u4e2d\u56fd<\/p>\n<p>\u6709\u9700\u8981\u81ea\u53d6&#xff0c;\u535a\u5ba2\u4e0d\u7cbe\u51c6\u5730\u65b9\u8bf7\u591a\u8c05\u89e3<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u6587\u7ae0\u6d4f\u89c8\u9605\u8bfb743\u6b21\uff0c\u70b9\u8d5e10\u6b21\uff0c\u6536\u85cf18\u6b21\u3002\u672c\u6587\u8be6\u7ec6\u4ecb\u7ecd\u4e86\u5982\u4f55\u5b9e\u73b0\u4e00\u4e2a\u57fa\u4e8eC++\u7684\u9ad8\u6027\u80fdHTTP\u670d\u52a1\u5668\uff0c\u6db5\u76d6\u4e86\u4ece\u57fa\u7840\u6a21\u5757\u5230\u5b8c\u6574\u670d\u52a1\u5668\u5b9e\u73b0\u7684\u5404\u4e2a\u90e8\u5206\u3002\u9996\u5148\uff0c\u6587\u7ae0\u4ecb\u7ecd\u4e86\u65f6\u95f4\u8f6e\u3001\u6b63\u5219\u8868\u8fbe\u5f0f\u548c\u901a\u7528\u7c7b\u578bAny\u7684\u5b9e\u73b0\uff0c\u8fd9\u4e9b\u662f\u670d\u52a1\u5668\u5f00\u53d1\u4e2d\u7684\u57fa\u7840\u5de5\u5177\u3002\u63a5\u7740\uff0c\u6587\u7ae0\u8be6\u7ec6\u8bb2\u89e3\u4e86\u670d\u52a1\u5668\u6a21\u5757\u7684\u5b9e\u73b0\uff0c\u5305\u62ec\u7f13\u51b2\u533a\u7ba1\u7406\u3001\u65e5\u5fd7\u5b8f\u3001\u5957\u63a5\u5b57\u6a21\u5757\u3001\u4e8b\u4ef6\u7ba1\u7406\u3001\u63cf\u8ff0\u7b26\u4e8b\u4ef6\u76d1\u63a7\u3001\u5b9a\u65f6\u4efb\u52a1\u7ba1\u7406\u3001Reactor-EventLoop\u7ebf\u7a0b\u6c60\u7b49\u6838\u5fc3\u7ec4\u4ef6\u3002\u968f\u540e\uff0c\u6587\u7ae0\u6df1\u5165\u63a2\u8ba8\u4e86HTTP\u534f\u8bae\u652f\u6301\u6a21\u5757\u7684\u5b9e\u73b0\uff0c\u5305\u62ec\u5b9e\u7528\u5de5\u5177\u7c7b\u3001HTTP\u8bf7\u6c42\u548c\u54cd\u5e94\u7c7b\u7684\u8bbe\u8ba1\uff0c\u4ee5\u53caHTTP\u4e0a\u4e0b\u6587\u7684\u7ba1\u7406\u3002\u6700\u540e\uff0c\u6587\u7ae0\u5c55\u793a\u4e86\u5982\u4f55\u5c06\u8fd9\u4e9b\u6a21\u5757\u6574\u5408\u6210<\/p>\n","protected":false},"author":2,"featured_media":38610,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[55,371,43],"topic":[],"class_list":["post-38611","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-server","tag-c","tag-371","tag-43"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v20.3 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>\u3010\u5168\u5c40\u6559\u5b66\u3011\u624b\u628a\u624b\u6559\u4f60\u505a\u4e00\u4e2amuduo\u670d\u52a1\u5668 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.wsisp.com\/helps\/38611.html\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"\u3010\u5168\u5c40\u6559\u5b66\u3011\u624b\u628a\u624b\u6559\u4f60\u505a\u4e00\u4e2amuduo\u670d\u52a1\u5668 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\" \/>\n<meta property=\"og:description\" content=\"\u6587\u7ae0\u6d4f\u89c8\u9605\u8bfb743\u6b21\uff0c\u70b9\u8d5e10\u6b21\uff0c\u6536\u85cf18\u6b21\u3002\u672c\u6587\u8be6\u7ec6\u4ecb\u7ecd\u4e86\u5982\u4f55\u5b9e\u73b0\u4e00\u4e2a\u57fa\u4e8eC++\u7684\u9ad8\u6027\u80fdHTTP\u670d\u52a1\u5668\uff0c\u6db5\u76d6\u4e86\u4ece\u57fa\u7840\u6a21\u5757\u5230\u5b8c\u6574\u670d\u52a1\u5668\u5b9e\u73b0\u7684\u5404\u4e2a\u90e8\u5206\u3002\u9996\u5148\uff0c\u6587\u7ae0\u4ecb\u7ecd\u4e86\u65f6\u95f4\u8f6e\u3001\u6b63\u5219\u8868\u8fbe\u5f0f\u548c\u901a\u7528\u7c7b\u578bAny\u7684\u5b9e\u73b0\uff0c\u8fd9\u4e9b\u662f\u670d\u52a1\u5668\u5f00\u53d1\u4e2d\u7684\u57fa\u7840\u5de5\u5177\u3002\u63a5\u7740\uff0c\u6587\u7ae0\u8be6\u7ec6\u8bb2\u89e3\u4e86\u670d\u52a1\u5668\u6a21\u5757\u7684\u5b9e\u73b0\uff0c\u5305\u62ec\u7f13\u51b2\u533a\u7ba1\u7406\u3001\u65e5\u5fd7\u5b8f\u3001\u5957\u63a5\u5b57\u6a21\u5757\u3001\u4e8b\u4ef6\u7ba1\u7406\u3001\u63cf\u8ff0\u7b26\u4e8b\u4ef6\u76d1\u63a7\u3001\u5b9a\u65f6\u4efb\u52a1\u7ba1\u7406\u3001Reactor-EventLoop\u7ebf\u7a0b\u6c60\u7b49\u6838\u5fc3\u7ec4\u4ef6\u3002\u968f\u540e\uff0c\u6587\u7ae0\u6df1\u5165\u63a2\u8ba8\u4e86HTTP\u534f\u8bae\u652f\u6301\u6a21\u5757\u7684\u5b9e\u73b0\uff0c\u5305\u62ec\u5b9e\u7528\u5de5\u5177\u7c7b\u3001HTTP\u8bf7\u6c42\u548c\u54cd\u5e94\u7c7b\u7684\u8bbe\u8ba1\uff0c\u4ee5\u53caHTTP\u4e0a\u4e0b\u6587\u7684\u7ba1\u7406\u3002\u6700\u540e\uff0c\u6587\u7ae0\u5c55\u793a\u4e86\u5982\u4f55\u5c06\u8fd9\u4e9b\u6a21\u5757\u6574\u5408\u6210\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.wsisp.com\/helps\/38611.html\" \/>\n<meta property=\"og:site_name\" content=\"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\" \/>\n<meta property=\"article:published_time\" content=\"2025-05-20T11:31:04+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2025\/05\/20250520113103-682c67f78f176.png\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u4f5c\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data2\" content=\"71 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/38611.html\",\"url\":\"https:\/\/www.wsisp.com\/helps\/38611.html\",\"name\":\"\u3010\u5168\u5c40\u6559\u5b66\u3011\u624b\u628a\u624b\u6559\u4f60\u505a\u4e00\u4e2amuduo\u670d\u52a1\u5668 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\",\"isPartOf\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/#website\"},\"datePublished\":\"2025-05-20T11:31:04+00:00\",\"dateModified\":\"2025-05-20T11:31:04+00:00\",\"author\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/38611.html#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.wsisp.com\/helps\/38611.html\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/38611.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u9996\u9875\",\"item\":\"https:\/\/www.wsisp.com\/helps\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"\u3010\u5168\u5c40\u6559\u5b66\u3011\u624b\u628a\u624b\u6559\u4f60\u505a\u4e00\u4e2amuduo\u670d\u52a1\u5668\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/#website\",\"url\":\"https:\/\/www.wsisp.com\/helps\/\",\"name\":\"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\",\"description\":\"\u9999\u6e2f\u670d\u52a1\u5668_\u9999\u6e2f\u4e91\u670d\u52a1\u5668\u8d44\u8baf_\u670d\u52a1\u5668\u5e2e\u52a9\u6587\u6863_\u670d\u52a1\u5668\u6559\u7a0b\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.wsisp.com\/helps\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"zh-Hans\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery\",\"contentUrl\":\"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery\",\"caption\":\"admin\"},\"sameAs\":[\"http:\/\/wp.wsisp.com\"],\"url\":\"https:\/\/www.wsisp.com\/helps\/author\/admin\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"\u3010\u5168\u5c40\u6559\u5b66\u3011\u624b\u628a\u624b\u6559\u4f60\u505a\u4e00\u4e2amuduo\u670d\u52a1\u5668 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.wsisp.com\/helps\/38611.html","og_locale":"zh_CN","og_type":"article","og_title":"\u3010\u5168\u5c40\u6559\u5b66\u3011\u624b\u628a\u624b\u6559\u4f60\u505a\u4e00\u4e2amuduo\u670d\u52a1\u5668 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","og_description":"\u6587\u7ae0\u6d4f\u89c8\u9605\u8bfb743\u6b21\uff0c\u70b9\u8d5e10\u6b21\uff0c\u6536\u85cf18\u6b21\u3002\u672c\u6587\u8be6\u7ec6\u4ecb\u7ecd\u4e86\u5982\u4f55\u5b9e\u73b0\u4e00\u4e2a\u57fa\u4e8eC++\u7684\u9ad8\u6027\u80fdHTTP\u670d\u52a1\u5668\uff0c\u6db5\u76d6\u4e86\u4ece\u57fa\u7840\u6a21\u5757\u5230\u5b8c\u6574\u670d\u52a1\u5668\u5b9e\u73b0\u7684\u5404\u4e2a\u90e8\u5206\u3002\u9996\u5148\uff0c\u6587\u7ae0\u4ecb\u7ecd\u4e86\u65f6\u95f4\u8f6e\u3001\u6b63\u5219\u8868\u8fbe\u5f0f\u548c\u901a\u7528\u7c7b\u578bAny\u7684\u5b9e\u73b0\uff0c\u8fd9\u4e9b\u662f\u670d\u52a1\u5668\u5f00\u53d1\u4e2d\u7684\u57fa\u7840\u5de5\u5177\u3002\u63a5\u7740\uff0c\u6587\u7ae0\u8be6\u7ec6\u8bb2\u89e3\u4e86\u670d\u52a1\u5668\u6a21\u5757\u7684\u5b9e\u73b0\uff0c\u5305\u62ec\u7f13\u51b2\u533a\u7ba1\u7406\u3001\u65e5\u5fd7\u5b8f\u3001\u5957\u63a5\u5b57\u6a21\u5757\u3001\u4e8b\u4ef6\u7ba1\u7406\u3001\u63cf\u8ff0\u7b26\u4e8b\u4ef6\u76d1\u63a7\u3001\u5b9a\u65f6\u4efb\u52a1\u7ba1\u7406\u3001Reactor-EventLoop\u7ebf\u7a0b\u6c60\u7b49\u6838\u5fc3\u7ec4\u4ef6\u3002\u968f\u540e\uff0c\u6587\u7ae0\u6df1\u5165\u63a2\u8ba8\u4e86HTTP\u534f\u8bae\u652f\u6301\u6a21\u5757\u7684\u5b9e\u73b0\uff0c\u5305\u62ec\u5b9e\u7528\u5de5\u5177\u7c7b\u3001HTTP\u8bf7\u6c42\u548c\u54cd\u5e94\u7c7b\u7684\u8bbe\u8ba1\uff0c\u4ee5\u53caHTTP\u4e0a\u4e0b\u6587\u7684\u7ba1\u7406\u3002\u6700\u540e\uff0c\u6587\u7ae0\u5c55\u793a\u4e86\u5982\u4f55\u5c06\u8fd9\u4e9b\u6a21\u5757\u6574\u5408\u6210","og_url":"https:\/\/www.wsisp.com\/helps\/38611.html","og_site_name":"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","article_published_time":"2025-05-20T11:31:04+00:00","og_image":[{"url":"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2025\/05\/20250520113103-682c67f78f176.png"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"admin","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"71 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.wsisp.com\/helps\/38611.html","url":"https:\/\/www.wsisp.com\/helps\/38611.html","name":"\u3010\u5168\u5c40\u6559\u5b66\u3011\u624b\u628a\u624b\u6559\u4f60\u505a\u4e00\u4e2amuduo\u670d\u52a1\u5668 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","isPartOf":{"@id":"https:\/\/www.wsisp.com\/helps\/#website"},"datePublished":"2025-05-20T11:31:04+00:00","dateModified":"2025-05-20T11:31:04+00:00","author":{"@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41"},"breadcrumb":{"@id":"https:\/\/www.wsisp.com\/helps\/38611.html#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.wsisp.com\/helps\/38611.html"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.wsisp.com\/helps\/38611.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/www.wsisp.com\/helps"},{"@type":"ListItem","position":2,"name":"\u3010\u5168\u5c40\u6559\u5b66\u3011\u624b\u628a\u624b\u6559\u4f60\u505a\u4e00\u4e2amuduo\u670d\u52a1\u5668"}]},{"@type":"WebSite","@id":"https:\/\/www.wsisp.com\/helps\/#website","url":"https:\/\/www.wsisp.com\/helps\/","name":"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","description":"\u9999\u6e2f\u670d\u52a1\u5668_\u9999\u6e2f\u4e91\u670d\u52a1\u5668\u8d44\u8baf_\u670d\u52a1\u5668\u5e2e\u52a9\u6587\u6863_\u670d\u52a1\u5668\u6559\u7a0b","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.wsisp.com\/helps\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"zh-Hans"},{"@type":"Person","@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41","name":"admin","image":{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/image\/","url":"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery","contentUrl":"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery","caption":"admin"},"sameAs":["http:\/\/wp.wsisp.com"],"url":"https:\/\/www.wsisp.com\/helps\/author\/admin"}]}},"_links":{"self":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts\/38611","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/comments?post=38611"}],"version-history":[{"count":0,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts\/38611\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/media\/38610"}],"wp:attachment":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/media?parent=38611"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/categories?post=38611"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/tags?post=38611"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/topic?post=38611"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}