连接的建立 数据的收发 施工中。。。

This commit is contained in:
impact-eintr
2023-01-04 11:31:11 +08:00
parent 5d0a9c3721
commit bda9357103
8 changed files with 1127 additions and 31 deletions

View File

@@ -193,8 +193,8 @@ func main() {
log.Printf("客户端 建立连接\n\n客户端 写入数据\n") log.Printf("客户端 建立连接\n\n客户端 写入数据\n")
size := 1 << 11 size := 1 << 10
for i := 0; i < 100; i++ { for i := 0; i < 3; i++ {
//conn.Write([]byte("Hello Netstack")) //conn.Write([]byte("Hello Netstack"))
conn.Write(make([]byte, size)) conn.Write(make([]byte, size))
} }

File diff suppressed because it is too large Load Diff

View File

@@ -488,9 +488,11 @@ func (n *NIC) DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolN
}) })
id := TransportEndpointID{dstPort, r.LocalAddress, srcPort, r.RemoteAddress} id := TransportEndpointID{dstPort, r.LocalAddress, srcPort, r.RemoteAddress}
// 调用分流器根据传输层协议和传输层id分发数据报文 // 调用分流器根据传输层协议和传输层id分发数据报文
// 现在本网卡中尝试分发
if n.demux.deliverPacket(r, protocol, vv, id) { if n.demux.deliverPacket(r, protocol, vv, id) {
return return
} }
// 在整个协议栈尝试分发
if n.stack.demux.deliverPacket(r, protocol, vv, id) { if n.stack.demux.deliverPacket(r, protocol, vv, id) {
return return
} }

View File

@@ -126,6 +126,8 @@ func (d *transportDemuxer) findEndpointLocked(eps *transportEndpoints,
} }
// Try to find a match with the id minus the remote part. // Try to find a match with the id minus the remote part.
// listener 的情况 本地没有这个 dstIP+dstPort:srcIP+srcPort 的连接交由
// ""+0:srcIP+srcPort的Listener来处理
nid.LocalAddress = id.LocalAddress nid.LocalAddress = id.LocalAddress
nid.RemoteAddress = "" nid.RemoteAddress = ""
nid.RemotePort = 0 nid.RemotePort = 0

View File

@@ -280,7 +280,7 @@ func (e *endpoint) handleSynSegment(ctx *listenContext, s *segment, opts *header
return return
} }
// 到这里,三次握手已经完成,那么分发一个新的连接 // 到这里,三次握手已经完成,那么分发一个新的连接
e.deliverAccepted(n) e.deliverAccepted(n) // 分发这个新连接到全连接队列
} }
// handleListenSegment is called when a listening endpoint receives a segment // handleListenSegment is called when a listening endpoint receives a segment
@@ -290,28 +290,51 @@ func (e *endpoint) handleListenSegment(ctx *listenContext, s *segment) {
case flagSyn: // syn报文处理 case flagSyn: // syn报文处理
// 分析tcp选项 // 分析tcp选项
opts := parseSynSegmentOptions(s) opts := parseSynSegmentOptions(s)
if incSynRcvdCount() { if !incSynRcvdCount() {
s.incRef() s.incRef()
go e.handleSynSegment(ctx, s, &opts) go e.handleSynSegment(ctx, s, &opts)
} else { } else {
// 防止半连接池攻击 我们使用cookie
cookie := ctx.createCookie(s.id, s.sequenceNumber, encodeMSS(opts.MSS)) cookie := ctx.createCookie(s.id, s.sequenceNumber, encodeMSS(opts.MSS))
// Send SYN with window scaling because we currently
// dont't encode this information in the cookie.
//
// Enable Timestamp option if the original syn did have
// the timestamp option specified.
synOpts := header.TCPSynOptions{ synOpts := header.TCPSynOptions{
WS: -1, WS: -1, // 告知对方关闭窗口滑动
TS: opts.TS, TS: opts.TS,
TSVal: tcpTimeStamp(timeStampOffset()), TSVal: tcpTimeStamp(timeStampOffset()),
TSEcr: opts.TSVal, TSEcr: opts.TSVal,
} }
// 返回 syn+ack 报文 // 返回 syn+ack 报文 ack+1 表明我们确认了这个syn报文 占用一个字节
sendSynTCP(&s.route, s.id, flagSyn|flagAck, cookie, s.sequenceNumber+1, ctx.rcvWnd, synOpts) sendSynTCP(&s.route, s.id, flagSyn|flagAck, cookie, s.sequenceNumber+1, ctx.rcvWnd, synOpts)
} }
// 返回一个syn+ack报文
case flagFin: // fin报文处理 case flagAck:
// 三次握手最后一次 ack 报文 // NOTICE 对应处理后台协程过多的情况 三次握手最后一次 ack 报文
// 当我们的后台写协程不足以处理新的连接的时候
// 我们认为协议栈目前没有能力处理大规模数据
// 所以我们限制后面新成立的连接的窗口尺寸
// 验证cookie seq-1 和 ack-1 表明 还原两次握手增加的计数
if data, ok := ctx.isCookieValid(s.id, s.ackNumber-1,
s.sequenceNumber-1); ok && int(data) < len(mssTable) {
// Create newly accepted endpoint and deliver it.
rcvdSynOptions := &header.TCPSynOptions{
MSS: mssTable[data],
// 关闭我们的窗口滑动
WS: -1,
}
if s.parsedOptions.TS {
rcvdSynOptions.TS = true
rcvdSynOptions.TSVal = s.parsedOptions.TSVal
rcvdSynOptions.TSEcr = s.parsedOptions.TSEcr
}
// 三次握手已经完成新建一个tcp连接
n, err := ctx.createConnectedEndpoint(s, s.ackNumber-1,
s.sequenceNumber-1, rcvdSynOptions)
if err == nil {
n.tsOffset = 0
e.deliverAccepted(n) // 分发这个新连接到全连接队列
}
}
} }
} }

