mirror of
https://github.com/impact-eintr/netstack.git
synced 2025-10-09 23:00:04 +08:00
连接的建立 数据的收发 施工中。。。
This commit is contained in:
@@ -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))
|
||||||
}
|
}
|
||||||
|
1048
note/README.md
1048
note/README.md
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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) // 分发这个新连接到全连接队列
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -390,13 +390,13 @@ func (h *handshake) processSegments() *tcpip.Error {
|
|||||||
/*
|
/*
|
||||||
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()
|
||||||
|
|
||||||
|
@@ -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()
|
||||||
|
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user