网络基础小记(一)

TCP为啥需要三次握手、四次挥手

  • 三次握手的最主要的目的是保证链接是双工的,可靠性更多是通过重传机制来保证的
  • 因为连接是全双工的,双方必须都收到对方的FIN包及确认才可以关闭

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  1. [s] 是seq包; [S.]是ack包; [P]是数据包; [F]是fin包

为什么time_wait需要等待2MSL

  • 保证TCP协议的全双工连接能够可靠关闭
  • 保证这次连接的重复数据段从网络中消失

为啥会出现大量close_wait

  • 首先close_wait一般出现在被动关闭方
  • 并发请求太多导致
  • 被动关闭方未能及时释放端口资源导致
package main

import (
	"fmt"
	"net"
)

func main() {
	//1、监听端口
	listener, err := net.Listen("tcp", "0.0.0.0:9090")
	if err != nil {
		fmt.Printf("listen fail, err: %v\n", err)
		return
	}
	//2.建立套接字连接
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Printf("accept fail, err: %v\n", err)
			continue
		}
		//3. 创建处理协程
		go func(conn net.Conn) {
			//defer conn.Close() //思考题:这里不填写会有啥问题?
			// 这里不关闭的话 服务端出现close_wait 客户端fin_wait
			for {
				var buf [128]byte
				n, err := conn.Read(buf[:])
				if err != nil {
					fmt.Printf("read from connect failed, err: %v\n", err)
					break
				}
				str := string(buf[:n])
				fmt.Printf("receive from client, data: %v\n", str)
			}
		}(conn)
	}
}

TCP为啥需要流量控制

  • 由于通讯双方,网速不同。通讯方任一方发送的过快都会导致对方消息处理不过来,所以就需要把数据放到缓冲区中
  • 如果缓冲区满了,发送方还在疯狂发送,那么接收方只能把数据包丢弃。因此我们需要控制发送速率
  • 我们缓冲区剩余大小称之为接收窗口,用变量win表示、如果wiin=0.则发送方停止发送
    在这里插入图片描述

TCP为啥需要拥塞控制

  • 流量控制和拥塞控制是两个概念,拥塞控制是调解网络的负载
  • 接收方网络资源繁忙,因未及时响应ACK导致发送方重传大量数据,这样将会导致网络更加拥堵
  • 拥堵控制是动态调整win大小,不只是依赖缓冲区大小确认窗口大小

TCP拥塞控制

  • 慢开始和拥塞避免
  • 快速重传和快速恢复
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

为什么会出现粘包和拆包

  • 应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包
  • 应用程序写入数据小于套接字缓冲=区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包
  • 进行MSS(最大报文长度)大小的TCP分段,当TCP报文长度-TCP头部长度>MSS的时候将发送拆包
  • 接收方法不及时读取套接字缓冲区数据,这将会发生粘包
    在这里插入图片描述

一个简单的decode和encode代码

package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
)

const Msg_Header = "12345678"

func main() {
	//类比接收缓冲区 net.Conn
	bytesBuffer := bytes.NewBuffer([]byte{})

	//发送
	if err := Encode(bytesBuffer, "hello world 0!!!"); err != nil {
		panic(err)
	}
	if err := Encode(bytesBuffer, "hello world 1!!!"); err != nil {
		panic(err)
	}

	//读取
	for {
		if bt, err := Decode(bytesBuffer); err == nil {
			fmt.Println(string(bt))
			continue
		}
		break
	}
}

func Encode(bytesBuffer io.Writer, content string) error {
	//msg_header+content_len+content
	//8			+4			+content
	if err := binary.Write(bytesBuffer, binary.BigEndian, []byte(Msg_Header)); err != nil {
		return err
	}
	clen := int32(len([]byte(content)))
	if err := binary.Write(bytesBuffer, binary.BigEndian, clen); err != nil {
		return err
	}
	if err := binary.Write(bytesBuffer, binary.BigEndian, []byte(content)); err != nil {
		return err
	}
	return nil
}

func Decode(bytesBuffer io.Reader) (bodyBuf []byte, err error) {
	MagicBuf := make([]byte, len(Msg_Header))
	if _, err = io.ReadFull(bytesBuffer, MagicBuf); err != nil {
		return nil, err
	}
	if string(MagicBuf) != Msg_Header {
		return nil, errors.New("msg_header error")
	}

	lengthBuf := make([]byte, 4)
	if _, err = io.ReadFull(bytesBuffer, lengthBuf); err != nil {
		return nil, err
	}

	length := binary.BigEndian.Uint32(lengthBuf)
	bodyBuf = make([]byte, length)
	if _, err = io.ReadFull(bytesBuffer, bodyBuf); err != nil {
		return nil, err
	}
	return bodyBuf, err
}

服务端和客户端代码

package main

import (
	"fmt"
	"github.com/e421083458/gateway_demo/demo/base/unpack/unpack"
	"net"
)

func main() {
	//simple tcp server
	//1.监听端口
	listener, err := net.Listen("tcp", "0.0.0.0:9090")
	if err != nil {
		fmt.Printf("listen fail, err: %v\n", err)
		return
	}

	//2.接收请求
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Printf("accept fail, err: %v\n", err)
			continue
		}

		//3.创建协程
		go process(conn)
	}
}

func process(conn net.Conn) {
	defer conn.Close()
	for {
		bt, err := unpack.Decode(conn)
		if err != nil {
			fmt.Printf("read from connect failed, err: %v\n", err)
			break
		}
		str := string(bt)
		fmt.Printf("receive from client, data: %v\n", str)
	}
}

package main

import (
	"fmt"
	"github.com/e421083458/gateway_demo/demo/base/unpack/unpack"
	"net"

)

func main() {
	conn, err := net.Dial("tcp", "localhost:9090")
	defer conn.Close()
	if err != nil {
		fmt.Printf("connect failed, err : %v\n", err.Error())
		return
	}
	unpack.Encode(conn, "hello world 0!!!")
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值