From 4ce4cea84dd4b43e1794fd8eef9fd25fc12c8630 Mon Sep 17 00:00:00 2001 From: impact-eintr Date: Mon, 16 Jan 2023 14:35:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9A=82=E5=81=9C=E6=9B=B4=E6=96=B0=20?= =?UTF-8?q?=E4=B9=8B=E5=90=8E=E6=9C=89=E4=BB=80=E4=B9=88=E5=AF=B9=E4=BA=8E?= =?UTF-8?q?tcp=E9=80=9A=E4=BF=A1=E7=9A=84=E6=96=B0=E7=9A=84=E7=96=91?= =?UTF-8?q?=E9=97=AE=E6=88=96=E7=90=86=E8=A7=A3=E5=8F=AF=E8=83=BD=E7=BB=93?= =?UTF-8?q?=E5=90=88=E8=AF=A5=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- note/README.md | 2 +- tcpip/transport/tcp/snd.go | 25 ++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/note/README.md b/note/README.md index 69a7d31..32978bd 100644 --- a/note/README.md +++ b/note/README.md @@ -1935,7 +1935,7 @@ c seq ack s | | 4 |------ack----->| | | - | | + | | ``` diff --git a/tcpip/transport/tcp/snd.go b/tcpip/transport/tcp/snd.go index f672962..d65e0d2 100644 --- a/tcpip/transport/tcp/snd.go +++ b/tcpip/transport/tcp/snd.go @@ -407,9 +407,6 @@ func (s *sender) handleRcvdSegment(seg *segment) { s.sndWnd = seg.window // 获取确认号 ack := seg.ackNumber - //if s.ep.id.LocalPort != 9999 { - // logger.NOTICE("进入处理ack报文", atoi(ack-1), atoi(s.sndUna), atoi(s.sndNxt)) - //} // 如果ack在最小未确认的seq和segNext之间 if (ack - 1).InRange(s.sndUna, s.sndNxt) { // 收到了东西 就暂停计时 @@ -426,20 +423,42 @@ func (s *sender) handleRcvdSegment(seg *segment) { // 获取这次确认的字节数,即 ack - snaUna acked := s.sndUna.Size(ack) // 更新下一个未确认的序列号 + /* + writeNxt(队列的指针) V outstanding: 2->1 +]->[seg3->seg2->seg1]->[seg3] ==> seg2 (队列中暂存) -seg1-(已确认 丢弃) + sndNxt(对应的字节)^ ^ sndUna(未确认的字节) + */ s.sndUna = ack ackLeft := acked originalOutstanding := s.outstanding // 从发送链表中删除已经确认的数据,发送窗口的滑动。 + /* + 假设我们收到了seg2开头的那个序号 我们将向后移动未确认字节到seg2 + 并从写队列中彻底删除seg1 + + writeNxt(队列的指针) V +]->[seg3->seg2->seg1]->[seg3] ==> seg2 (队列中暂存) -seg1-(已确认 丢弃) + sndNxt(对应的字节)^ ^ sndUna(未确认的字节) + */ for ackLeft > 0 { // 有成功确认的数据 丢弃它们 有剩余数据的话继续发送(根据拥塞策略控制) seg := s.writeList.Front() datalen := seg.logicalLen() + // 一个不完整的段 ackLeft=0不执行这步 + // [##seg1##] => [##] 这部分可能会重发一次 + // ^ack if datalen > ackLeft { seg.data.TrimFront(int(ackLeft)) break } + /* + 上一个段被完整确认 如果段指针来到了写队列的头指针 + writeNxt(队列的指针) V +]->[seg3->seg2->seg1]->[seg3] ==> seg2 (队列中暂存) -seg1-(已确认 丢弃) + sndNxt(对应的字节)^ ^ sndUna(未确认的字节) + */ if s.writeNext == seg { s.writeNext = seg.Next() }