From e9005f3e22f8ed00bae6b0c8da79270cd89ea3cc Mon Sep 17 00:00:00 2001 From: FluxMind-O <192421299+FluxMind-O@users.noreply.github.com> Date: Tue, 18 Aug 2026 04:58:35 +0800 Subject: [PATCH 1/4] =?UTF-8?q?fix(ringbuffer):=20=E6=9E=90=E6=9E=84?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=20delete[]=20=E9=87=8A=E6=94=BE=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E5=86=85=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit buffer_ 由 new char[capacity_] 分配,析构却用 delete,属未定义行为,可能导致内存损坏。改为 delete[]。 --- webserver/tcp/KRingBuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver/tcp/KRingBuffer.h b/webserver/tcp/KRingBuffer.h index 94ddc4a..4983a13 100644 --- a/webserver/tcp/KRingBuffer.h +++ b/webserver/tcp/KRingBuffer.h @@ -23,7 +23,7 @@ class Buffer : public kback::copyable { } ~Buffer() { - delete buffer_; + delete[] buffer_; buffer_ = nullptr; capacity_ = 0; } From 813c02a41be8a7734203532670f4b33e9b307590 Mon Sep 17 00:00:00 2001 From: FluxMind-O <192421299+FluxMind-O@users.noreply.github.com> Date: Tue, 18 Aug 2026 04:58:55 +0800 Subject: [PATCH 2/4] =?UTF-8?q?fix(ringbuffer):=20append=20=E5=9B=9E?= =?UTF-8?q?=E7=BB=95=E5=88=86=E6=94=AF=E6=8E=A8=E8=BF=9B=20writerIndex=5F?= =?UTF-8?q?=20=E9=98=B2=E6=AD=A2=E6=95=B0=E6=8D=AE=E4=B8=A2=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当 writerIndex_ < readerIndex_(环形回绕)时,memcpy 后未更新 writerIndex_,新写入数据被后续写入覆盖且索引停滞,导致数据丢失。在 memcpy 后补 writerIndex_ += len。 --- webserver/tcp/KRingBuffer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/webserver/tcp/KRingBuffer.h b/webserver/tcp/KRingBuffer.h index 4983a13..720fdb9 100644 --- a/webserver/tcp/KRingBuffer.h +++ b/webserver/tcp/KRingBuffer.h @@ -118,6 +118,7 @@ class Buffer : public kback::copyable { // 可以和std::copy对比下,看看哪个性能更高 if (writerIndex_ < readerIndex_) { memcpy(beginWrite(), data, len); + writerIndex_ += len; } else { // 看看尾部预留的空间大小 size_t reserve_tail = capacity_ - writerIndex_; From 4585e0f49c7973fb0ec0c407df579c4edde909a8 Mon Sep 17 00:00:00 2001 From: FluxMind-O <192421299+FluxMind-O@users.noreply.github.com> Date: Tue, 18 Aug 2026 04:59:33 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix(buffer):=20writeFd=20=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E5=AE=9E=E9=99=85=E5=86=99=E5=85=A5=E5=AD=97=E8=8A=82=E6=95=B0?= =?UTF-8?q?=E8=80=8C=E9=9D=9E=200?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit writeFd 始终返回 0 而非实际写入字节数 n,调用方 TcpConnection::handleWrite 依赖返回值判断写入进度,导致误判已写完。改为返回 n,并在 n < 0 时设置 *savedErrno = errno。 --- webserver/tcp/KBuffer.cpp | 4 +++- webserver/tcp/KRingBuffer.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/webserver/tcp/KBuffer.cpp b/webserver/tcp/KBuffer.cpp index ebc1a2c..08df4c2 100644 --- a/webserver/tcp/KBuffer.cpp +++ b/webserver/tcp/KBuffer.cpp @@ -91,8 +91,10 @@ ssize_t Buffer::writeFd(int fd, int *savedErrno) { if (n > 0) { retrieve(n); + } else if (n < 0) { + *savedErrno = errno; } - return 0; + return n; } #ifdef USE_EPOLL_LT diff --git a/webserver/tcp/KRingBuffer.cpp b/webserver/tcp/KRingBuffer.cpp index 96f8069..1f3f5af 100644 --- a/webserver/tcp/KRingBuffer.cpp +++ b/webserver/tcp/KRingBuffer.cpp @@ -124,8 +124,10 @@ ssize_t Buffer::writeFd(int fd, int *savedErrno) { ssize_t n = ::writev(fd, vec, 2); if (n > 0) { retrieve(n); + } else if (n < 0) { + *savedErrno = errno; } - return 0; + return n; } #ifdef USE_EPOLL_LT From 8d00883caee8aacc7724fd2c26cb5f09a8445b85 Mon Sep 17 00:00:00 2001 From: FluxMind-O <192421299+FluxMind-O@users.noreply.github.com> Date: Tue, 18 Aug 2026 05:00:15 +0800 Subject: [PATCH 4/4] =?UTF-8?q?perf(http):=20=E5=90=88=E5=B9=B6=20RINGBUFF?= =?UTF-8?q?ER=20=E8=A7=A3=E6=9E=90=E8=B7=AF=E5=BE=84=E6=B6=88=E9=99=A4?= =?UTF-8?q?=E5=85=A8=E9=87=8F=E6=8B=B7=E8=B4=9D=E5=B9=B6=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=20crlf=20=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原 RINGBUFFER 模式 parseRequest 通过 retrieveAsString 将整个缓冲区 O(n) 拷贝成 std::string 再解析,丧失零拷贝优势;且 if(crlf) 判断 std::search 返回值永远为真(data()+size() 非空指针),存在解析 bug。线性 Buffer 与环形 RingBuffer 暴露一致的 findCRLF/peek/retrieveUntil 接口,合并两套 parseRequest 为一份零拷贝实现。 --- webserver/http/KHttpContext.cpp | 56 +++------------------------------ 1 file changed, 4 insertions(+), 52 deletions(-) diff --git a/webserver/http/KHttpContext.cpp b/webserver/http/KHttpContext.cpp index 13c85e1..9d3ced4 100644 --- a/webserver/http/KHttpContext.cpp +++ b/webserver/http/KHttpContext.cpp @@ -43,58 +43,11 @@ bool HttpContext::processRequestLine(const char *begin, const char *end) { return succeed; } -#ifdef USE_RINGBUFFER -bool HttpContext::parseRequest(Buffer *buf, Timestamp receiveTime) { - string str_buf = buf->retrieveAsString(); - bool ok = true; - bool hasMore = true; - // 利用状态机转移,分三部分对请求报文进行解析 - while (hasMore) { - int start = 0; - if (state_ == kExpectRequestLine) { - const char *crlf = - std::search(str_buf.data() + start, str_buf.data() + str_buf.size(), - kCRLF, kCRLF + 2); - if (crlf) { - ok = processRequestLine(str_buf.data() + start, crlf); - if (ok) { - request_.setReceiveTime(receiveTime); - // buf->retrieveUntil(crlf + 2); - start = crlf + 2 - str_buf.data(); - state_ = kExpectHeaders; - } else { - hasMore = false; - } - } else { - hasMore = false; - } - } else if (state_ == kExpectHeaders) { - const char *crlf = - std::search(str_buf.data() + start, str_buf.data() + str_buf.size(), - kCRLF, kCRLF + 2); - if (crlf) { - const char *colon = std::find(str_buf.data() + start, crlf, ':'); - if (colon != crlf) { - request_.addHeader(str_buf.data() + start, colon, crlf); - } else { - // 空行,头部解析完毕 - state_ = kGotAll; - hasMore = false; - } - // buf->retrieveUntil(crlf + 2); - start = crlf + 2 - str_buf.data(); - } else { - hasMore = false; - } - } else if (state_ == kExpectBody) { - // 可以用于提取报文的主体部分 - } - } - return ok; -} - -#else // 解析http请求 +// 线性 Buffer 与环形 RingBuffer 暴露一致的接口(findCRLF/peek/retrieveUntil), +// 因此无需在 RINGBUFFER 模式下将整个缓冲区拷贝成 std::string 再解析, +// 直接基于 Buffer 接口零拷贝解析,避免大请求时的 O(n) 拷贝开销, +// 同时消除原先 string::data()+size() 非空指针导致 findCRLF 误判的问题。 bool HttpContext::parseRequest(Buffer *buf, Timestamp receiveTime) { bool ok = true; bool hasMore = true; @@ -138,4 +91,3 @@ bool HttpContext::parseRequest(Buffer *buf, Timestamp receiveTime) { } return ok; } -#endif