网站首页 > 技术教程 正文
golang微服务网关之网络基础知识
面试中被面试官经常问到的一些关于tcp网络知识问题 今天依依给大家分析下(毫无保留分享:)
- 三次握手
- 四次挥手
- 为啥time_wait需要等待2MSL?
- 为啥会出现大量的close_wait?
- 什么时候会出现FIN-WAIT?
- TCP为啥需要流量控制?
- 如何调整网络负载?
- tcp为啥需要拥塞控制?
- 慢开始和拥塞避免?
- 快速重传和快速恢复?
- 为什么出现粘包/拆包?
为啥time_wait需要等待2MSL?
1,MSL:Maximum Segment Lifetime,30秒-1分钟
2,保证TCP协议的全双工连接能够可靠关闭
3,保证这次连接的重复数据段从网络中消失
为啥会出现大量的close_wait?
1,首先close_wait一般书现在被动方关闭
2,并发请求太多导致
3,被动关闭方未及时释放端口资源导致
CLOSE_WAIT产生原因
close_wait是被动关闭连接是形成的,根据TCP状态机,服务器端收到客户端发送的FIN,TCP协议栈会自动发送ACK,链接进入close_wait状态。但如果服务器端不执行socket的close()操作,状态就不能由close_wait迁移到last_ack,则系统中会存在很多close_wait状态的连接;
说白的就是并发可能有点大,io不能及时切换过去,I/O线程被意外阻塞,I/O操作处理不及时,链路不能被及时释放
TCP为啥需要流量控制?
如何调整网络负载,tcp为啥需要拥塞控制?
- 慢开始和拥塞避免
- 快速重传和快速恢复
所谓慢开始,tcp刚开始一点点传递试探一下网络的承受能力,以免扰乱网络通道的秩序
上图中,图标3处遇到网络拥塞,就把拥塞的窗口直接降为1了,然后重新开始慢开始,一点点递增
为了优化慢开始所以对算法进行了优化:快重传和快恢复
快速重传;当收到3个重复ACK 执行快重传:
会把当前拥塞窗口降为原来的一般。然后把拥塞避免的预值降为原来的一半,进入一个快速恢复的阶段
快速恢复:因为受到3次重复ack,丢包,只要是在这个阶段丢的包,会重复发送一遍,直到把所有丢失的包重新发送完毕后就会退出快速恢复阶段,
然后进入拥塞避免阶段
为什么出现粘包/拆包?
上图:
发送方由应用程序发送应用的报文,根据应用数据报文大小的不同,它会占用2个或者1个,应用的数据实际会发送到tcp的缓冲区里面(发送缓冲区)。真正发送是由linux内核走tcp连接发送;
tcp根据缓冲区大小来决定是否要粘包,粘包:多次请求合并到一个tcp报文中,拆包:一次请求拆到多个tcp报文里面,至于数据如何被包装都是由tcp底层去完成的。
因为我运用的其实是应用层,不需要关心它的细节,数据会流入接收方的接收缓冲区,接收方通过socket的reverve方法去获取到数据。
我们是在应用层通过socket 直接从bufer缓冲区拿取数据
如何获取完整应用的数据报文?
如何获取完整的数据报文?
实例代码:
golang创建udp服务和客户端
golang创建tcp服务器和客户端
客户端:defer conn.Close() //思考题:这里不填写会有啥问题?(连接一直在建立状态,除非tcp连接探测后才会关闭)
服务端:defer conn.Close() //思考题:这里不填写会有啥问题?
客户端发起了关闭,服务端没有关闭,此时按照四次挥手图分析:
客户端是主动关闭方,客户端此时处于FIN-WAIT-2;
服务端属于被动关闭方,服务端处于CLOSE-WAIT状态;
golang创建http服务
服务端:
- 创建路由器;
- 设置路由规则;
- 创建服务器;
- 监听端口并提供服务;
客户端:
- 创建连接池:
- 创建客户端;
- 请求数据;
- 读取内容;
golang http服务器源码分析:
在分析httpserver源码之前,请看看此文章 ,了解下type func的用法,函数式一等公民概念,不然下面代码可能难以理解。
type关键字的用法
从最简单的例子开始:
package main
import (
"log"
"net/http"
"time"
)
var (
Addr = ":1210"
)
func main() {
// 创建路由器
mux := http.NewServeMux()
// 设置路由规则
mux.HandleFunc("/bye", sayBye)
// 创建服务器
server := &http.Server{
Addr: Addr,
WriteTimeout: time.Second * 3,
Handler: mux,
}
// 监听端口并提供服务
log.Println("Starting httpserver at "+Addr)
log.Fatal(server.ListenAndServe())
}
func sayBye(w http.ResponseWriter, r *http.Request) {
time.Sleep(1 * time.Second)
w.Write([]byte("bye bye ,this is httpServer"))
}
来看看HandleFunc是啥?
// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
HandlerFunc(handler)
此处就是用到了type关键字 把一个函数转成HandlerFunc 类型,并且实现了ServeHTTP方法
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
ServeHTTP方法又实现了Handler接口
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
通过回调思路最终执行了sayBye()
mu:一把锁
m:存放着路由和回调函数
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // slice of entries sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
h 注册的函数
pattern 注册的路由
type muxEntry struct {
h Handler
pattern string
}
注册路由
mux.Handle(pattern, HandlerFunc(handler))
开启服务:
func (srv *Server) ListenAndServe() error {
if srv.shuttingDown() {
return ErrServerClosed
}
addr := srv.Addr
if addr == "" {
addr = ":http"
}
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
return srv.Serve(ln)
}
func (srv *Server) Serve(l net.Listener) error
处理链接:
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
if r.RequestURI == "*" {
if r.ProtoAtLeast(1, 1) {
w.Header().Set("Connection", "close")
}
w.WriteHeader(StatusBadRequest)
return
}
h, _ := mux.Handler(r)
h.ServeHTTP(w, r)
}
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string)
httpClient源码简单解析:
先看看一个简单的例子:
package main
import (
"fmt"
"io/ioutil"
"net"
"net/http"
"time"
)
func main() {
// 创建连接池
transport := &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second, //连接超时
KeepAlive: 30 * time.Second, //探活时间
}).DialContext,
MaxIdleConns: 100, //最大空闲连接
IdleConnTimeout: 90 * time.Second, //空闲超时时间
TLSHandshakeTimeout: 10 * time.Second, //tls握手超时时间
ExpectContinueTimeout: 1 * time.Second, //100-continue状态码超时时间
}
// 创建客户端
client := &http.Client{
Timeout: time.Second * 30, //请求超时时间
Transport: transport,
}
// 请求数据
resp, err := client.Get("http://127.0.0.1:1210/bye")
if err != nil {
panic(err)
}
defer resp.Body.Close()
// 读取内容
bds, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(bds))
}
分析以后继续。。。。。。。。
猜你喜欢
- 2025-06-10 如何将VMWare虚拟机的IP改为静态IP
- 2025-06-10 Gateway网关在url参数带有特殊字符的情况下转发失败(响应400)
- 2025-06-10 DNS分离解析实验(dns解析两种方式)
- 2025-06-10 LINUX 网络配置(linux 网络配置工具)
- 2025-06-10 如何在linux上手动配置网络(linux怎么配置网络ip)
- 2025-06-10 Linux:显示和管理IP址设置(linux设置ip访问权限)
- 2025-06-10 语音功能加入,打造六合一全能酒店网关
- 2025-06-10 微服务架构必读篇 - 网关(微服务网关框架有哪些)
- 2025-06-10 无需公网IP,实现自建NAS远程访问:贝锐花生壳Docker版使用教程
- 2025-06-10 通过LoRaWAN网关实现FRP功能(网关route)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- 下划线是什么 (87)
- 精美网站 (58)
- qq登录界面 (90)
- nginx 命令 (82)
- nginx .http (73)
- nginx lua (70)
- nginx 重定向 (68)
- Nginx超时 (65)
- nginx 监控 (57)
- odbc (59)
- rar密码破解工具 (62)
- annotation (71)
- 红黑树 (57)
- 智力题 (62)
- php空间申请 (61)
- 按键精灵 注册码 (69)
- 软件测试报告 (59)
- ntcreatefile (64)
- 闪动文字 (56)
- guid (66)
- abap (63)
- mpeg 2 (65)
- column (63)
- dreamweaver教程 (57)
- excel行列转换 (56)
本文暂时没有评论,来添加一个吧(●'◡'●)