{"id":14200,"date":"2025-04-18T20:59:15","date_gmt":"2025-04-18T12:59:15","guid":{"rendered":"https:\/\/www.wsisp.com\/helps\/14200.html"},"modified":"2025-04-18T20:59:15","modified_gmt":"2025-04-18T12:59:15","slug":"%e4%bb%bfmodou%e5%ba%93one-thread-one-loop%e5%bc%8f%e5%b9%b6%e5%8f%91%e6%9c%8d%e5%8a%a1%e5%99%a8","status":"publish","type":"post","link":"https:\/\/www.wsisp.com\/helps\/14200.html","title":{"rendered":"\u4effmodou\u5e93one thread one loop\u5f0f\u5e76\u53d1\u670d\u52a1\u5668"},"content":{"rendered":"<p>\u6e90\u7801&#xff1a;\u7530\u67d0super\/moduo<\/p>\n<\/p>\n<p id=\"main-toc\">\u76ee\u5f55<\/p>\n<p id=\"SERVER%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:80px\">SERVER\u6a21\u5757&#xff1a;<\/p>\n<p id=\"Buffer%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">Buffer\u6a21\u5757&#xff1a;<\/p>\n<p id=\"Socket%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">Socket\u6a21\u5757&#xff1a;<\/p>\n<p id=\"Channel%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">Channel\u6a21\u5757&#xff1a;<\/p>\n<p id=\"Connection%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">Connection\u6a21\u5757&#xff1a;<\/p>\n<p id=\"Acceptor%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">Acceptor\u6a21\u5757&#xff1a;<\/p>\n<p id=\"TimerQueue%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">TimerQueue\u6a21\u5757&#xff1a;<\/p>\n<p id=\"Poller%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">Poller\u6a21\u5757&#xff1a;<\/p>\n<p id=\"EventLoop%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">EventLoop\u6a21\u5757&#xff1a;<\/p>\n<p id=\"TcpServer%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">TcpServer\u6a21\u5757&#xff1a;<\/p>\n<p id=\"HTTP%E5%8D%8F%E8%AE%AE%E7%BB%84%E4%BB%B6%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:80px\">HTTP\u534f\u8bae\u7ec4\u4ef6\u6a21\u5757&#xff1a;<\/p>\n<p id=\"Util%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">Util\u6a21\u5757&#xff1a;<\/p>\n<p id=\"HttpRequest%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">HttpRequest\u6a21\u5757&#xff1a;<\/p>\n<p id=\"HttpContext%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">HttpContext\u6a21\u5757&#xff1a;<\/p>\n<p id=\"HttpServer%E6%A8%A1%E5%9D%97%EF%BC%9A-toc\" style=\"margin-left:120px\">HttpServer\u6a21\u5757&#xff1a;<\/p>\n<hr id=\"hr-toc\" \/>\n<p>\u901a\u8fc7\u54b1\u4eec\u5b9e\u73b0\u7684\u2fbc\u5e76\u53d1\u670d\u52a1\u5668\u7ec4\u4ef6&#xff0c;\u53ef\u4ee5\u7b80\u6d01\u5feb\u901f\u7684\u5b8c\u6210\u2f00\u4e2a\u2fbc\u6027\u80fd\u7684\u670d\u52a1\u5668\u642d\u5efa\u3002 \u5e76\u4e14&#xff0c;\u901a\u8fc7\u7ec4\u4ef6\u5185\u63d0\u4f9b\u7684\u4e0d\u540c\u5e94\u2f64\u5c42\u534f\u8bae\u2f40\u6301&#xff0c;\u4e5f\u53ef\u4ee5\u5feb\u901f\u5b8c\u6210\u2f00\u4e2a\u2fbc\u6027\u80fd\u5e94\u2f64\u670d\u52a1\u5668\u7684\u642d\u5efa&#xff08;\u5f53\u524d &#xff0c;\u4e3a\u4e86\u4fbf\u4e8e\u9879\u2f6c\u7684\u6f14\u2f70&#xff0c;\u9879\u2f6c\u4e2d\u63d0\u4f9bHTTP\u534f\u8bae\u7ec4\u4ef6\u7684\u2f40\u6301&#xff09;\u3002 \u5728\u8fd9\u2fa5&#xff0c;\u8981\u660e\u786e\u7684\u662f\u54b1\u4eec\u8981\u5b9e\u73b0\u7684\u662f\u2f00\u4e2a\u2fbc\u5e76\u53d1\u670d\u52a1\u5668\u7ec4\u4ef6&#xff0c;\u56e0\u6b64\u5f53\u524d\u7684\u9879\u2f6c\u4e2d\u5e76\u4e0d\u5305\u542b\u5b9e\u9645\u7684\u4e1a\u52a1\u5185\u5bb9\u3002<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" alt=\"\" height=\"507\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2025\/04\/20250418125914-68024ca28ccf6.png\" width=\"813\" \/><\/p>\n<p>\u56fe\u7247\u6765\u6e90&#xff1a;\u00a0\u56fe\u89e3one loop per thread&#xff1a;\u4f7f\u7528muduo\u7f51\u7edc\u5e93\u5b9e\u73b0web\u670d\u52a1\u5668_znzxc\u7684\u535a\u5ba2-CSDN\u535a\u5ba2<\/p>\n<p>\u672c\u9879\u76ee\u603b\u5171\u5206\u4e3a\u4e24\u5927\u6a21\u5757\u5206\u522b\u4e3aServer\u548cHTTP\u6a21\u5757\u3002<\/p>\n<h4 id=\"SERVER%E6%A8%A1%E5%9D%97%EF%BC%9A\">SERVER\u6a21\u5757&#xff1a;<\/h4>\n<p>SERVER\u6a21\u5757\u5c31\u662f\u5bf9\u6240\u6709\u7684\u8fde\u63a5\u4ee5\u53ca\u7ebf\u7a0b\u8fdb\u2f8f\u7ba1\u7406&#xff0c;\u8ba9\u5b83\u4eec\u5404\u53f8\u5176\u804c&#xff0c;\u5728\u5408\u9002\u7684\u65f6\u5019\u505a\u5408\u9002\u7684\u4e8b&#xff0c;\u6700\u7ec8\u5b8c\u6210\u2fbc\u6027\u80fd\u670d\u52a1\u5668\u7ec4\u4ef6\u7684\u5b9e\u73b0\u3002<\/p>\n<p>\u7ba1\u7406\u2f45\u2faf&#xff1a; \u76d1\u542c\u8fde\u63a5\u7ba1\u7406&#xff1a;\u5bf9\u76d1\u542c\u8fde\u63a5\u8fdb\u2f8f\u7ba1\u7406 \u901a\u4fe1\u8fde\u63a5\u7ba1\u7406&#xff1a;\u5bf9\u901a\u4fe1\u8fde\u63a5\u8fdb\u2f8f\u7ba1\u7406 \u8d85\u65f6\u8fde\u63a5\u7ba1\u7406&#xff1a;\u5bf9\u8d85\u65f6\u8fde\u63a5\u8fdb\u2f8f\u7ba1\u7406 \u57fa\u4e8e\u4ee5\u4e0a\u53ef\u4ee5\u5c06\u5176\u5206\u4e3a\u591a\u4e2a\u5b50\u6a21\u5757&#xff1a;<\/p>\n<h5 id=\"Buffer%E6%A8%A1%E5%9D%97%EF%BC%9A\">Buffer\u6a21\u5757&#xff1a;<\/h5>\n<p>\u2f64\u4e8e\u5b9e\u73b0\u7528\u6237\u6001\u7f13\u51b2\u533a&#xff0c;\u63d0\u4f9b\u6570\u636e\u7f13\u51b2&#xff0c;\u53d6\u51fa\u7b49\u529f\u80fd\u3002<\/p>\n<p>class Buffer {<br \/>\n    private:<br \/>\n        std::vector&lt;char&gt; _buffer; \/\/\u4f7f\u7528vector\u8fdb\u884c\u5185\u5b58\u7a7a\u95f4\u7ba1\u7406<br \/>\n        uint64_t _reader_idx; \/\/\u8bfb\u504f\u79fb<br \/>\n        uint64_t _writer_idx; \/\/\u5199\u504f\u79fb<br \/>\n    public:<br \/>\n        Buffer():_reader_idx(0), _writer_idx(0), _buffer(BUFFER_DEFAULT_SIZE){}<br \/>\n        char *Begin() { return &amp;*_buffer.begin(); }<br \/>\n        \/\/\u83b7\u53d6\u5f53\u524d\u5199\u5165\u8d77\u59cb\u5730\u5740, _buffer\u7684\u7a7a\u95f4\u8d77\u59cb\u5730\u5740&#xff0c;\u52a0\u4e0a\u5199\u504f\u79fb\u91cf<br \/>\n        char *WritePosition() { return Begin() &#043; _writer_idx; }<br \/>\n        \/\/\u83b7\u53d6\u5f53\u524d\u8bfb\u53d6\u8d77\u59cb\u5730\u5740<br \/>\n        char *ReadPosition() { return Begin() &#043; _reader_idx; }<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, \u603b\u4f53\u7a7a\u95f4\u5927\u5c0f\u51cf\u53bb\u5199\u504f\u79fb<br \/>\n        uint64_t TailIdleSize() { return _buffer.size() &#8211; _writer_idx; }<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() { return _reader_idx; }<br \/>\n        \/\/\u83b7\u53d6\u53ef\u8bfb\u6570\u636e\u5927\u5c0f &#061; \u5199\u504f\u79fb &#8211; \u8bfb\u504f\u79fb<br \/>\n        uint64_t ReadAbleSize() { return _writer_idx &#8211; _reader_idx; }<br \/>\n        \/\/\u5c06\u8bfb\u504f\u79fb\u5411\u540e\u79fb\u52a8<br \/>\n        void MoveReadOffset(uint64_t len) {<br \/>\n            if (len &#061;&#061; 0) return;<br \/>\n            \/\/\u5411\u540e\u79fb\u52a8\u7684\u5927\u5c0f&#xff0c;\u5fc5\u987b\u5c0f\u4e8e\u53ef\u8bfb\u6570\u636e\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            \/\/\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&#xff08;\u6574\u4f53\u7a7a\u95f2\u7a7a\u95f4\u591f\u4e86\u5c31\u79fb\u52a8\u6570\u636e&#xff0c;\u5426\u5219\u5c31\u6269\u5bb9&#xff09;<br \/>\n        void EnsureWriteSpace(uint64_t len) {<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) { return; }<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, \u591f\u4e86\u5c31\u5c06\u6570\u636e\u79fb\u52a8\u5230\u8d77\u59cb\u4f4d\u7f6e<br \/>\n            if (len &lt;&#061; TailIdleSize() &#043; HeadIdleSize()) {<br \/>\n                \/\/\u5c06\u6570\u636e\u79fb\u52a8\u5230\u8d77\u59cb\u4f4d\u7f6e<br \/>\n                uint64_t rsz &#061; ReadAbleSize();\/\/\u628a\u5f53\u524d\u6570\u636e\u5927\u5c0f\u5148\u4fdd\u5b58\u8d77\u6765<br \/>\n                std::copy(ReadPosition(), ReadPosition() &#043; rsz, Begin());\/\/\u628a\u53ef\u8bfb\u6570\u636e\u62f7\u8d1d\u5230\u8d77\u59cb\u4f4d\u7f6e<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            }else {<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            \/\/1. \u4fdd\u8bc1\u6709\u8db3\u591f\u7a7a\u95f4&#xff0c;2. \u62f7\u8d1d\u6570\u636e\u8fdb\u53bb<br \/>\n            if (len &#061;&#061; 0) return;<br \/>\n            EnsureWriteSpace(len);<br \/>\n            const char *d &#061; (const char *)data;<br \/>\n            std::copy(d, d &#043; len, WritePosition());<br \/>\n        }<br \/>\n        void WriteAndPush(const void *data, uint64_t len) {<br \/>\n            Write(data, len);<br \/>\n            MoveWriteOffset(len);<br \/>\n        }<br \/>\n        void WriteString(const std::string &amp;data) {<br \/>\n            return Write(data.c_str(), data.size());<br \/>\n        }<br \/>\n        void WriteStringAndPush(const std::string &amp;data) {<br \/>\n            WriteString(data);<br \/>\n            MoveWriteOffset(data.size());<br \/>\n        }<br \/>\n        void WriteBuffer(Buffer &amp;data) {<br \/>\n            return Write(data.ReadPosition(), data.ReadAbleSize());<br \/>\n        }<br \/>\n        void WriteBufferAndPush(Buffer &amp;data) {<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            \/\/\u8981\u6c42\u8981\u83b7\u53d6\u7684\u6570\u636e\u5927\u5c0f\u5fc5\u987b\u5c0f\u4e8e\u53ef\u8bfb\u6570\u636e\u5927\u5c0f<br \/>\n            assert(len &lt;&#061; ReadAbleSize());<br \/>\n            std::copy(ReadPosition(), ReadPosition() &#043; len, (char*)buf);<br \/>\n        }<br \/>\n        void ReadAndPop(void *buf, uint64_t len) {<br \/>\n            Read(buf, len);<br \/>\n            MoveReadOffset(len);<br \/>\n        }<br \/>\n        std::string ReadAsString(uint64_t len) {<br \/>\n            \/\/\u8981\u6c42\u8981\u83b7\u53d6\u7684\u6570\u636e\u5927\u5c0f\u5fc5\u987b\u5c0f\u4e8e\u53ef\u8bfb\u6570\u636e\u5927\u5c0f<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            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            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\u662f*\/<br \/>\n        std::string GetLine() {<br \/>\n            char *pos &#061; FindCRLF();<br \/>\n            if (pos &#061;&#061; NULL) {<br \/>\n                return &#034;&#034;;<br \/>\n            }<br \/>\n            \/\/ &#043;1\u662f\u4e3a\u4e86\u628a\u6362\u884c\u5b57\u7b26\u4e5f\u53d6\u51fa\u6765\u3002<br \/>\n            return ReadAsString(pos &#8211; ReadPosition() &#043; 1);<br \/>\n        }<br \/>\n        std::string GetLineAndPop() {<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            \/\/\u53ea\u9700\u8981\u5c06\u504f\u79fb\u91cf\u5f520\u5373\u53ef<br \/>\n            _reader_idx &#061; 0;<br \/>\n            _writer_idx &#061; 0;<br \/>\n        }<br \/>\n}; <\/p>\n<h5 id=\"Socket%E6%A8%A1%E5%9D%97%EF%BC%9A\">Socket\u6a21\u5757&#xff1a;<\/h5>\n<p>\u5c01\u88c5\u5957\u63a5\u5b57<\/p>\n<p>class Socket {<br \/>\n    private:<br \/>\n        int _sockfd;<br \/>\n    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            \/\/ int socket(int domain, int type, int protocol)<br \/>\n            _sockfd &#061; socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);<br \/>\n            if (_sockfd &lt; 0) {<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            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 bind(int sockfd, struct sockaddr*addr, socklen_t len);<br \/>\n            int ret &#061; bind(_sockfd, (struct sockaddr*)&amp;addr, len);<br \/>\n            if (ret &lt; 0) {<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            \/\/ int listen(int backlog)<br \/>\n            int ret &#061; listen(_sockfd, backlog);<br \/>\n            if (ret &lt; 0) {<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            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 connect(int sockfd, struct sockaddr*addr, socklen_t len);<br \/>\n            int ret &#061; connect(_sockfd, (struct sockaddr*)&amp;addr, len);<br \/>\n            if (ret &lt; 0) {<br \/>\n                ERR_LOG(&#034;CONNECT SERVER FAILED!&#034;);<br \/>\n                return false;<br \/>\n            }<br \/>\n            return true;<br \/>\n        }<br \/>\n        \/\/\u83b7\u53d6\u65b0\u8fde\u63a5<br \/>\n        int Accept() {<br \/>\n            \/\/ int accept(int sockfd, struct sockaddr *addr, socklen_t *len);<br \/>\n            int newfd &#061; accept(_sockfd, NULL, NULL);<br \/>\n            if (newfd &lt; 0) {<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) {<br \/>\n            \/\/ ssize_t recv(int sockfd, void *buf, size_t len, int flag);<br \/>\n            ssize_t ret &#061; recv(_sockfd, buf, len, flag);<br \/>\n            if (ret &lt;&#061; 0) {<br \/>\n                \/\/EAGAIN \u5f53\u524dsocket\u7684\u63a5\u6536\u7f13\u51b2\u533a\u4e2d\u6ca1\u6709\u6570\u636e\u4e86&#xff0c;\u5728\u975e\u963b\u585e\u7684\u60c5\u51b5\u4e0b\u624d\u4f1a\u6709\u8fd9\u4e2a\u9519\u8bef<br \/>\n                \/\/EINTR  \u8868\u793a\u5f53\u524dsocket\u7684\u963b\u585e\u7b49\u5f85&#xff0c;\u88ab\u4fe1\u53f7\u6253\u65ad\u4e86&#xff0c;<br \/>\n                if (errno &#061;&#061; EAGAIN || errno &#061;&#061; EINTR) {<br \/>\n                    return 0;\/\/\u8868\u793a\u8fd9\u6b21\u63a5\u6536\u6ca1\u6709\u63a5\u6536\u5230\u6570\u636e<br \/>\n                }<br \/>\n                ERR_LOG(&#034;SOCKET RECV FAILED!!&#034;);<br \/>\n                return -1;<br \/>\n            }<br \/>\n            return ret; \/\/\u5b9e\u9645\u63a5\u6536\u7684\u6570\u636e\u957f\u5ea6<br \/>\n        }<br \/>\n        ssize_t NonBlockRecv(void *buf, size_t len) {<br \/>\n            return Recv(buf, len, MSG_DONTWAIT); \/\/ MSG_DONTWAIT \u8868\u793a\u5f53\u524d\u63a5\u6536\u4e3a\u975e\u963b\u585e\u3002<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            \/\/ 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                if (errno &#061;&#061; EAGAIN || errno &#061;&#061; EINTR) {<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;\/\/\u5b9e\u9645\u53d1\u9001\u7684\u6570\u636e\u957f\u5ea6<br \/>\n        }<br \/>\n        ssize_t NonBlockSend(void *buf, size_t len) {<br \/>\n            if (len &#061;&#061; 0) return 0;<br \/>\n            return Send(buf, len, MSG_DONTWAIT); \/\/ MSG_DONTWAIT \u8868\u793a\u5f53\u524d\u53d1\u9001\u4e3a\u975e\u963b\u585e\u3002<br \/>\n        }<br \/>\n        \/\/\u5173\u95ed\u5957\u63a5\u5b57<br \/>\n        void Close() {<br \/>\n            if (_sockfd !&#061; -1) {<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            \/\/1. \u521b\u5efa\u5957\u63a5\u5b57&#xff0c;2. \u7ed1\u5b9a\u5730\u5740&#xff0c;3. \u5f00\u59cb\u76d1\u542c&#xff0c;4. \u8bbe\u7f6e\u975e\u963b\u585e&#xff0c; 5. \u542f\u52a8\u5730\u5740\u91cd\u7528<br \/>\n            if (Create() &#061;&#061; false) return false;<br \/>\n            if (block_flag) NonBlock();<br \/>\n            if (Bind(ip, port) &#061;&#061; false) return false;<br \/>\n            if (Listen() &#061;&#061; false) return false;<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            \/\/1. \u521b\u5efa\u5957\u63a5\u5b57&#xff0c;2.\u6307\u5411\u8fde\u63a5\u670d\u52a1\u5668<br \/>\n            if (Create() &#061;&#061; false) return false;<br \/>\n            if (Connect(ip, port) &#061;&#061; false) return false;<br \/>\n            return true;<br \/>\n        }<br \/>\n        \/\/\u8bbe\u7f6e\u5957\u63a5\u5b57\u9009\u9879&#8212;\u5f00\u542f\u5730\u5740\u7aef\u53e3\u91cd\u7528<br \/>\n        void ReuseAddress() {<br \/>\n            \/\/ int setsockopt(int fd, int leve, int optname, void *val, int vallen)<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            \/\/int fcntl(int fd, int cmd, &#8230; \/* arg *\/ );<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<h5 id=\"Channel%E6%A8%A1%E5%9D%97%EF%BC%9A\">Channel\u6a21\u5757&#xff1a;<\/h5>\n<p>Channel\u6a21\u5757\u662f\u5bf9\u2f00\u4e2a\u63cf\u8ff0\u7b26\u9700\u8981\u8fdb\u2f8f\u7684IO\u4e8b\u4ef6\u7ba1\u7406\u7684\u6a21\u5757&#xff0c;\u5b9e\u73b0\u5bf9\u63cf\u8ff0\u7b26\u53ef\u8bfb&#xff0c;\u53ef\u5199&#xff0c;\u9519\u8bef&#8230;\u4e8b\u4ef6\u7684\u7ba1\u7406\u64cd\u4f5c&#xff0c;\u4ee5\u53caPoller\u6a21\u5757\u5bf9\u63cf\u8ff0\u7b26\u8fdb\u2f8fIO\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>class Channel {<br \/>\n    private:<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\u8fde\u63a5\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 \/>\n    public:<br \/>\n        Channel(EventLoop *loop, int fd):_fd(fd), _events(0), _revents(0), _loop(loop) {}<br \/>\n        int Fd() { return _fd; }<br \/>\n        uint32_t Events() { return _events; }\/\/\u83b7\u53d6\u60f3\u8981\u76d1\u63a7\u7684\u4e8b\u4ef6<br \/>\n        void SetREvents(uint32_t events) { _revents &#061; events; }\/\/\u8bbe\u7f6e\u5b9e\u9645\u5c31\u7eea\u7684\u4e8b\u4ef6<br \/>\n        void SetReadCallback(const EventCallback &amp;cb) { _read_callback &#061; cb; }<br \/>\n        void SetWriteCallback(const EventCallback &amp;cb) { _write_callback &#061; cb; }<br \/>\n        void SetErrorCallback(const EventCallback &amp;cb) { _error_callback &#061; cb; }<br \/>\n        void SetCloseCallback(const EventCallback &amp;cb) { _close_callback &#061; cb; }<br \/>\n        void SetEventCallback(const EventCallback &amp;cb) { _event_callback &#061; cb; }<br \/>\n        \/\/\u5f53\u524d\u662f\u5426\u76d1\u63a7\u4e86\u53ef\u8bfb<br \/>\n        bool ReadAble() { return (_events &amp; EPOLLIN); }<br \/>\n        \/\/\u5f53\u524d\u662f\u5426\u76d1\u63a7\u4e86\u53ef\u5199<br \/>\n        bool WriteAble() { return (_events &amp; EPOLLOUT); }<br \/>\n        \/\/\u542f\u52a8\u8bfb\u4e8b\u4ef6\u76d1\u63a7<br \/>\n        void EnableRead() { _events |&#061; EPOLLIN; Update(); }<br \/>\n        \/\/\u542f\u52a8\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n        void EnableWrite() { _events |&#061; EPOLLOUT; Update(); }<br \/>\n        \/\/\u5173\u95ed\u8bfb\u4e8b\u4ef6\u76d1\u63a7<br \/>\n        void DisableRead() { _events &amp;&#061; ~EPOLLIN; Update(); }<br \/>\n        \/\/\u5173\u95ed\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n        void DisableWrite() { _events &amp;&#061; ~EPOLLOUT; Update(); }<br \/>\n        \/\/\u5173\u95ed\u6240\u6709\u4e8b\u4ef6\u76d1\u63a7<br \/>\n        void DisableAll() { _events &#061; 0; Update(); }<br \/>\n        \/\/\u79fb\u9664\u76d1\u63a7<br \/>\n        void Remove();<br \/>\n        void Update();<br \/>\n        \/\/\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\u5904\u7406\u81ea\u5df1\u51b3\u5b9a<br \/>\n        void HandleEvent() {<br \/>\n            if ((_revents &amp; EPOLLIN) || (_revents &amp; EPOLLRDHUP) || (_revents &amp; EPOLLPRI)) {<br \/>\n                \/*\u4e0d\u7ba1\u4efb\u4f55\u4e8b\u4ef6&#xff0c;\u90fd\u8c03\u7528\u7684\u56de\u8c03\u51fd\u6570*\/<br \/>\n                if (_read_callback) _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                if (_write_callback) _write_callback();<br \/>\n            }else if (_revents &amp; EPOLLERR) {<br \/>\n                if (_error_callback) _error_callback();\/\/\u4e00\u65e6\u51fa\u9519&#xff0c;\u5c31\u4f1a\u91ca\u653e\u8fde\u63a5&#xff0c;\u56e0\u6b64\u8981\u653e\u5230\u524d\u8fb9\u8c03\u7528\u4efb\u610f\u56de\u8c03<br \/>\n            }else if (_revents &amp; EPOLLHUP) {<br \/>\n                if (_close_callback) _close_callback();<br \/>\n            }<br \/>\n            if (_event_callback) _event_callback();<br \/>\n        }<br \/>\n}; <\/p>\n<h5 id=\"Connection%E6%A8%A1%E5%9D%97%EF%BC%9A\">Connection\u6a21\u5757&#xff1a;<\/h5>\n<p>Connection\u6a21\u5757\u662f\u5bf9Buffer\u6a21\u5757&#xff0c;Socket\u6a21\u5757&#xff0c;Channel\u6a21\u5757\u7684\u2f00\u4e2a\u6574\u4f53\u5c01\u88c5&#xff0c;\u5b9e\u73b0\u4e86\u5bf9\u2f00\u4e2a\u901a\u4fe1\u5957\u63a5\u5b57\u7684\u6574\u4f53\u7684\u7ba1\u7406&#xff0c;\u6bcf\u2f00\u4e2a\u8fdb\u2f8f\u6570\u636e\u901a\u4fe1\u7684\u5957\u63a5\u5b57&#xff08;\u4e5f\u5c31\u662faccept\u83b7\u53d6\u5230\u7684\u65b0\u8fde\u63a5&#xff09;\u90fd\u4f1a\u4f7f\u2f64 Connection\u8fdb\u2f8f\u7ba1\u7406\u3002<\/p>\n<p>class Connection : public std::enable_shared_from_this&lt;Connection&gt; {<br \/>\n    private:<br \/>\n        uint64_t _conn_id;  \/\/ \u8fde\u63a5\u7684\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;\u8fd9\u5757\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\u7684\u5224\u65ad\u6807\u5fd7&#xff0c;\u9ed8\u8ba4\u4e3afalse<br \/>\n        EventLoop *_loop;   \/\/ \u8fde\u63a5\u6240\u5173\u8054\u7684\u4e00\u4e2aEventLoop<br \/>\n        ConnStatu _statu;   \/\/ \u8fde\u63a5\u72b6\u6001<br \/>\n        Socket _socket;     \/\/ \u5957\u63a5\u5b57\u64cd\u4f5c\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\u63a5\u6536\u5904\u7406\u4e0a\u4e0b\u6587<\/p>\n<p>        \/*\u8fd9\u56db\u4e2a\u56de\u8c03\u51fd\u6570&#xff0c;\u662f\u8ba9\u670d\u52a1\u5668\u6a21\u5757\u6765\u8bbe\u7f6e\u7684&#xff08;\u5176\u5b9e\u670d\u52a1\u5668\u6a21\u5757\u7684\u5904\u7406\u56de\u8c03\u4e5f\u662f\u7ec4\u4ef6\u4f7f\u7528\u8005\u8bbe\u7f6e\u7684&#xff09;*\/<br \/>\n        \/*\u6362\u53e5\u8bdd\u8bf4&#xff0c;\u8fd9\u51e0\u4e2a\u56de\u8c03\u90fd\u662f\u7ec4\u4ef6\u4f7f\u7528\u8005\u4f7f\u7528\u7684*\/<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\u8fde\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;<br \/>\n    private:<br \/>\n        \/*\u4e94\u4e2achannel\u7684\u4e8b\u4ef6\u56de\u8c03\u51fd\u6570*\/<br \/>\n        \/\/\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<br \/>\n        void HandleRead() {<br \/>\n            \/\/1. \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                \/\/\u51fa\u9519\u4e86,\u4e0d\u80fd\u76f4\u63a5\u5173\u95ed\u8fde\u63a5<br \/>\n                return ShutdownInLoop();<br \/>\n            }<br \/>\n            \/\/\u8fd9\u91cc\u7684\u7b49\u4e8e0\u8868\u793a\u7684\u662f\u6ca1\u6709\u8bfb\u53d6\u5230\u6570\u636e&#xff0c;\u800c\u5e76\u4e0d\u662f\u8fde\u63a5\u65ad\u5f00\u4e86&#xff0c;\u8fde\u63a5\u65ad\u5f00\u8fd4\u56de\u7684\u662f-1<br \/>\n            \/\/\u5c06\u6570\u636e\u653e\u5165\u8f93\u5165\u7f13\u51b2\u533a,\u5199\u5165\u4e4b\u540e\u987a\u4fbf\u5c06\u5199\u504f\u79fb\u5411\u540e\u79fb\u52a8<br \/>\n            _in_buffer.WriteAndPush(buf, ret);<br \/>\n            \/\/2. \u8c03\u7528message_callback\u8fdb\u884c\u4e1a\u52a1\u5904\u7406<br \/>\n            if (_in_buffer.ReadAbleSize() &gt; 0) {<br \/>\n                \/\/shared_from_this&#8211;\u4ece\u5f53\u524d\u5bf9\u8c61\u81ea\u8eab\u83b7\u53d6\u81ea\u8eab\u7684shared_ptr\u7ba1\u7406\u5bf9\u8c61<br \/>\n                return _message_callback(shared_from_this(), &amp;_in_buffer);<br \/>\n            }<br \/>\n        }<br \/>\n        \/\/\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        void HandleWrite() {<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                \/\/\u53d1\u9001\u9519\u8bef\u5c31\u8be5\u5173\u95ed\u8fde\u63a5\u4e86&#xff0c;<br \/>\n                if (_in_buffer.ReadAbleSize() &gt; 0) {<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\u4e86\u3002<br \/>\n            }<br \/>\n            _out_buffer.MoveReadOffset(ret);\/\/\u5343\u4e07\u4e0d\u8981\u5fd8\u4e86&#xff0c;\u5c06\u8bfb\u504f\u79fb\u5411\u540e\u79fb\u52a8<br \/>\n            if (_out_buffer.ReadAbleSize() &#061;&#061; 0) {<br \/>\n                _channel.DisableWrite();\/\/ \u6ca1\u6709\u6570\u636e\u5f85\u53d1\u9001\u4e86&#xff0c;\u5173\u95ed\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n                \/\/\u5982\u679c\u5f53\u524d\u662f\u8fde\u63a5\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                    return Release();<br \/>\n                }<br \/>\n            }<br \/>\n            return;<br \/>\n        }<br \/>\n        \/\/\u63cf\u8ff0\u7b26\u89e6\u53d1\u6302\u65ad\u4e8b\u4ef6<br \/>\n        void HandleClose() {<br \/>\n            \/*\u4e00\u65e6\u8fde\u63a5\u6302\u65ad\u4e86&#xff0c;\u5957\u63a5\u5b57\u5c31\u4ec0\u4e48\u90fd\u5e72\u4e0d\u4e86\u4e86&#xff0c;\u56e0\u6b64\u6709\u6570\u636e\u5f85\u5904\u7406\u5c31\u5904\u7406\u4e00\u4e0b&#xff0c;\u5b8c\u6bd5\u5173\u95ed\u8fde\u63a5*\/<br \/>\n            if (_in_buffer.ReadAbleSize() &gt; 0) {<br \/>\n                _message_callback(shared_from_this(), &amp;_in_buffer);<br \/>\n            }<br \/>\n            return Release();<br \/>\n        }<br \/>\n        \/\/\u63cf\u8ff0\u7b26\u89e6\u53d1\u51fa\u9519\u4e8b\u4ef6<br \/>\n        void HandleError() {<br \/>\n            return HandleClose();<br \/>\n        }<br \/>\n        \/\/\u63cf\u8ff0\u7b26\u89e6\u53d1\u4efb\u610f\u4e8b\u4ef6: 1. \u5237\u65b0\u8fde\u63a5\u7684\u6d3b\u8dc3\u5ea6&#8211;\u5ef6\u8fdf\u5b9a\u65f6\u9500\u6bc1\u4efb\u52a1&#xff1b;  2. \u8c03\u7528\u7ec4\u4ef6\u4f7f\u7528\u8005\u7684\u4efb\u610f\u4e8b\u4ef6\u56de\u8c03<br \/>\n        void HandleEvent() {<br \/>\n            if (_enable_inactive_release &#061;&#061; true)  {  _loop-&gt;TimerRefresh(_conn_id); }<br \/>\n            if (_event_callback)  {  _event_callback(shared_from_this()); }<br \/>\n        }<br \/>\n        \/\/\u8fde\u63a5\u83b7\u53d6\u4e4b\u540e&#xff0c;\u6240\u5904\u7684\u72b6\u6001\u4e0b\u8981\u8fdb\u884c\u5404\u79cd\u8bbe\u7f6e&#xff08;\u542f\u52a8\u8bfb\u76d1\u63a7,\u8c03\u7528\u56de\u8c03\u51fd\u6570&#xff09;<br \/>\n        void EstablishedInLoop() {<br \/>\n            \/\/ 1. \u4fee\u6539\u8fde\u63a5\u72b6\u6001&#xff1b;  2. \u542f\u52a8\u8bfb\u4e8b\u4ef6\u76d1\u63a7&#xff1b;  3. \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\u8fde\u63a5\u9500\u6bc1<br \/>\n            _channel.EnableRead();<br \/>\n            if (_connected_callback) _connected_callback(shared_from_this());<br \/>\n        }<br \/>\n        \/\/\u8fd9\u4e2a\u63a5\u53e3\u624d\u662f\u5b9e\u9645\u7684\u91ca\u653e\u63a5\u53e3<br \/>\n        void ReleaseInLoop() {<br \/>\n            \/\/1. \u4fee\u6539\u8fde\u63a5\u72b6\u6001&#xff0c;\u5c06\u5176\u7f6e\u4e3aDISCONNECTED<br \/>\n            _statu &#061; DISCONNECTED;<br \/>\n            \/\/2. \u79fb\u9664\u8fde\u63a5\u7684\u4e8b\u4ef6\u76d1\u63a7<br \/>\n            _channel.Remove();<br \/>\n            \/\/3. \u5173\u95ed\u63cf\u8ff0\u7b26<br \/>\n            _socket.Close();<br \/>\n            \/\/4. \u5982\u679c\u5f53\u524d\u5b9a\u65f6\u5668\u961f\u5217\u4e2d\u8fd8\u6709\u5b9a\u65f6\u9500\u6bc1\u4efb\u52a1&#xff0c;\u5219\u53d6\u6d88\u4efb\u52a1<br \/>\n            if (_loop-&gt;HasTimer(_conn_id)) CancelInactiveReleaseInLoop();<br \/>\n            \/\/5. \u8c03\u7528\u5173\u95ed\u56de\u8c03\u51fd\u6570&#xff0c;\u907f\u514d\u5148\u79fb\u9664\u670d\u52a1\u5668\u7ba1\u7406\u7684\u8fde\u63a5\u4fe1\u606f\u5bfc\u81f4Connection\u88ab\u91ca\u653e&#xff0c;\u518d\u53bb\u5904\u7406\u4f1a\u51fa\u9519&#xff0c;\u56e0\u6b64\u5148\u8c03\u7528\u7528\u6237\u7684\u56de\u8c03\u51fd\u6570<br \/>\n            if (_closed_callback) _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) _server_closed_callback(shared_from_this());<br \/>\n        }<br \/>\n        \/\/\u8fd9\u4e2a\u63a5\u53e3\u5e76\u4e0d\u662f\u5b9e\u9645\u7684\u53d1\u9001\u63a5\u53e3&#xff0c;\u800c\u53ea\u662f\u628a\u6570\u636e\u653e\u5230\u4e86\u53d1\u9001\u7f13\u51b2\u533a&#xff0c;\u542f\u52a8\u4e86\u53ef\u5199\u4e8b\u4ef6\u76d1\u63a7<br \/>\n        void SendInLoop(Buffer &amp;buf) {<br \/>\n            if (_statu &#061;&#061; DISCONNECTED) return ;<br \/>\n            _out_buffer.WriteBufferAndPush(buf);<br \/>\n            if (_channel.WriteAble() &#061;&#061; false) {<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            _statu &#061; DISCONNECTING;\/\/ \u8bbe\u7f6e\u8fde\u63a5\u4e3a\u534a\u5173\u95ed\u72b6\u6001<br \/>\n            if (_in_buffer.ReadAbleSize() &gt; 0) {<br \/>\n                if (_message_callback) _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                if (_channel.WriteAble() &#061;&#061; false) {<br \/>\n                    _channel.EnableWrite();<br \/>\n                }<br \/>\n            }<br \/>\n            if (_out_buffer.ReadAbleSize() &#061;&#061; 0) {<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            \/\/1. \u5c06\u5224\u65ad\u6807\u5fd7 _enable_inactive_release \u7f6e\u4e3atrue<br \/>\n            _enable_inactive_release &#061; true;<br \/>\n            \/\/2. \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                return _loop-&gt;TimerRefresh(_conn_id);<br \/>\n            }<br \/>\n            \/\/3. \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            _enable_inactive_release &#061; false;<br \/>\n            if (_loop-&gt;HasTimer(_conn_id)) {<br \/>\n                _loop-&gt;TimerCancel(_conn_id);<br \/>\n            }<br \/>\n        }<br \/>\n        void UpgradeInLoop(const Any &amp;context,<br \/>\n                    const ConnectedCallback &amp;conn,<br \/>\n                    const MessageCallback &amp;msg,<br \/>\n                    const ClosedCallback &amp;closed,<br \/>\n                    const AnyEventCallback &amp;event) {<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        }<br \/>\n    public:<br \/>\n        Connection(EventLoop *loop, uint64_t conn_id, int sockfd):_conn_id(conn_id), _sockfd(sockfd),<br \/>\n            _enable_inactive_release(false), _loop(loop), _statu(CONNECTING), _socket(_sockfd),<br \/>\n            _channel(loop, _sockfd) {<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() { DBG_LOG(&#034;RELEASE CONNECTION:%p&#034;, this); }<br \/>\n        \/\/\u83b7\u53d6\u7ba1\u7406\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26<br \/>\n        int Fd() { return _sockfd; }<br \/>\n        \/\/\u83b7\u53d6\u8fde\u63a5ID<br \/>\n        int Id() { return _conn_id; }<br \/>\n        \/\/\u662f\u5426\u5904\u4e8eCONNECTED\u72b6\u6001<br \/>\n        bool Connected() { return (_statu &#061;&#061; CONNECTED); }<br \/>\n        \/\/\u8bbe\u7f6e\u4e0a\u4e0b\u6587&#8211;\u8fde\u63a5\u5efa\u7acb\u5b8c\u6210\u65f6\u8fdb\u884c\u8c03\u7528<br \/>\n        void SetContext(const Any &amp;context) { _context &#061; context; }<br \/>\n        \/\/\u83b7\u53d6\u4e0a\u4e0b\u6587&#xff0c;\u8fd4\u56de\u7684\u662f\u6307\u9488<br \/>\n        Any *GetContext() { return &amp;_context; }<br \/>\n        void SetConnectedCallback(const ConnectedCallback&amp;cb) { _connected_callback &#061; cb; }<br \/>\n        void SetMessageCallback(const MessageCallback&amp;cb) { _message_callback &#061; cb; }<br \/>\n        void SetClosedCallback(const ClosedCallback&amp;cb) { _closed_callback &#061; cb; }<br \/>\n        void SetAnyEventCallback(const AnyEventCallback&amp;cb) { _event_callback &#061; cb; }<br \/>\n        void SetSrvClosedCallback(const ClosedCallback&amp;cb) { _server_closed_callback &#061; cb; }<br \/>\n        \/\/\u8fde\u63a5\u5efa\u7acb\u5c31\u7eea\u540e&#xff0c;\u8fdb\u884cchannel\u56de\u8c03\u8bbe\u7f6e&#xff0c;\u542f\u52a8\u8bfb\u76d1\u63a7&#xff0c;\u8c03\u7528_connected_callback<br \/>\n        void Established() {<br \/>\n            _loop-&gt;RunInLoop(std::bind(&amp;Connection::EstablishedInLoop, this));<br \/>\n        }<br \/>\n        \/\/\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        void Send(const char *data, size_t len) {<br \/>\n            \/\/\u5916\u754c\u4f20\u5165\u7684data&#xff0c;\u53ef\u80fd\u662f\u4e2a\u4e34\u65f6\u7684\u7a7a\u95f4&#xff0c;\u6211\u4eec\u73b0\u5728\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\u3002<br \/>\n            Buffer buf;<br \/>\n            buf.WriteAndPush(data, len);<br \/>\n            _loop-&gt;RunInLoop(std::bind(&amp;Connection::SendInLoop, this, std::move(buf)));<br \/>\n        }<br \/>\n        \/\/\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\u6570\u636e\u5f85\u5904\u7406<br \/>\n        void Shutdown() {<br \/>\n            _loop-&gt;RunInLoop(std::bind(&amp;Connection::ShutdownInLoop, this));<br \/>\n        }<br \/>\n        void Release() {<br \/>\n            _loop-&gt;QueueInLoop(std::bind(&amp;Connection::ReleaseInLoop, this));<br \/>\n        }<br \/>\n        \/\/\u542f\u52a8\u975e\u6d3b\u8dc3\u9500\u6bc1&#xff0c;\u5e76\u5b9a\u4e49\u591a\u957f\u65f6\u95f4\u65e0\u901a\u4fe1\u5c31\u662f\u975e\u6d3b\u8dc3&#xff0c;\u6dfb\u52a0\u5b9a\u65f6\u4efb\u52a1<br \/>\n        void EnableInactiveRelease(int sec) {<br \/>\n            _loop-&gt;RunInLoop(std::bind(&amp;Connection::EnableInactiveReleaseInLoop, this, sec));<br \/>\n        }<br \/>\n        \/\/\u53d6\u6d88\u975e\u6d3b\u8dc3\u9500\u6bc1<br \/>\n        void CancelInactiveRelease() {<br \/>\n            _loop-&gt;RunInLoop(std::bind(&amp;Connection::CancelInactiveReleaseInLoop, this));<br \/>\n        }<br \/>\n        \/\/\u5207\u6362\u534f\u8bae&#8212;\u91cd\u7f6e\u4e0a\u4e0b\u6587\u4ee5\u53ca\u9636\u6bb5\u6027\u56de\u8c03\u5904\u7406\u51fd\u6570 &#8212; \u800c\u662f\u8fd9\u4e2a\u63a5\u53e3\u5fc5\u987b\u5728EventLoop\u7ebf\u7a0b\u4e2d\u7acb\u5373\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&#8211;\u4f1a\u5bfc\u81f4\u6570\u636e\u4f7f\u7528\u539f\u534f\u8bae\u5904\u7406\u4e86\u3002<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            _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<h5 id=\"Acceptor%E6%A8%A1%E5%9D%97%EF%BC%9A\">Acceptor\u6a21\u5757&#xff1a;<\/h5>\n<p>Acceptor\u6a21\u5757\u662f\u5bf9Socket\u6a21\u5757&#xff0c;Channel\u6a21\u5757\u7684\u2f00\u4e2a\u6574\u4f53\u5c01\u88c5&#xff0c;\u5b9e\u73b0\u4e86\u5bf9\u2f00\u4e2a\u76d1\u542c\u5957\u63a5\u5b57\u7684\u6574\u4f53\u7684\u7ba1\u7406\u3002<\/p>\n<p>class Acceptor {<br \/>\n    private:<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<\/p>\n<p>        using AcceptCallback &#061; std::function&lt;void(int)&gt;;<br \/>\n        AcceptCallback _accept_callback;<br \/>\n    private:<br \/>\n        \/*\u76d1\u542c\u5957\u63a5\u5b57\u7684\u8bfb\u4e8b\u4ef6\u56de\u8c03\u5904\u7406\u51fd\u6570&#8212;\u83b7\u53d6\u65b0\u8fde\u63a5&#xff0c;\u8c03\u7528_accept_callback\u51fd\u6570\u8fdb\u884c\u65b0\u8fde\u63a5\u5904\u7406*\/<br \/>\n        void HandleRead() {<br \/>\n            int newfd &#061; _socket.Accept();<br \/>\n            if (newfd &lt; 0) {<br \/>\n                return ;<br \/>\n            }<br \/>\n            if (_accept_callback) _accept_callback(newfd);<br \/>\n        }<br \/>\n        int CreateServer(int port) {<br \/>\n            bool ret &#061; _socket.CreateServer(port);<br \/>\n            assert(ret &#061;&#061; true);<br \/>\n            return _socket.Fd();<br \/>\n        }<br \/>\n    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\u8fde\u63a5\u5f97\u4e0d\u5230\u5904\u7406&#xff0c;\u4e14\u8d44\u6e90\u6cc4\u6f0f*\/<br \/>\n        Acceptor(EventLoop *loop, int port): _socket(CreateServer(port)), _loop(loop),<br \/>\n            _channel(loop, _socket.Fd()) {<br \/>\n            _channel.SetReadCallback(std::bind(&amp;Acceptor::HandleRead, this));<br \/>\n        }<br \/>\n        void SetAcceptCallback(const AcceptCallback &amp;cb) { _accept_callback &#061; cb; }<br \/>\n        void Listen() { _channel.EnableRead(); }<br \/>\n}; <\/p>\n<h5 id=\"TimerQueue%E6%A8%A1%E5%9D%97%EF%BC%9A\">TimerQueue\u6a21\u5757&#xff1a;<\/h5>\n<p>TimerQueue\u6a21\u5757\u662f\u5b9e\u73b0\u56fa\u5b9a\u65f6\u95f4\u5b9a\u65f6\u4efb\u52a1\u7684\u6a21\u5757&#xff0c;\u53ef\u4ee5\u7406\u89e3\u5c31\u662f\u8981\u7ed9\u5b9a\u65f6\u4efb\u52a1\u7ba1\u7406\u5668&#xff0c;\u5411\u5b9a\u65f6\u4efb\u52a1\u7ba1\u7406\u5668\u4e2d\u6dfb\u52a0\u2f00\u4e2a\u4efb\u52a1&#xff0c;\u4efb\u52a1\u5c06\u5728\u56fa\u5b9a\u65f6\u95f4\u540e\u88ab\u6267\u2f8f&#xff0c;\u540c\u65f6\u4e5f\u53ef\u4ee5\u901a\u8fc7\u5237\u65b0\u5b9a\u65f6\u4efb\u52a1\u6765\u5ef6\u8fdf\u4efb\u52a1\u7684\u6267\u2f8f\u3002<\/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    private:<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&#xff0c; true-\u8868\u793a\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 \/>\n    public:<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        ~TimerTask() {<br \/>\n            if (_canceled &#061;&#061; false) _task_cb();<br \/>\n            _release();<br \/>\n        }<br \/>\n        void Cancel() { _canceled &#061; true; }<br \/>\n        void SetRelease(const ReleaseFunc &amp;cb) { _release &#061; cb; }<br \/>\n        uint32_t DelayTime() { return _timeout; }<br \/>\n};<\/p>\n<p>class TimerWheel {<br \/>\n    private:<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&#xff0c;\u91ca\u653e\u54ea\u91cc&#xff0c;\u5c31\u76f8\u5f53\u4e8e\u6267\u884c\u54ea\u91cc\u7684\u4efb\u52a1<br \/>\n        int _capacity;  \/\/\u8868\u76d8\u6700\u5927\u6570\u91cf&#8212;\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;<\/p>\n<p>        EventLoop *_loop;<br \/>\n        int _timerfd;\/\/\u5b9a\u65f6\u5668\u63cf\u8ff0\u7b26&#8211;\u53ef\u8bfb\u4e8b\u4ef6\u56de\u8c03\u5c31\u662f\u8bfb\u53d6\u8ba1\u6570\u5668&#xff0c;\u6267\u884c\u5b9a\u65f6\u4efb\u52a1<br \/>\n        std::unique_ptr&lt;Channel&gt; _timer_channel;<br \/>\n    private:<br \/>\n        void RemoveTimer(uint64_t id) {<br \/>\n            auto it &#061; _timers.find(id);<br \/>\n            if (it !&#061; _timers.end()) {<br \/>\n                _timers.erase(it);<br \/>\n            }<br \/>\n        }<br \/>\n        static int CreateTimerfd() {<br \/>\n            int timerfd &#061; timerfd_create(CLOCK_MONOTONIC, 0);<br \/>\n            if (timerfd &lt; 0) {<br \/>\n                ERR_LOG(&#034;TIMERFD CREATE FAILED!&#034;);<br \/>\n                abort();<br \/>\n            }<br \/>\n            \/\/int timerfd_settime(int fd, int flags, struct itimerspec *new, struct itimerspec *old);<br \/>\n            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\u95f4\u9694\u65f6<br \/>\n            timerfd_settime(timerfd, 0, &amp;itime, NULL);<br \/>\n            return timerfd;<br \/>\n        }<br \/>\n        int ReadTimefd() {<br \/>\n            uint64_t times;<br \/>\n            \/\/\u6709\u53ef\u80fd\u56e0\u4e3a\u5176\u4ed6\u63cf\u8ff0\u7b26\u7684\u4e8b\u4ef6\u5904\u7406\u82b1\u8d39\u4e8b\u4ef6\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                ERR_LOG(&#034;READ TIMEFD FAILED!&#034;);<br \/>\n                abort();<br \/>\n            }<br \/>\n            return times;<br \/>\n        }<br \/>\n        \/\/\u8fd9\u4e2a\u51fd\u6570\u5e94\u8be5\u6bcf\u79d2\u949f\u88ab\u6267\u884c\u4e00\u6b21&#xff0c;\u76f8\u5f53\u4e8e\u79d2\u9488\u5411\u540e\u8d70\u4e86\u4e00\u6b65<br \/>\n        void RunTimerTask() {<br \/>\n            _tick &#061; (_tick &#043; 1) % _capacity;<br \/>\n            _wheel[_tick].clear();\/\/\u6e05\u7a7a\u6307\u5b9a\u4f4d\u7f6e\u7684\u6570\u7ec4&#xff0c;\u5c31\u4f1a\u628a\u6570\u7ec4\u4e2d\u4fdd\u5b58\u7684\u6240\u6709\u7ba1\u7406\u5b9a\u65f6\u5668\u5bf9\u8c61\u7684shared_ptr\u91ca\u653e\u6389<br \/>\n        }<br \/>\n        void OnTime() {<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                RunTimerTask();<br \/>\n            }<br \/>\n        }<br \/>\n        void TimerAddInLoop(uint64_t id, uint32_t delay, const TaskFunc &amp;cb) {<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 TimerRefreshInLoop(uint64_t id) {<br \/>\n            \/\/\u901a\u8fc7\u4fdd\u5b58\u7684\u5b9a\u65f6\u5668\u5bf9\u8c61\u7684weak_ptr\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                return;\/\/\u6ca1\u627e\u7740\u5b9a\u65f6\u4efb\u52a1&#xff0c;\u6ca1\u6cd5\u5237\u65b0&#xff0c;\u6ca1\u6cd5\u5ef6\u8fdf<br \/>\n            }<br \/>\n            PtrTask pt &#061; it-&gt;second.lock();\/\/lock\u83b7\u53d6weak_ptr\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 TimerCancelInLoop(uint64_t id) {<br \/>\n            auto it &#061; _timers.find(id);<br \/>\n            if (it &#061;&#061; _timers.end()) {<br \/>\n                return;\/\/\u6ca1\u627e\u7740\u5b9a\u65f6\u4efb\u52a1&#xff0c;\u6ca1\u6cd5\u5237\u65b0&#xff0c;\u6ca1\u6cd5\u5ef6\u8fdf<br \/>\n            }<br \/>\n            PtrTask pt &#061; it-&gt;second.lock();<br \/>\n            if (pt) pt-&gt;Cancel();<br \/>\n        }<br \/>\n    public:<br \/>\n        TimerWheel(EventLoop *loop):_capacity(60), _tick(0), _wheel(_capacity), _loop(loop),<br \/>\n            _timerfd(CreateTimerfd()), _timer_channel(new Channel(_loop, _timerfd)) {<br \/>\n            _timer_channel-&gt;SetReadCallback(std::bind(&amp;TimerWheel::OnTime, this));<br \/>\n            _timer_channel-&gt;EnableRead();\/\/\u542f\u52a8\u8bfb\u4e8b\u4ef6\u76d1\u63a7<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\u671f\u7684\u6240\u6709\u64cd\u4f5c&#xff0c;\u90fd\u653e\u5230\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            auto it &#061; _timers.find(id);<br \/>\n            if (it &#061;&#061; _timers.end()) {<br \/>\n                return false;<br \/>\n            }<br \/>\n            return true;<br \/>\n        }<br \/>\n}; <\/p>\n<h5 id=\"Poller%E6%A8%A1%E5%9D%97%EF%BC%9A\">Poller\u6a21\u5757&#xff1a;<\/h5>\n<p>Poller\u6a21\u5757\u662f\u5bf9epoll\u8fdb\u2f8f\u5c01\u88c5\u7684\u2f00\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\u3002<\/p>\n<p>class Poller {<br \/>\n    private:<br \/>\n        int _epfd;<br \/>\n        struct epoll_event _evs[MAX_EPOLLEVENTS];<br \/>\n        std::unordered_map&lt;int, Channel *&gt; _channels;<br \/>\n    private:<br \/>\n        \/\/\u5bf9epoll\u7684\u76f4\u63a5\u64cd\u4f5c<br \/>\n        void Update(Channel *channel, int op) {<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                ERR_LOG(&#034;EPOLLCTL FAILED!&#034;);<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            auto it &#061; _channels.find(channel-&gt;Fd());<br \/>\n            if (it &#061;&#061; _channels.end()) {<br \/>\n                return false;<br \/>\n            }<br \/>\n            return true;<br \/>\n        }<br \/>\n    public:<br \/>\n        Poller() {<br \/>\n            _epfd &#061; epoll_create(MAX_EPOLLEVENTS);<br \/>\n            if (_epfd &lt; 0) {<br \/>\n                ERR_LOG(&#034;EPOLL CREATE FAILED!!&#034;);<br \/>\n                abort();\/\/\u9000\u51fa\u7a0b\u5e8f<br \/>\n            }<br \/>\n        }<br \/>\n        \/\/\u6dfb\u52a0\u6216\u4fee\u6539\u76d1\u63a7\u4e8b\u4ef6<br \/>\n        void UpdateEvent(Channel *channel) {<br \/>\n            bool ret &#061; HasChannel(channel);<br \/>\n            if (ret &#061;&#061; false) {<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        \/\/\u79fb\u9664\u76d1\u63a7<br \/>\n        void RemoveEvent(Channel *channel) {<br \/>\n            auto it &#061; _channels.find(channel-&gt;Fd());<br \/>\n            if (it !&#061; _channels.end()) {<br \/>\n                _channels.erase(it);<br \/>\n            }<br \/>\n            Update(channel, EPOLL_CTL_DEL);<br \/>\n        }<br \/>\n        \/\/\u5f00\u59cb\u76d1\u63a7&#xff0c;\u8fd4\u56de\u6d3b\u8dc3\u8fde\u63a5<br \/>\n        void Poll(std::vector&lt;Channel*&gt; *active) {<br \/>\n            \/\/ int epoll_wait(int epfd, struct epoll_event *evs, int maxevents, int timeout)<br \/>\n            int nfds &#061; epoll_wait(_epfd, _evs, MAX_EPOLLEVENTS, -1);<br \/>\n            if (nfds &lt; 0) {<br \/>\n                if (errno &#061;&#061; EINTR) {<br \/>\n                    return ;<br \/>\n                }<br \/>\n                ERR_LOG(&#034;EPOLL WAIT ERROR:%s\\\\n&#034;, strerror(errno));<br \/>\n                abort();\/\/\u9000\u51fa\u7a0b\u5e8f<br \/>\n            }<br \/>\n            for (int i &#061; 0; i &lt; nfds; i&#043;&#043;) {<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);\/\/\u8bbe\u7f6e\u5b9e\u9645\u5c31\u7eea\u7684\u4e8b\u4ef6<br \/>\n                active-&gt;push_back(it-&gt;second);<br \/>\n            }<br \/>\n            return;<br \/>\n        }<br \/>\n}; <\/p>\n<h5 id=\"EventLoop%E6%A8%A1%E5%9D%97%EF%BC%9A\">EventLoop\u6a21\u5757&#xff1a;<\/h5>\n<p>EventLoop\u6a21\u5757\u53ef\u4ee5\u7406\u89e3\u5c31\u662f\u6211\u4eec\u4e0a\u8fb9\u6240\u8bf4\u7684Reactor\u6a21\u5757&#xff0c;\u5b83\u662f\u5bf9Poller\u6a21\u5757&#xff0c;TimerQueue\u6a21\u5757&#xff0c;Socket\u6a21\u5757\u7684\u2f00\u4e2a\u6574\u4f53\u5c01\u88c5&#xff0c;\u8fdb\u2f8f\u6240\u6709\u63cf\u8ff0\u7b26\u7684\u4e8b\u4ef6\u76d1\u63a7\u3002 EventLoop\u6a21\u5757\u5fc5\u7136\u662f\u2f00\u4e2a\u5bf9\u8c61\u5bf9\u5e94\u2f00\u4e2a\u7ebf\u7a0b\u7684\u6a21\u5757&#xff0c;\u7ebf\u7a0b\u5185\u90e8\u7684\u2f6c\u7684\u5c31\u662f\u8fd0\u2f8fEventLoop\u7684\u542f\u52a8\u51fd\u6570\u3002<\/p>\n<p>class EventLoop {<br \/>\n    private:<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;<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 \/>\n    public:<br \/>\n        \/\/\u6267\u884c\u4efb\u52a1\u6c60\u4e2d\u7684\u6240\u6709\u4efb\u52a1<br \/>\n        void RunAllTask() {<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);<br \/>\n            }<br \/>\n            for (auto &amp;f : functor) {<br \/>\n                f();<br \/>\n            }<br \/>\n            return ;<br \/>\n        }<br \/>\n        static int CreateEventFd() {<br \/>\n            int efd &#061; eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);<br \/>\n            if (efd &lt; 0) {<br \/>\n                ERR_LOG(&#034;CREATE EVENTFD FAILED!!&#034;);<br \/>\n                abort();\/\/\u8ba9\u7a0b\u5e8f\u5f02\u5e38\u9000\u51fa<br \/>\n            }<br \/>\n            return efd;<br \/>\n        }<br \/>\n        void ReadEventfd() {<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                \/\/EINTR &#8212; \u88ab\u4fe1\u53f7\u6253\u65ad&#xff1b;   EAGAIN &#8212; \u8868\u793a\u65e0\u6570\u636e\u53ef\u8bfb<br \/>\n                if (errno &#061;&#061; EINTR || errno &#061;&#061; EAGAIN) {<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 WeakUpEventFd() {<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                if (errno &#061;&#061; EINTR) {<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    public:<br \/>\n        EventLoop():_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            \/\/\u7ed9eventfd\u6dfb\u52a0\u53ef\u8bfb\u4e8b\u4ef6\u56de\u8c03\u51fd\u6570&#xff0c;\u8bfb\u53d6eventfd\u4e8b\u4ef6\u901a\u77e5\u6b21\u6570<br \/>\n            _event_channel-&gt;SetReadCallback(std::bind(&amp;EventLoop::ReadEventfd, this));<br \/>\n            \/\/\u542f\u52a8eventfd\u7684\u8bfb\u4e8b\u4ef6\u76d1\u63a7<br \/>\n            _event_channel-&gt;EnableRead();<br \/>\n        }<br \/>\n        \/\/\u4e09\u6b65\u8d70&#8211;\u4e8b\u4ef6\u76d1\u63a7-\u300b\u5c31\u7eea\u4e8b\u4ef6\u5904\u7406-\u300b\u6267\u884c\u4efb\u52a1<br \/>\n        void Start() {<br \/>\n            while(1) {<br \/>\n                \/\/1. \u4e8b\u4ef6\u76d1\u63a7&#xff0c;<br \/>\n                std::vector&lt;Channel *&gt; actives;<br \/>\n                _poller.Poll(&amp;actives);<br \/>\n                \/\/2. \u4e8b\u4ef6\u5904\u7406\u3002<br \/>\n                for (auto &amp;channel : actives) {<br \/>\n                    channel-&gt;HandleEvent();<br \/>\n                }<br \/>\n                \/\/3. \u6267\u884c\u4efb\u52a1<br \/>\n                RunAllTask();<br \/>\n            }<br \/>\n        }<br \/>\n        \/\/\u7528\u4e8e\u5224\u65ad\u5f53\u524d\u7ebf\u7a0b\u662f\u5426\u662fEventLoop\u5bf9\u5e94\u7684\u7ebf\u7a0b&#xff1b;<br \/>\n        bool IsInLoop() {<br \/>\n            return (_thread_id &#061;&#061; std::this_thread::get_id());<br \/>\n        }<br \/>\n        void AssertInLoop() {<br \/>\n            assert(_thread_id &#061;&#061; std::this_thread::get_id());<br \/>\n        }<br \/>\n        \/\/\u5224\u65ad\u5c06\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\u3002<br \/>\n        void RunInLoop(const Functor &amp;cb) {<br \/>\n            if (IsInLoop()) {<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                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&#xff0c;\u800c\u5bfc\u81f4\u7684epoll\u963b\u585e&#xff1b;<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            WeakUpEventFd();<br \/>\n        }<br \/>\n        \/\/\u6dfb\u52a0\/\u4fee\u6539\u63cf\u8ff0\u7b26\u7684\u4e8b\u4ef6\u76d1\u63a7<br \/>\n        void UpdateEvent(Channel *channel) { return _poller.UpdateEvent(channel); }<br \/>\n        \/\/\u79fb\u9664\u63cf\u8ff0\u7b26\u7684\u76d1\u63a7<br \/>\n        void RemoveEvent(Channel *channel) { return _poller.RemoveEvent(channel); }<br \/>\n        void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &amp;cb) { return _timer_wheel.TimerAdd(id, delay, cb); }<br \/>\n        void TimerRefresh(uint64_t id) { return _timer_wheel.TimerRefresh(id); }<br \/>\n        void TimerCancel(uint64_t id) { return _timer_wheel.TimerCancel(id); }<br \/>\n        bool HasTimer(uint64_t id) { return _timer_wheel.HasTimer(id); }<br \/>\n}; <\/p>\n<h5 id=\"TcpServer%E6%A8%A1%E5%9D%97%EF%BC%9A\">TcpServer\u6a21\u5757&#xff1a;<\/h5>\n<p>\u8fd9\u4e2a\u6a21\u5757\u662f\u2f00\u4e2a\u6574\u4f53Tcp\u670d\u52a1\u5668\u6a21\u5757\u7684\u5c01\u88c5&#xff0c;\u5185\u90e8\u5c01\u88c5\u4e86Acceptor\u6a21\u5757&#xff0c;EventLoopThreadPool\u6a21<\/p>\n<p>\u5757\u3002<\/p>\n<p>class TcpServer {<br \/>\n    private:<br \/>\n        uint64_t _next_id;      \/\/\u8fd9\u662f\u4e00\u4e2a\u81ea\u52a8\u589e\u957f\u7684\u8fde\u63a5ID&#xff0c;<br \/>\n        int _port;<br \/>\n        int _timeout;           \/\/\u8fd9\u662f\u975e\u6d3b\u8dc3\u8fde\u63a5\u7684\u7edf\u8ba1\u65f6\u95f4&#8212;\u591a\u957f\u65f6\u95f4\u65e0\u901a\u4fe1\u5c31\u662f\u975e\u6d3b\u8dc3\u8fde\u63a5<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        EventLoop _baseloop;    \/\/\u8fd9\u662f\u4e3b\u7ebf\u7a0b\u7684EventLoop\u5bf9\u8c61&#xff0c;\u8d1f\u8d23\u76d1\u542c\u4e8b\u4ef6\u7684\u5904\u7406<br \/>\n        Acceptor _acceptor;    \/\/\u8fd9\u662f\u76d1\u542c\u5957\u63a5\u5b57\u7684\u7ba1\u7406\u5bf9\u8c61<br \/>\n        LoopThreadPool _pool;   \/\/\u8fd9\u662f\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;<br \/>\n    private:<br \/>\n        void RunAfterInLoop(const Functor &amp;task, int delay) {<br \/>\n            _next_id&#043;&#043;;<br \/>\n            _baseloop.TimerAdd(_next_id, delay, task);<br \/>\n        }<br \/>\n        \/\/\u4e3a\u65b0\u8fde\u63a5\u6784\u9020\u4e00\u4e2aConnection\u8fdb\u884c\u7ba1\u7406<br \/>\n        void NewConnection(int fd) {<br \/>\n            _next_id&#043;&#043;;<br \/>\n            PtrConnection conn(new Connection(_pool.NextLoop(), _next_id, fd));<br \/>\n            conn-&gt;SetMessageCallback(_message_callback);<br \/>\n            conn-&gt;SetClosedCallback(_closed_callback);<br \/>\n            conn-&gt;SetConnectedCallback(_connected_callback);<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) 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            int id &#061; conn-&gt;Id();<br \/>\n            auto it &#061; _conns.find(id);<br \/>\n            if (it !&#061; _conns.end()) {<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            _baseloop.RunInLoop(std::bind(&amp;TcpServer::RemoveConnectionInLoop, this, conn));<br \/>\n        }<br \/>\n    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            _acceptor.SetAcceptCallback(std::bind(&amp;TcpServer::NewConnection, this, std::placeholders::_1));<br \/>\n            _acceptor.Listen();\/\/\u5c06\u76d1\u542c\u5957\u63a5\u5b57\u6302\u5230baseloop\u4e0a<br \/>\n        }<br \/>\n        void SetThreadCount(int count) { return _pool.SetThreadCount(count); }<br \/>\n        void SetConnectedCallback(const ConnectedCallback&amp;cb) { _connected_callback &#061; cb; }<br \/>\n        void SetMessageCallback(const MessageCallback&amp;cb) { _message_callback &#061; cb; }<br \/>\n        void SetClosedCallback(const ClosedCallback&amp;cb) { _closed_callback &#061; cb; }<br \/>\n        void SetAnyEventCallback(const AnyEventCallback&amp;cb) { _event_callback &#061; cb; }<br \/>\n        void EnableInactiveRelease(int timeout) { _timeout &#061; timeout; _enable_inactive_release &#061; true; }<br \/>\n        \/\/\u7528\u4e8e\u6dfb\u52a0\u4e00\u4e2a\u5b9a\u65f6\u4efb\u52a1<br \/>\n        void RunAfter(const Functor &amp;task, int delay) {<br \/>\n            _baseloop.RunInLoop(std::bind(&amp;TcpServer::RunAfterInLoop, this, task, delay));<br \/>\n        }<br \/>\n        void Start() { _pool.Create();  _baseloop.Start(); }<br \/>\n};<\/p>\n<p>void Channel::Remove() { return _loop-&gt;RemoveEvent(this); }<br \/>\nvoid Channel::Update() { return _loop-&gt;UpdateEvent(this); }<br \/>\nvoid TimerWheel::TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &amp;cb) {<br \/>\n    _loop-&gt;RunInLoop(std::bind(&amp;TimerWheel::TimerAddInLoop, this, id, delay, cb));<br \/>\n}<br \/>\n\/\/\u5237\u65b0\/\u5ef6\u8fdf\u5b9a\u65f6\u4efb\u52a1<br \/>\nvoid TimerWheel::TimerRefresh(uint64_t id) {<br \/>\n    _loop-&gt;RunInLoop(std::bind(&amp;TimerWheel::TimerRefreshInLoop, this, id));<br \/>\n}<br \/>\nvoid TimerWheel::TimerCancel(uint64_t id) {<br \/>\n    _loop-&gt;RunInLoop(std::bind(&amp;TimerWheel::TimerCancelInLoop, this, id));<br \/>\n}<\/p>\n<p>class NetWork {<br \/>\n    public:<br \/>\n        NetWork() {<br \/>\n            DBG_LOG(&#034;SIGPIPE INIT&#034;);<br \/>\n            signal(SIGPIPE, SIG_IGN);<br \/>\n        }<br \/>\n}; <\/p>\n<h4 id=\"HTTP%E5%8D%8F%E8%AE%AE%E7%BB%84%E4%BB%B6%E6%A8%A1%E5%9D%97%EF%BC%9A\">HTTP\u534f\u8bae\u7ec4\u4ef6\u6a21\u5757&#xff1a;<\/h4>\n<h5 id=\"Util%E6%A8%A1%E5%9D%97%EF%BC%9A\">Util\u6a21\u5757&#xff1a;<\/h5>\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;}<br \/>\n};<\/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;}<br \/>\n};<\/p>\n<p>class Util {<br \/>\n    public:<br \/>\n        \/\/\u5b57\u7b26\u4e32\u5206\u5272\u51fd\u6570,\u5c06src\u5b57\u7b26\u4e32\u6309\u7167sep\u5b57\u7b26\u8fdb\u884c\u5206\u5272&#xff0c;\u5f97\u5230\u7684\u5404\u4e2a\u5b57\u4e32\u653e\u5230arry\u4e2d&#xff0c;\u6700\u7ec8\u8fd4\u56de\u5b57\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            size_t offset &#061; 0;<br \/>\n            \/\/ \u670910\u4e2a\u5b57\u7b26&#xff0c;offset\u662f\u67e5\u627e\u7684\u8d77\u59cb\u4f4d\u7f6e&#xff0c;\u8303\u56f4\u5e94\u8be5\u662f0~9&#xff0c;offset&#061;&#061;10\u5c31\u4ee3\u8868\u5df2\u7ecf\u8d8a\u754c\u4e86<br \/>\n            while(offset &lt; src.size()) {<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\/\u5b57\u4e32&#xff0c;\u8fd4\u56de\u67e5\u627e\u5230\u7684\u4f4d\u7f6e<br \/>\n                if (pos &#061;&#061; std::string::npos) {\/\/\u6ca1\u6709\u627e\u5230\u7279\u5b9a\u7684\u5b57\u7b26<br \/>\n                    \/\/\u5c06\u5269\u4f59\u7684\u90e8\u5206\u5f53\u4f5c\u4e00\u4e2a\u5b57\u4e32&#xff0c;\u653e\u5165arry\u4e2d<br \/>\n                    if(pos &#061;&#061; src.size()) 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                    offset &#061; pos &#043; sep.size();<br \/>\n                    continue;\/\/\u5f53\u524d\u5b57\u4e32\u662f\u4e00\u4e2a\u7a7a\u7684&#xff0c;\u6ca1\u6709\u5185\u5bb9<br \/>\n                }<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\u7684\u6240\u6709\u5185\u5bb9&#xff0c;\u5c06\u8bfb\u53d6\u7684\u5185\u5bb9\u653e\u5230\u4e00\u4e2aBuffer\u4e2d<br \/>\n        static bool ReadFile(const std::string &amp;filename, std::string *buf) {<br \/>\n            std::ifstream ifs(filename, std::ios::binary);<br \/>\n            if (ifs.is_open() &#061;&#061; false) {<br \/>\n                printf(&#034;OPEN %s FILE FAILED!!&#034;, filename.c_str());<br \/>\n                return false;<br \/>\n            }<br \/>\n            size_t fsize &#061; 0;<br \/>\n            ifs.seekg(0, ifs.end);\/\/\u8df3\u8f6c\u8bfb\u5199\u4f4d\u7f6e\u5230\u672b\u5c3e<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                printf(&#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            std::ofstream ofs(filename, std::ios::binary | std::ios::trunc);<br \/>\n            if (ofs.is_open() &#061;&#061; false) {<br \/>\n                printf(&#034;OPEN %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                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;\u524d\u7f00%   C&#043;&#043; -&gt; C%2B%2B<br \/>\n        \/\/  \u4e0d\u7f16\u7801\u7684\u7279\u6b8a\u5b57\u7b26&#xff1a; RFC3986\u6587\u6863\u89c4\u5b9a . &#8211; _ ~ \u5b57\u6bcd&#xff0c;\u6570\u5b57\u5c5e\u4e8e\u7edd\u5bf9\u4e0d\u7f16\u7801\u5b57\u7b26<br \/>\n        \/\/RFC3986\u6587\u6863\u89c4\u5b9a&#xff0c;\u7f16\u7801\u683c\u5f0f %HH<br \/>\n        \/\/W3C\u6807\u51c6\u4e2d\u89c4\u5b9a&#xff0c;\u67e5\u8be2\u5b57\u7b26\u4e32\u4e2d\u7684\u7a7a\u683c&#xff0c;\u9700\u8981\u7f16\u7801\u4e3a&#043;&#xff0c; \u89e3\u7801\u5219\u662f&#043;\u8f6c\u7a7a\u683c<br \/>\n        static std::string UrlEncode(const std::string url, bool convert_space_to_plus) {<br \/>\n            std::string res;<br \/>\n            for (auto &amp;c : url) {<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                    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                    res &#043;&#061; &#039;&#043;&#039;;<br \/>\n                    continue;<br \/>\n                }<br \/>\n                \/\/\u5269\u4e0b\u7684\u5b57\u7b26\u90fd\u662f\u9700\u8981\u7f16\u7801\u6210\u4e3a %HH \u683c\u5f0f<br \/>\n                char tmp[4] &#061; {0};<br \/>\n                \/\/snprintf \u4e0e printf\u6bd4\u8f83\u7c7b\u4f3c&#xff0c;\u90fd\u662f\u683c\u5f0f\u5316\u5b57\u7b26\u4e32&#xff0c;\u53ea\u4e0d\u8fc7\u4e00\u4e2a\u662f\u6253\u5370&#xff0c;\u4e00\u4e2a\u662f\u653e\u5230\u4e00\u5757\u7a7a\u95f4\u4e2d<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            if (c &gt;&#061; &#039;0&#039; &amp;&amp; c &lt;&#061; &#039;9&#039;) {<br \/>\n                return c &#8211; &#039;0&#039;;<br \/>\n            }else if (c &gt;&#061; &#039;a&#039; &amp;&amp; c &lt;&#061; &#039;z&#039;) {<br \/>\n                return c &#8211; &#039;a&#039; &#043; 10;<br \/>\n            }else if (c &gt;&#061; &#039;A&#039; &amp;&amp; c &lt;&#061; &#039;Z&#039;) {<br \/>\n                return c &#8211; &#039;A&#039; &#043; 10;<br \/>\n            }<br \/>\n            return -1;<br \/>\n        }<br \/>\n        static std::string UrlDecode(const std::string url, bool convert_plus_to_space) {<br \/>\n            \/\/\u9047\u5230\u4e86%&#xff0c;\u5219\u5c06\u7d27\u968f\u5176\u540e\u76842\u4e2a\u5b57\u7b26&#xff0c;\u8f6c\u6362\u4e3a\u6570\u5b57&#xff0c;\u7b2c\u4e00\u4e2a\u6570\u5b57\u5de6\u79fb4\u4f4d&#xff0c;\u7136\u540e\u52a0\u4e0a\u7b2c\u4e8c\u4e2a\u6570\u5b57  &#043; -&gt; 2b  %2b-&gt;2 &lt;&lt; 4 &#043; 11<br \/>\n            std::string res;<br \/>\n            for (int i &#061; 0; i &lt; url.size(); i&#043;&#043;) {<br \/>\n                if (url[i] &#061;&#061; &#039;&#043;&#039; &amp;&amp; convert_plus_to_space &#061;&#061; true) {<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                    char v1 &#061; HEXTOI(url[i &#043; 1]);<br \/>\n                    char v2 &#061; HEXTOI(url[i &#043; 2]);<br \/>\n                    char v &#061; v1 * 16 &#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        \/\/\u54cd\u5e94\u72b6\u6001\u7801\u7684\u63cf\u8ff0\u4fe1\u606f\u83b7\u53d6<br \/>\n        static std::string StatuDesc(int statu) {<\/p>\n<p>            auto it &#061; _statu_msg.find(statu);<br \/>\n            if (it !&#061; _statu_msg.end()) {<br \/>\n                return it-&gt;second;<br \/>\n            }<br \/>\n            return &#034;Unknow&#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) {<\/p>\n<p>            \/\/ a.b.txt  \u5148\u83b7\u53d6\u6587\u4ef6\u6269\u5c55\u540d<br \/>\n            size_t pos &#061; filename.find_last_of(&#039;.&#039;);<br \/>\n            if (pos &#061;&#061; std::string::npos) {<br \/>\n                return &#034;application\/octet-stream&#034;;<br \/>\n            }<br \/>\n            \/\/\u6839\u636e\u6269\u5c55\u540d&#xff0c;\u83b7\u53d6mime<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                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            struct stat st;<br \/>\n            int ret &#061; stat(filename.c_str(), &amp;st);<br \/>\n            if (ret &lt; 0) {<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            struct stat st;<br \/>\n            int ret &#061; stat(filename.c_str(), &amp;st);<br \/>\n            if (ret &lt; 0) {<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\u8fb9\u7684\/\u53eb\u505a\u76f8\u5bf9\u6839\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\u7684\u8d44\u6e90\u90fd\u4e0d\u4e88\u7406\u4f1a<br \/>\n        \/\/ \/..\/login, \u8fd9\u4e2a\u8def\u5f84\u4e2d\u7684..\u4f1a\u8ba9\u8def\u5f84\u7684\u67e5\u627e\u8dd1\u5230\u76f8\u5bf9\u6839\u76ee\u5f55\u4e4b\u5916&#xff0c;\u8fd9\u662f\u4e0d\u5408\u7406\u7684&#xff0c;\u4e0d\u5b89\u5168\u7684<br \/>\n        static bool ValidPath(const std::string &amp;path) {<br \/>\n            \/\/\u601d\u60f3&#xff1a;\u6309\u7167\/\u8fdb\u884c\u8def\u5f84\u5206\u5272&#xff0c;\u6839\u636e\u6709\u591a\u5c11\u5b50\u76ee\u5f55&#xff0c;\u8ba1\u7b97\u76ee\u5f55\u6df1\u5ea6&#xff0c;\u6709\u591a\u5c11\u5c42&#xff0c;\u6df1\u5ea6\u4e0d\u80fd\u5c0f\u4e8e0<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                if (dir &#061;&#061; &#034;..&#034;) {<br \/>\n                    level&#8211;; \/\/\u4efb\u610f\u4e00\u5c42\u8d70\u51fa\u76f8\u5bf9\u6839\u76ee\u5f55&#xff0c;\u5c31\u8ba4\u4e3a\u6709\u95ee\u9898<br \/>\n                    if (level &lt; 0) return false;<br \/>\n                    continue;<br \/>\n                }<br \/>\n                level&#043;&#043;;<br \/>\n            }<br \/>\n            return true;<br \/>\n        }<br \/>\n}; <\/p>\n<h5 id=\"HttpRequest%E6%A8%A1%E5%9D%97%EF%BC%9A\">HttpRequest\u6a21\u5757&#xff1a;<\/h5>\n<p>class HttpRequest {<br \/>\n    public:<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<br \/>\n    public:<br \/>\n        HttpRequest():_version(&#034;HTTP\/1.1&#034;) {}<br \/>\n        void ReSet() {<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(const std::string &amp;key, const std::string &amp;val) {<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            auto it &#061; _headers.find(key);<br \/>\n            if (it &#061;&#061; _headers.end()) {<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            auto it &#061; _headers.find(key);<br \/>\n            if (it &#061;&#061; _headers.end()) {<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            _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            auto it &#061; _params.find(key);<br \/>\n            if (it &#061;&#061; _params.end()) {<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            auto it &#061; _params.find(key);<br \/>\n            if (it &#061;&#061; _params.end()) {<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            \/\/ Content-Length: 1234\\\\r\\\\n<br \/>\n            bool ret &#061; HasHeader(&#034;Content-Length&#034;);<br \/>\n            if (ret &#061;&#061; false) {<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\u662f\u77ed\u94fe\u63a5<br \/>\n        bool Close() const {<br \/>\n            \/\/ \u6ca1\u6709Connection\u5b57\u6bb5&#xff0c;\u6216\u8005\u6709Connection\u4f46\u662f\u503c\u662fclose&#xff0c;\u5219\u90fd\u662f\u77ed\u94fe\u63a5&#xff0c;\u5426\u5219\u5c31\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                return false;<br \/>\n            }<br \/>\n            return true;<br \/>\n        }<br \/>\n}; <\/p>\n<h5 id=\"HttpContext%E6%A8%A1%E5%9D%97%EF%BC%9A\">HttpContext\u6a21\u5757&#xff1a;<\/h5>\n<p>class HttpContext {<br \/>\n    private:<br \/>\n        int _resp_statu; \/\/\u54cd\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 \/>\n    private:<br \/>\n        bool ParseHttpLine(const std::string &amp;line) {<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                _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n                _resp_statu &#061; 400;\/\/BAD REQUEST<br \/>\n                return false;<br \/>\n            }<br \/>\n            \/\/0 : GET \/bitejiuyeke\/login?user&#061;xiaoming&amp;pass&#061;123123 HTTP\/1.1<br \/>\n            \/\/1 : GET<br \/>\n            \/\/2 : \/bitejiuyeke\/login<br \/>\n            \/\/3 : user&#061;xiaoming&amp;pass&#061;123123<br \/>\n            \/\/4 : HTTP\/1.1<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\u83b7\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;val&amp;key&#061;val&#8230;.., \u5148\u4ee5 &amp; \u7b26\u53f7\u8fdb\u884c\u5206\u5272&#xff0c;\u5f97\u5230\u5404\u4e2a\u5b57\u4e32<br \/>\n            Util::Split(query_string, &#034;&amp;&#034;, &amp;query_string_arry);<br \/>\n            \/\/\u9488\u5bf9\u5404\u4e2a\u5b57\u4e32&#xff0c;\u4ee5 &#061; \u7b26\u53f7\u8fdb\u884c\u5206\u5272&#xff0c;\u5f97\u5230key \u548cval&#xff0c; \u5f97\u5230\u4e4b\u540e\u4e5f\u9700\u8981\u8fdb\u884cURL\u89e3\u7801<br \/>\n            for (auto &amp;str : query_string_arry) {<br \/>\n                size_t pos &#061; str.find(&#034;&#061;&#034;);<br \/>\n                if (pos &#061;&#061; std::string::npos) {<br \/>\n                    _recv_statu &#061; RECV_HTTP_ERROR;<br \/>\n                    _resp_statu &#061; 400;\/\/BAD REQUEST<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        bool RecvHttpLine(Buffer *buf) {<br \/>\n            if (_recv_statu !&#061; RECV_HTTP_LINE) return false;<br \/>\n            \/\/1. \u83b7\u53d6\u4e00\u884c\u6570\u636e&#xff0c;\u5e26\u6709\u672b\u5c3e\u7684\u6362\u884c<br \/>\n            std::string line &#061; buf-&gt;GetLineAndPop();<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                \/\/\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u5219\u9700\u8981\u5224\u65ad\u7f13\u51b2\u533a\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                    _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                _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                return false;<br \/>\n            }<br \/>\n            \/\/\u9996\u884c\u5904\u7406\u5b8c\u6bd5&#xff0c;\u8fdb\u5165\u5934\u90e8\u83b7\u53d6\u9636\u6bb5<br \/>\n            _recv_statu &#061; RECV_HTTP_HEAD;<br \/>\n            return true;<br \/>\n        }<br \/>\n        bool RecvHttpHead(Buffer *buf) {<br \/>\n            if (_recv_statu !&#061; RECV_HTTP_HEAD) return false;<br \/>\n            \/\/\u4e00\u884c\u4e00\u884c\u53d6\u51fa\u6570\u636e&#xff0c;\u76f4\u5230\u9047\u5230\u7a7a\u884c\u4e3a\u6b62&#xff0c; \u5934\u90e8\u7684\u683c\u5f0f key: val\\\\r\\\\nkey: val\\\\r\\\\n&#8230;.<br \/>\n            while(1){<br \/>\n                std::string line &#061; buf-&gt;GetLineAndPop();<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                    \/\/\u7f13\u51b2\u533a\u4e2d\u7684\u6570\u636e\u4e0d\u8db3\u4e00\u884c&#xff0c;\u5219\u9700\u8981\u5224\u65ad\u7f13\u51b2\u533a\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                        _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                    _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                    break;<br \/>\n                }<br \/>\n                bool ret &#061; ParseHttpHead(line);<br \/>\n                if (ret &#061;&#061; false) {<br \/>\n                    return false;<br \/>\n                }<br \/>\n            }<br \/>\n            \/\/\u5934\u90e8\u5904\u7406\u5b8c\u6bd5&#xff0c;\u8fdb\u5165\u6b63\u6587\u83b7\u53d6\u9636\u6bb5<br \/>\n            _recv_statu &#061; RECV_HTTP_BODY;<br \/>\n            return true;<br \/>\n        }<br \/>\n        bool ParseHttpHead(std::string &amp;line) {<br \/>\n            \/\/key: val\\\\r\\\\nkey: val\\\\r\\\\n&#8230;.<br \/>\n            if (line.back() &#061;&#061; &#039;\\\\n&#039;) line.pop_back();\/\/\u672b\u5c3e\u662f\u6362\u884c\u5219\u53bb\u6389\u6362\u884c\u5b57\u7b26<br \/>\n            if (line.back() &#061;&#061; &#039;\\\\r&#039;) line.pop_back();\/\/\u672b\u5c3e\u662f\u56de\u8f66\u5219\u53bb\u6389\u56de\u8f66\u5b57\u7b26<br \/>\n            size_t pos &#061; line.find(&#034;: &#034;);<br \/>\n            if (pos &#061;&#061; std::string::npos) {<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            if (_recv_statu !&#061; RECV_HTTP_BODY) 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                \/\/\u6ca1\u6709\u6b63\u6587&#xff0c;\u5219\u8bf7\u6c42\u63a5\u6536\u89e3\u6790\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,\u5176\u5b9e\u5c31\u662f\u5f80  _request._body \u4e2d\u653e\u4e86\u591a\u5c11\u6570\u636e\u4e86<br \/>\n            size_t real_len &#061; content_length &#8211; _request._body.size();\/\/\u5b9e\u9645\u8fd8\u9700\u8981\u63a5\u6536\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&#xff0c;\u662f\u5426\u662f\u5168\u90e8\u7684\u6b63\u6587<br \/>\n            \/\/  3.1 \u7f13\u51b2\u533a\u4e2d\u6570\u636e&#xff0c;\u5305\u542b\u4e86\u5f53\u524d\u8bf7\u6c42\u7684\u6240\u6709\u6b63\u6587&#xff0c;\u5219\u53d6\u51fa\u6240\u9700\u7684\u6570\u636e<br \/>\n            if (buf-&gt;ReadAbleSize() &gt;&#061; real_len) {<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            }<br \/>\n            \/\/  3.2 \u7f13\u51b2\u533a\u4e2d\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        }<br \/>\n    public:<br \/>\n        HttpContext():_resp_statu(200), _recv_statu(RECV_HTTP_LINE) {}<br \/>\n        void ReSet() {<br \/>\n            _resp_statu &#061; 200;<br \/>\n            _recv_statu &#061; RECV_HTTP_LINE;<br \/>\n            _request.ReSet();<br \/>\n        }<br \/>\n        int RespStatu() { return _resp_statu; }<br \/>\n        HttpRecvStatu RecvStatu() { return _recv_statu; }<br \/>\n        HttpRequest &amp;Request() { return _request; }<br \/>\n        \/\/\u63a5\u6536\u5e76\u89e3\u6790HTTP\u8bf7\u6c42<br \/>\n        void RecvHttpRequest(Buffer *buf) {<br \/>\n            \/\/\u4e0d\u540c\u7684\u72b6\u6001&#xff0c;\u505a\u4e0d\u540c\u7684\u4e8b\u60c5&#xff0c;\u4f46\u662f\u8fd9\u91cc\u4e0d\u8981break&#xff0c; \u56e0\u4e3a\u5904\u7406\u5b8c\u8bf7\u6c42\u884c\u540e&#xff0c;\u5e94\u8be5\u7acb\u5373\u5904\u7406\u5934\u90e8&#xff0c;\u800c\u4e0d\u662f\u9000\u51fa\u7b49\u65b0\u6570\u636e<br \/>\n            switch(_recv_statu) {<br \/>\n                case RECV_HTTP_LINE: RecvHttpLine(buf);<br \/>\n                case RECV_HTTP_HEAD: RecvHttpHead(buf);<br \/>\n                case RECV_HTTP_BODY: RecvHttpBody(buf);<br \/>\n            }<br \/>\n            return;<br \/>\n        }<br \/>\n}; <\/p>\n<h5 id=\"HttpServer%E6%A8%A1%E5%9D%97%EF%BC%9A\">HttpServer\u6a21\u5757&#xff1a;<\/h5>\n<p>class HttpServer {<br \/>\n    private:<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;<br \/>\n    private:<br \/>\n        void ErrorHandler(const HttpRequest &amp;req, HttpResponse *rsp) {<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\u4f5c\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 WriteReponse(const PtrConnection &amp;conn, const HttpRequest &amp;req, HttpResponse &amp;rsp) {<br \/>\n            \/\/1. \u5148\u5b8c\u5584\u5934\u90e8\u5b57\u6bb5<br \/>\n            if (req.Close() &#061;&#061; true) {<br \/>\n                rsp.SetHeader(&#034;Connection&#034;, &#034;close&#034;);<br \/>\n            }else {<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                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                rsp.SetHeader(&#034;Content-Type&#034;, &#034;application\/octet-stream&#034;);<br \/>\n            }<br \/>\n            if (rsp._redirect_flag &#061;&#061; true) {<br \/>\n                rsp.SetHeader(&#034;Location&#034;, rsp._redirect_url);<br \/>\n            }<br \/>\n            \/\/2. \u5c06rsp\u4e2d\u7684\u8981\u7d20&#xff0c;\u6309\u7167http\u534f\u8bae\u683c\u5f0f\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                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        bool IsFileHandler(const HttpRequest &amp;req) {<br \/>\n            \/\/ 1. \u5fc5\u987b\u8bbe\u7f6e\u4e86\u9759\u6001\u8d44\u6e90\u6839\u76ee\u5f55<br \/>\n            if (_basedir.empty()) {<br \/>\n                return false;<br \/>\n            }<br \/>\n            \/\/ 2. \u8bf7\u6c42\u65b9\u6cd5&#xff0c;\u5fc5\u987b\u662fGET \/ HEAD\u8bf7\u6c42\u65b9\u6cd5<br \/>\n            if (req._method !&#061; &#034;GET&#034; &amp;&amp; req._method !&#061; &#034;HEAD&#034;) {<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                return false;<br \/>\n            }<br \/>\n            \/\/ 4. \u8bf7\u6c42\u7684\u8d44\u6e90\u5fc5\u987b\u5b58\u5728,\u4e14\u662f\u4e00\u4e2a\u666e\u901a\u6587\u4ef6<br \/>\n            \/\/    \u6709\u4e00\u79cd\u8bf7\u6c42\u6bd4\u8f83\u7279\u6b8a &#8212; \u76ee\u5f55&#xff1a;\/, \/image\/&#xff0c; \u8fd9\u79cd\u60c5\u51b5\u7ed9\u540e\u8fb9\u9ed8\u8ba4\u8ffd\u52a0\u4e00\u4e2a index.html<br \/>\n            \/\/ index.html    \/image\/a.png<br \/>\n            \/\/ \u4e0d\u8981\u5fd8\u4e86\u524d\u7f00\u7684\u76f8\u5bf9\u6839\u76ee\u5f55,\u4e5f\u5c31\u662f\u5c06\u8bf7\u6c42\u8def\u5f84\u8f6c\u6362\u4e3a\u5b9e\u9645\u5b58\u5728\u7684\u8def\u5f84  \/image\/a.png  -&gt;   .\/wwwroot\/image\/a.png<br \/>\n            std::string req_path &#061; _basedir &#043; req._path;\/\/\u4e3a\u4e86\u907f\u514d\u76f4\u63a5\u4fee\u6539\u8bf7\u6c42\u7684\u8d44\u6e90\u8def\u5f84&#xff0c;\u56e0\u6b64\u5b9a\u4e49\u4e00\u4e2a\u4e34\u65f6\u5bf9\u8c61<br \/>\n            if (req._path.back() &#061;&#061; &#039;\/&#039;)  {<br \/>\n                req_path &#043;&#061; &#034;index.html&#034;;<br \/>\n            }<br \/>\n            if (Util::IsRegular(req_path) &#061;&#061; false) {<br \/>\n                return false;<br \/>\n            }<br \/>\n            return true;<br \/>\n        }<br \/>\n        \/\/\u9759\u6001\u8d44\u6e90\u7684\u8bf7\u6c42\u5904\u7406 &#8212; \u5c06\u9759\u6001\u8d44\u6e90\u6587\u4ef6\u7684\u6570\u636e\u8bfb\u53d6\u51fa\u6765&#xff0c;\u653e\u5230rsp\u7684_body\u4e2d, \u5e76\u8bbe\u7f6emime<br \/>\n        void FileHandler(const HttpRequest &amp;req, HttpResponse *rsp) {<br \/>\n            std::string req_path &#061; _basedir &#043; req._path;<br \/>\n            if (req._path.back() &#061;&#061; &#039;\/&#039;)  {<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                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            \/\/\u5728\u5bf9\u5e94\u8bf7\u6c42\u65b9\u6cd5\u7684\u8def\u7531\u8868\u4e2d&#xff0c;\u67e5\u627e\u662f\u5426\u542b\u6709\u5bf9\u5e94\u8d44\u6e90\u8bf7\u6c42\u7684\u5904\u7406\u51fd\u6570&#xff0c;\u6709\u5219\u8c03\u7528&#xff0c;\u6ca1\u6709\u5219\u53d1\u6325404<br \/>\n            \/\/\u601d\u60f3&#xff1a;\u8def\u7531\u8868\u5b58\u50a8\u7684\u65f6\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\u4f7f\u7528\u5bf9\u5e94\u51fd\u6570\u8fdb\u884c\u5904\u7406<br \/>\n            \/\/  \/numbers\/(\\\\d&#043;)       \/numbers\/12345<br \/>\n            for (auto &amp;handler : handlers) {<br \/>\n                const std::regex &amp;re &#061; handler.first;<br \/>\n                const Handler &amp;functor &#061; handler.second;<br \/>\n                bool ret &#061; std::regex_match(req._path, req._matches, re);<br \/>\n                if (ret &#061;&#061; false) {<br \/>\n                    continue;<br \/>\n                }<br \/>\n                return functor(req, rsp);\/\/\u4f20\u5165\u8bf7\u6c42\u4fe1\u606f&#xff0c;\u548c\u7a7a\u7684rsp&#xff0c;\u6267\u884c\u5904\u7406\u51fd\u6570<br \/>\n            }<br \/>\n            rsp-&gt;_statu &#061; 404;<br \/>\n        }<br \/>\n        void Route(HttpRequest &amp;req, HttpResponse *rsp) {<br \/>\n            \/\/1. \u5bf9\u8bf7\u6c42\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\u7684\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\u6ca1\u6709\u8bbe\u7f6e\u5bf9\u5e94\u7684\u529f\u80fd\u6027\u8bf7\u6c42\u5904\u7406\u51fd\u6570&#xff0c;\u5c31\u8fd4\u56de405<br \/>\n            if (IsFileHandler(req) &#061;&#061; true) {<br \/>\n                \/\/\u662f\u4e00\u4e2a\u9759\u6001\u8d44\u6e90\u8bf7\u6c42, \u5219\u8fdb\u884c\u9759\u6001\u8d44\u6e90\u8bf7\u6c42\u7684\u5904\u7406<br \/>\n                return FileHandler(req, rsp);<br \/>\n            }<br \/>\n            if (req._method &#061;&#061; &#034;GET&#034; || req._method &#061;&#061; &#034;HEAD&#034;) {<br \/>\n                return Dispatcher(req, rsp, _get_route);<br \/>\n            }else if (req._method &#061;&#061; &#034;POST&#034;) {<br \/>\n                return Dispatcher(req, rsp, _post_route);<br \/>\n            }else if (req._method &#061;&#061; &#034;PUT&#034;) {<br \/>\n                return Dispatcher(req, rsp, _put_route);<br \/>\n            }else if (req._method &#061;&#061; &#034;DELETE&#034;) {<br \/>\n                return Dispatcher(req, rsp, _delete_route);<br \/>\n            }<br \/>\n            rsp-&gt;_statu &#061; 405;\/\/ Method Not Allowed<br \/>\n            return ;<br \/>\n        }<br \/>\n        \/\/\u8bbe\u7f6e\u4e0a\u4e0b\u6587<br \/>\n        void OnConnected(const PtrConnection &amp;conn) {<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            while(buffer-&gt;ReadAbleSize() &gt; 0){<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                    \/\/\u8fdb\u884c\u9519\u8bef\u54cd\u5e94&#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                    WriteReponse(conn, req, rsp);\/\/\u7ec4\u7ec7\u54cd\u5e94\u53d1\u9001\u7ed9\u5ba2\u6237\u7aef<br \/>\n                    context-&gt;ReSet();<br \/>\n                    buffer-&gt;MoveReadOffset(buffer-&gt;ReadAbleSize());\/\/\u51fa\u9519\u4e86\u5c31\u628a\u7f13\u51b2\u533a\u6570\u636e\u6e05\u7a7a<br \/>\n                    conn-&gt;Shutdown();\/\/\u5173\u95ed\u8fde\u63a5<br \/>\n                    return;<br \/>\n                }<br \/>\n                if (context-&gt;RecvStatu() !&#061; RECV_HTTP_OVER) {<br \/>\n                    \/\/\u5f53\u524d\u8bf7\u6c42\u8fd8\u6ca1\u6709\u63a5\u6536\u5b8c\u6574,\u5219\u9000\u51fa&#xff0c;\u7b49\u65b0\u6570\u636e\u5230\u6765\u518d\u91cd\u65b0\u7ee7\u7eed\u5904\u7406<br \/>\n                    return;<br \/>\n                }<br \/>\n                \/\/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                WriteReponse(conn, req, rsp);<br \/>\n                \/\/5. \u91cd\u7f6e\u4e0a\u4e0b\u6587<br \/>\n                context-&gt;ReSet();<br \/>\n                \/\/6. \u6839\u636e\u957f\u77ed\u8fde\u63a5\u5224\u65ad\u662f\u5426\u5173\u95ed\u8fde\u63a5\u6216\u8005\u7ee7\u7eed\u5904\u7406<br \/>\n                if (rsp.Close() &#061;&#061; true) conn-&gt;Shutdown();\/\/\u77ed\u94fe\u63a5\u5219\u76f4\u63a5\u5173\u95ed<br \/>\n            }<br \/>\n            return;<br \/>\n        }<br \/>\n    public:<br \/>\n        HttpServer(int port, int timeout &#061; DEFALT_TIMEOUT):_server(port) {<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            assert(Util::IsDirectory(path) &#061;&#061; true);<br \/>\n            _basedir &#061; path;<br \/>\n        }<br \/>\n        \/*\u8bbe\u7f6e\/\u6dfb\u52a0&#xff0c;\u8bf7\u6c42&#xff08;\u8bf7\u6c42\u7684\u6b63\u5219\u8868\u8fbe&#xff09;\u4e0e\u5904\u7406\u51fd\u6570\u7684\u6620\u5c04\u5173\u7cfb*\/<br \/>\n        void Get(const std::string &amp;pattern, const Handler &amp;handler) {<br \/>\n            _get_route.push_back(std::make_pair(std::regex(pattern), handler));<br \/>\n        }<br \/>\n        void Post(const std::string &amp;pattern, const Handler &amp;handler) {<br \/>\n            _post_route.push_back(std::make_pair(std::regex(pattern), handler));<br \/>\n        }<br \/>\n        void Put(const std::string &amp;pattern, const Handler &amp;handler) {<br \/>\n            _put_route.push_back(std::make_pair(std::regex(pattern), handler));<br \/>\n        }<br \/>\n        void Delete(const std::string &amp;pattern, const Handler &amp;handler) {<br \/>\n            _delete_route.push_back(std::make_pair(std::regex(pattern), handler));<br \/>\n        }<br \/>\n        void SetThreadCount(int count) {<br \/>\n            _server.SetThreadCount(count);<br \/>\n        }<br \/>\n        void Listen() {<br \/>\n            _server.Start();<br \/>\n        }<br \/>\n}; <\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u6587\u7ae0\u6d4f\u89c8\u9605\u8bfb919\u6b21\uff0c\u70b9\u8d5e9\u6b21\uff0c\u6536\u85cf9\u6b21\u3002\u901a\u8fc7\u54b1\u4eec\u5b9e\u73b0\u7684\u2fbc\u5e76\u53d1\u670d\u52a1\u5668\u7ec4\u4ef6\uff0c\u53ef\u4ee5\u7b80\u6d01\u5feb\u901f\u7684\u5b8c\u6210\u2f00\u4e2a\u2fbc\u6027\u80fd\u7684\u670d\u52a1\u5668\u642d\u5efa\u3002\u5e76\u4e14\uff0c\u901a\u8fc7\u7ec4\u4ef6\u5185\u63d0\u4f9b\u7684\u4e0d\u540c\u5e94\u2f64\u5c42\u534f\u8bae\u2f40\u6301\uff0c\u4e5f\u53ef\u4ee5\u5feb\u901f\u5b8c\u6210\u2f00\u4e2a\u2fbc\u6027\u80fd\u5e94\u2f64\u670d\u52a1\u5668\u7684\u642d\u5efa\uff08\u5f53\u524d \uff0c\u4e3a\u4e86\u4fbf\u4e8e\u9879\u2f6c\u7684\u6f14\u2f70\uff0c\u9879\u2f6c\u4e2d\u63d0\u4f9bHTTP\u534f\u8bae\u7ec4\u4ef6\u7684\u2f40\u6301\uff09\u3002\u5728\u8fd9\u2fa5\uff0c\u8981\u660e\u786e\u7684\u662f\u54b1\u4eec\u8981\u5b9e\u73b0\u7684\u662f\u2f00\u4e2a\u2fbc\u5e76\u53d1\u670d\u52a1\u5668\u7ec4\u4ef6\uff0c\u56e0\u6b64\u5f53\u524d\u7684\u9879\u2f6c\u4e2d\u5e76\u4e0d\u5305\u542b\u5b9e\u9645\u7684\u4e1a\u52a1\u5185\u5bb9\u3002\u56fe\u7247\u6765\u6e90\uff1a\u672c\u9879\u76ee\u603b\u5171\u5206\u4e3a\u4e24\u5927\u6a21\u5757\u5206\u522b\u4e3aServer\u548cHTTP\u6a21\u5757\u3002_\u4effmuduo\u5e93one-thread-one-loop\u5f0f\u5e76\u53d1\u670d\u52a1\u5668<\/p>\n","protected":false},"author":2,"featured_media":14199,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[43,44],"topic":[],"class_list":["post-14200","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-server","tag-43","tag-44"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v20.3 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>\u4effmodou\u5e93one thread one loop\u5f0f\u5e76\u53d1\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\/14200.html\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"\u4effmodou\u5e93one thread one loop\u5f0f\u5e76\u53d1\u670d\u52a1\u5668 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\" \/>\n<meta property=\"og:description\" content=\"\u6587\u7ae0\u6d4f\u89c8\u9605\u8bfb919\u6b21\uff0c\u70b9\u8d5e9\u6b21\uff0c\u6536\u85cf9\u6b21\u3002\u901a\u8fc7\u54b1\u4eec\u5b9e\u73b0\u7684\u2fbc\u5e76\u53d1\u670d\u52a1\u5668\u7ec4\u4ef6\uff0c\u53ef\u4ee5\u7b80\u6d01\u5feb\u901f\u7684\u5b8c\u6210\u2f00\u4e2a\u2fbc\u6027\u80fd\u7684\u670d\u52a1\u5668\u642d\u5efa\u3002\u5e76\u4e14\uff0c\u901a\u8fc7\u7ec4\u4ef6\u5185\u63d0\u4f9b\u7684\u4e0d\u540c\u5e94\u2f64\u5c42\u534f\u8bae\u2f40\u6301\uff0c\u4e5f\u53ef\u4ee5\u5feb\u901f\u5b8c\u6210\u2f00\u4e2a\u2fbc\u6027\u80fd\u5e94\u2f64\u670d\u52a1\u5668\u7684\u642d\u5efa\uff08\u5f53\u524d \uff0c\u4e3a\u4e86\u4fbf\u4e8e\u9879\u2f6c\u7684\u6f14\u2f70\uff0c\u9879\u2f6c\u4e2d\u63d0\u4f9bHTTP\u534f\u8bae\u7ec4\u4ef6\u7684\u2f40\u6301\uff09\u3002\u5728\u8fd9\u2fa5\uff0c\u8981\u660e\u786e\u7684\u662f\u54b1\u4eec\u8981\u5b9e\u73b0\u7684\u662f\u2f00\u4e2a\u2fbc\u5e76\u53d1\u670d\u52a1\u5668\u7ec4\u4ef6\uff0c\u56e0\u6b64\u5f53\u524d\u7684\u9879\u2f6c\u4e2d\u5e76\u4e0d\u5305\u542b\u5b9e\u9645\u7684\u4e1a\u52a1\u5185\u5bb9\u3002\u56fe\u7247\u6765\u6e90\uff1a\u672c\u9879\u76ee\u603b\u5171\u5206\u4e3a\u4e24\u5927\u6a21\u5757\u5206\u522b\u4e3aServer\u548cHTTP\u6a21\u5757\u3002_\u4effmuduo\u5e93one-thread-one-loop\u5f0f\u5e76\u53d1\u670d\u52a1\u5668\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.wsisp.com\/helps\/14200.html\" \/>\n<meta property=\"og:site_name\" content=\"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\" \/>\n<meta property=\"article:published_time\" content=\"2025-04-18T12:59:15+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2025\/04\/20250418125914-68024ca28ccf6.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=\"33 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/14200.html\",\"url\":\"https:\/\/www.wsisp.com\/helps\/14200.html\",\"name\":\"\u4effmodou\u5e93one thread one loop\u5f0f\u5e76\u53d1\u670d\u52a1\u5668 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\",\"isPartOf\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/#website\"},\"datePublished\":\"2025-04-18T12:59:15+00:00\",\"dateModified\":\"2025-04-18T12:59:15+00:00\",\"author\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/14200.html#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.wsisp.com\/helps\/14200.html\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/14200.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u9996\u9875\",\"item\":\"https:\/\/www.wsisp.com\/helps\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"\u4effmodou\u5e93one thread one loop\u5f0f\u5e76\u53d1\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":"\u4effmodou\u5e93one thread one loop\u5f0f\u5e76\u53d1\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\/14200.html","og_locale":"zh_CN","og_type":"article","og_title":"\u4effmodou\u5e93one thread one loop\u5f0f\u5e76\u53d1\u670d\u52a1\u5668 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","og_description":"\u6587\u7ae0\u6d4f\u89c8\u9605\u8bfb919\u6b21\uff0c\u70b9\u8d5e9\u6b21\uff0c\u6536\u85cf9\u6b21\u3002\u901a\u8fc7\u54b1\u4eec\u5b9e\u73b0\u7684\u2fbc\u5e76\u53d1\u670d\u52a1\u5668\u7ec4\u4ef6\uff0c\u53ef\u4ee5\u7b80\u6d01\u5feb\u901f\u7684\u5b8c\u6210\u2f00\u4e2a\u2fbc\u6027\u80fd\u7684\u670d\u52a1\u5668\u642d\u5efa\u3002\u5e76\u4e14\uff0c\u901a\u8fc7\u7ec4\u4ef6\u5185\u63d0\u4f9b\u7684\u4e0d\u540c\u5e94\u2f64\u5c42\u534f\u8bae\u2f40\u6301\uff0c\u4e5f\u53ef\u4ee5\u5feb\u901f\u5b8c\u6210\u2f00\u4e2a\u2fbc\u6027\u80fd\u5e94\u2f64\u670d\u52a1\u5668\u7684\u642d\u5efa\uff08\u5f53\u524d \uff0c\u4e3a\u4e86\u4fbf\u4e8e\u9879\u2f6c\u7684\u6f14\u2f70\uff0c\u9879\u2f6c\u4e2d\u63d0\u4f9bHTTP\u534f\u8bae\u7ec4\u4ef6\u7684\u2f40\u6301\uff09\u3002\u5728\u8fd9\u2fa5\uff0c\u8981\u660e\u786e\u7684\u662f\u54b1\u4eec\u8981\u5b9e\u73b0\u7684\u662f\u2f00\u4e2a\u2fbc\u5e76\u53d1\u670d\u52a1\u5668\u7ec4\u4ef6\uff0c\u56e0\u6b64\u5f53\u524d\u7684\u9879\u2f6c\u4e2d\u5e76\u4e0d\u5305\u542b\u5b9e\u9645\u7684\u4e1a\u52a1\u5185\u5bb9\u3002\u56fe\u7247\u6765\u6e90\uff1a\u672c\u9879\u76ee\u603b\u5171\u5206\u4e3a\u4e24\u5927\u6a21\u5757\u5206\u522b\u4e3aServer\u548cHTTP\u6a21\u5757\u3002_\u4effmuduo\u5e93one-thread-one-loop\u5f0f\u5e76\u53d1\u670d\u52a1\u5668","og_url":"https:\/\/www.wsisp.com\/helps\/14200.html","og_site_name":"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","article_published_time":"2025-04-18T12:59:15+00:00","og_image":[{"url":"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2025\/04\/20250418125914-68024ca28ccf6.png"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"admin","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"33 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.wsisp.com\/helps\/14200.html","url":"https:\/\/www.wsisp.com\/helps\/14200.html","name":"\u4effmodou\u5e93one thread one loop\u5f0f\u5e76\u53d1\u670d\u52a1\u5668 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","isPartOf":{"@id":"https:\/\/www.wsisp.com\/helps\/#website"},"datePublished":"2025-04-18T12:59:15+00:00","dateModified":"2025-04-18T12:59:15+00:00","author":{"@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41"},"breadcrumb":{"@id":"https:\/\/www.wsisp.com\/helps\/14200.html#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.wsisp.com\/helps\/14200.html"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.wsisp.com\/helps\/14200.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/www.wsisp.com\/helps"},{"@type":"ListItem","position":2,"name":"\u4effmodou\u5e93one thread one loop\u5f0f\u5e76\u53d1\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\/14200","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=14200"}],"version-history":[{"count":0,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts\/14200\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/media\/14199"}],"wp:attachment":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/media?parent=14200"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/categories?post=14200"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/tags?post=14200"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/topic?post=14200"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}