View File

@@ -388,15 +388,15 @@ func (h *handshake) processSegments() *tcpip.Error {
// execute executes the TCP 3-way handshake. // execute executes the TCP 3-way handshake.
// 执行tcp 3次握手客户端和服务端都是调用该函数来实现三次握手 // 执行tcp 3次握手客户端和服务端都是调用该函数来实现三次握手
/* /*
c flag s c flag s
生成ISN1 | |生成ISN2 生成ISN1 | | 生成ISN2
sync_sent|------sync---->|sync_rcvd sync_sent |------sync----->| sync_rcvd
| | | |
| | | |
established|<--sync|ack----| established |<---sync|ack----|
| | | |
| | | |
|------ack----->|established |------ack------>| established
*/ */
func (h *handshake) execute() *tcpip.Error { func (h *handshake) execute() *tcpip.Error {
// 是否需要拿到下一条地址 // 是否需要拿到下一条地址
@@ -663,7 +663,23 @@ func (e *endpoint) sendRaw(data buffer.VectorisedView, flags byte, seq, ack seqn
return err return err
} }
// 从发送队列中取出数据并发送出去 // 从发送队列中取出数据并发送出去
/*
ep.sndQueue: ...->seg3->seg2->seg1 =>
当发送队列中有数据的时候 将这个队列压入写队列 队列的队列
writeNext
V
ep.snd.writeList:...->seglist3->seglist2->seglist1 =>
^ ^ ^ ^ ^ ^
|_s->s_| |_s->s_| |_s->s_|
我们消费数据的时候找到写队列的队列头,然后遍历它
*/
func (e *endpoint) handleWrite() *tcpip.Error { func (e *endpoint) handleWrite() *tcpip.Error {
e.sndBufMu.Lock() e.sndBufMu.Lock()

View File

@@ -425,9 +425,9 @@ func (e *endpoint) Write(p tcpip.Payload, opts tcpip.WriteOptions) (uintptr, <-c
l := len(v) l := len(v)
s := newSegmentFromView(&e.route, e.id, v) // 分段 s := newSegmentFromView(&e.route, e.id, v) // 分段
// 插入发送队列 // 插入发送队列
e.sndBufUsed += l e.sndBufUsed += l // 发送队列中段+1
e.sndBufInQueue += seqnum.Size(l) e.sndBufInQueue += seqnum.Size(l) // 发送队列长度+length
e.sndQueue.PushBack(s) e.sndQueue.PushBack(s) // 将段压入发送队列
e.sndBufMu.Unlock() e.sndBufMu.Unlock()

View File

@@ -525,7 +525,7 @@ func (s *sender) retransmitTimerExpired() bool {
// 发送数据段,最终调用 sendSegment 来发送 // 发送数据段,最终调用 sendSegment 来发送
func (s *sender) sendData() { func (s *sender) sendData() {
limit := s.maxPayloadSize //最开始是65483 limit := s.maxPayloadSize
// 如果TCP在超过重新传输超时的时间间隔内没有发送数据TCP应该在开始传输之前将cwnd设置为不超过RW。 // 如果TCP在超过重新传输超时的时间间隔内没有发送数据TCP应该在开始传输之前将cwnd设置为不超过RW。
if !s.fr.active && time.Now().Sub(s.lastSendTime) > s.rto { if !s.fr.active && time.Now().Sub(s.lastSendTime) > s.rto {
@@ -539,7 +539,9 @@ func (s *sender) sendData() {
var dataSent bool var dataSent bool
// 遍历发送链表,发送数据 // 遍历发送链表,发送数据
// tcp拥塞控制s.outstanding < s.sndCwnd 判断正在发送的数据量不能超过拥塞窗口。 // tcp拥塞控制s.outstanding < s.sndCwnd 判断正在发送的数据量不能超过拥塞窗口。
for seg = s.writeNext; seg != nil && s.outstanding < s.sndCwnd; seg = seg.Next() { // 首次发送不会超过两个包 for seg = s.writeNext;
seg != nil && s.outstanding < s.sndCwnd;
seg = seg.Next() {
// 如果seg的flags是0将flags改为psh|ack // 如果seg的flags是0将flags改为psh|ack
if seg.flags == 0 { if seg.flags == 0 {
seg.sequenceNumber = s.sndNxt seg.sequenceNumber = s.sndNxt
@@ -560,8 +562,7 @@ func (s *sender) sendData() {
if seg.flags&flagFin != 0 { if seg.flags&flagFin != 0 {
panic("Netstack queues FIN segments without data.") panic("Netstack queues FIN segments without data.")
} }
if !seg.sequenceNumber.LessThan(end) { if !seg.sequenceNumber.LessThan(end) { // 超过了发送窗口限制
log.Println("暂停数据发送 等待确认标号", seg.sequenceNumber, " 已收到 。。。。")
break break
} }
@@ -573,6 +574,8 @@ func (s *sender) sendData() {
// 如果seg的payload字节数大于available // 如果seg的payload字节数大于available
// 将seg进行分段并且插入到该seg的后面 // 将seg进行分段并且插入到该seg的后面
// ...->[seg3->seg2->seg1]->[seg3->seg2->seg1(2048)]
// ...->[seg3->seg2->seg1]->[seg4->seg3->seg2(1024)->seg1(1024)]
if seg.data.Size() > available { if seg.data.Size() > available {
nSeg := seg.clone() nSeg := seg.clone()
nSeg.data.TrimFront(available) // NOTE 删掉用过的 nSeg.data.TrimFront(available) // NOTE 删掉用过的
@@ -599,8 +602,10 @@ func (s *sender) sendData() {
// 发送包 开始计算RTT // 发送包 开始计算RTT
s.sendSegment(seg.data, seg.flags, seg.sequenceNumber) s.sendSegment(seg.data, seg.flags, seg.sequenceNumber)
// 发送一个数据段后更新sndNxt // 发送一个数据段后更新sndNxt
// 旧的 sndNxt V
// ...->[seg3->seg2->seg1]->[seg3->seg2->seg1]
// 新的 sndNxt^
if s.sndNxt.LessThan(segEnd) { if s.sndNxt.LessThan(segEnd) {
log.Println(s.ep.id.LocalPort, " 更新sndNxt", s.sndNxt, " 为 ", segEnd, "下一次发送的数据头为", segEnd)
s.sndNxt = segEnd s.sndNxt = segEnd
} }
} }