Golang 网络编程

TCP

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议

如何保证连接的可靠性?

  1. 三次握手
  2. 四次挥手
三次握手

TCP 三次握手(Three-way Handshake)是TCP/IP 协议用来在两个网络端点之间建立一个连接的过程。它涉及到发送者和接收者的三个步骤,确保两端都准备好接收和发送数据
以下是三次握手的步骤:

  1. SYN
    客户端发送一个带有 SYN(同步序列编号)标志的TCP段到服务器,以初始化一个连接。
    此时,客户端进入 SYN-SENT 状态
  2. SYN-ACK
    服务器接收到客户端的SYN请求后,必须确认客户的SYN(ACK),同时自己也发送一个SYN请求,即SYN+ACK
    此时,服务器进入 SYN-RECEIVED 状态
  3. ACK
    客户端接收到服务器的SYN+ACK后,发送一个确认包ACK给服务器。该包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手,连接建立
    如果ACK没有在预定的时间内到达服务器,服务器通常会重试发送SYN-ACK,并继续等待客户端的ACK。这会重复几次,根据TCP实现的具体细节和配置而有所不同。如果在几次重试后仍没有收到ACK,服务器最终会超时并放弃这个连接尝试,连接建立失败

Go中,我们不直接操作这些底层细节,因为net包抽象了这些实现细节。当我们使用net.Dial去连接服务器,或者服务器使用Accept接收一个连接时,三次握手都在底层自动完成了

四次挥手

TCP 四次挥手(Four-way Handshake)是TCP/IP 协议用来在两个网络端点之间终止一个连接的过程。它比建立连接时的三次握手要多一步,因为TCP连接是全双工的,所以每个方向必须单独进行终止。这个过程确保了数据完全传输且双方都同意关闭连接
步骤:

  1. FIN
    客户端决定数据发送完毕之后,它需要关闭连接。它发送一个带有 FIN 标志的TCP段到服务器,表示没有更多的数据传输。
    此时,客户端进入 FIN-WAIT-1 状态
  2. ACK
    服务器接收到这个 FIN 段后,发送一个 ACK 确认,告诉客户端它的 FIN 已经收到。
    服务器进入 CLOSE-WAIT 状态。客户端在收到 ACK 后进入 FIN-WAIT-2 状态
  3. FIN (from server)
    一段时间后,服务器准备好关闭连接时,它发送一个带有 FIN 标志的TCP段回给客户端。
    服务器进入 LAST-ACK 状态
  4. ACK
    客户端收到服务器的 FIN 后,发送一个 ACK 确认,然后进入 TIME-WAIT 状态。客户端会在 TIME-WAIT 状态等待足够的时间以确保服务器收到它的 ACK
    服务器在收到客户端的 ACK 后,关闭连接,进入 CLOSED 状态。客户端在等待一段时间后也会关闭连接,进入 CLOSED 状态

这个过程确保了双方都不会丢失任何在网络中延迟的最后数据。Go中,这个过程通常是由 net 包的 Close 方法来触发的。当你调用 Close 方法时,底层的 TCP 套接字会开始四次挥手过程,但这个过程对于开发者来说是透明的

Golang 创建TCP服务器与客户端

创建服务端:

  1. 监听一个端口
  2. 接受连接
  3. 读取数据
  4. 写入响应
  5. 关闭连接
package mainimport ("bufio""fmt""net""os"
)func main() {// 监听端口ln, err := net.Listen("tcp", ":8080")if err != nil {fmt.Println(err)os.Exit(1)}defer ln.Close()// 循环接受连接for {conn, err := ln.Accept()if err != nil {fmt.Println(err)continue}// 在goroutine中处理连接go handleConnection(conn)}
}// 处理连接的函数
func handleConnection(conn net.Conn) {defer conn.Close()reader := bufio.NewReader(conn)for {// 读取数据message, err := reader.ReadString('\n')if err != nil {fmt.Println(err)return}fmt.Print("Message Received:", message)// 写入响应conn.Write([]byte("Hello, Client!\n"))}
}

创建客户端:

  1. 连接到服务器
  2. 发送数据
  3. 读取响应
  4. 关闭连接
package mainimport ("bufio""fmt""net""os"
)func main() {// 连接到服务器conn, err := net.Dial("tcp", "localhost:8080")if err != nil {fmt.Println(err)return}defer conn.Close()// 发送数据fmt.Fprintf(conn, "Hello, Server!\n")// 读取响应message, err := bufio.NewReader(conn).ReadString('\n')if err != nil {fmt.Println(err)os.Exit(1)}fmt.Print("Message from server:", message)
}

服务器监听8080端口,并在接受到连接后,在单独的goroutine中处理它。服务器读取来自客户端的消息,然后发送一个简单的响应。客户端连接到服务器,发送一个消息,并等待响应

net.Listennet.ListenTCP

net.Listennet.ListenTCP都是 Go 语言标准库 net 包中的函数,用于监听网络端口,但它们的用途和返回的类型有所不同
net.Listen 函数用于创建一个通用的网络监听器,它可以监听TCPUDPUnix sockets等多种类型的网络协议。该函数返回一个 net.Listener 接口,它抽象了网络监听操作的细节。使用 net.Listener 接口可以接受新的连接

ln, err := net.Listen("tcp", "localhost:8080")

第一个参数是网络类型,第二个参数是地址和端口

net.ListenTCP 函数是一个更具体的函数,它只用于TCP网络协议。它返回一个 *net.TCPListener 类型的对象,这个对象提供了一些TCP特定的方法,比如 SetDeadlineSetKeepAlive

addr, _ := net.ResolveTCPAddr("tcp", "localhost:8080")
ln, err := net.ListenTCP("tcp", addr)

这里需要先通过 net.ResolveTCPAddr 解析地址,然后传给 net.ListenTCP

使用 net.Listen 可以监听各种类型的网络协议,非常灵活。而 net.ListenTCP 则是专门用于TCP协议,提供了一些TCP特有的控制方法。根据具体需求选择使用哪一个
如果你只需要创建一个简单的TCP服务器,而不需要使用TCP协议的高级特性,net.Listen 就足够了。如果你需要对TCP连接进行更精细的控制,比如设置keep-alive参数或者设置连接的deadline,那么应该使用 net.ListenTCP

HTTP

可以使用net/http标准库来创建HTTP客户端和服务器
服务端

package mainimport ("fmt""net/http"
)func main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path)})fmt.Println("Server is running at http://localhost:8080/")http.ListenAndServe(":8080", nil)
}

客户端

package mainimport ("io""log""net/http"
)func main() {resp, err := http.Get("http://localhost:8080/")if err != nil {log.Fatal(err)}defer resp.Body.Close()body, err := io.ReadAll(resp.Body)if err != nil {log.Fatal(err)}log.Println(string(body))
}

服务器端代码将在8080端口启动一个HTTP服务器,并对所有到达根路径"/"的请求作出响应。客户端代码将向该服务器发送一个请求,并打印出响应的内容

RPC

RPC(Remote Procedure Call,RPC)允许客户端像调用本地函数一样调用远程服务器上的函数。Go的net/rpc包支持通过TCP或HTTP进行通信
服务端

package mainimport ("log""net""net/rpc"
)// Args 定义了RPC函数的参数
type Args struct {A, B int
}// Arith 定义了RPC服务的结构体
type Arith int// Multiply 是一个RPC服务方法,它将Args中的A和B相乘,并返回结果
func (t *Arith) Multiply(args *Args, reply *int) error {*reply = args.A * args.Breturn nil
}func main() {arith := new(Arith)rpc.Register(arith)// 在TCP上监听listener, err := net.Listen("tcp", ":1234")if err != nil {log.Fatal("Listen error:", err)}log.Printf("Serving RPC server on port %d", 1234)// 接受连接请求for {conn, err := listener.Accept()if err != nil {log.Fatal(err)}go rpc.ServeConn(conn)}
}

客户端

package mainimport ("log""net/rpc"
)// Args 和服务端定义的结构相同
type Args struct {A, B int
}func main() {client, err := rpc.Dial("tcp", "localhost:1234")if err != nil {log.Fatal("Dialing:", err)}// Synchronous callargs := &Args{A: 7, B: 8}var reply interr = client.Call("Arith.Multiply", args, &reply)if err != nil {log.Fatal("Arith error:", err)}log.Printf("Arith: %d*%d=%d", args.A, args.B, reply)
}

服务端注册了一个Arith服务,包含了一个Multiply方法。客户端通过创建一个rpc.Client对象,然后调用Call方法发起同步的RPC调用。Call方法的第一个参数是要调用的服务和方法的名称,格式是"服务名.方法名"。后面的参数分别是RPC方法的输入参数和输出参数

如果你打算在生产环境中使用RPC,可能需要考虑使用更现代的RPC框架,如gRPC,它提供更多的功能,包括支持Protocol Buffers和流式传输

WebSocket

gorilla/websocket是一个流行的库,用于处理WebSocket连接。WebSocket协议允许建立持久的全双工通信,这意味着服务器和客户端可以随时发送消息,而不需要建立多个HTTP连接
服务端
首先,你需要安装gorilla/websocket包:

go get github.com/gorilla/websocket
package mainimport ("log""net/http""github.com/gorilla/websocket"
)var upgrader = websocket.Upgrader{CheckOrigin: func(r *http.Request) bool {return true // 不检查来源},
}func echo(w http.ResponseWriter, r *http.Request) {conn, err := upgrader.Upgrade(w, r, nil)if err != nil {log.Print("upgrade:", err)return}defer conn.Close()for {mt, message, err := conn.ReadMessage()if err != nil {log.Println("read:", err)break}log.Printf("recv: %s", message)err = conn.WriteMessage(mt, message)if err != nil {log.Println("write:", err)break}}
}func main() {http.HandleFunc("/echo", echo)log.Fatal(http.ListenAndServe("localhost:8080", nil))
}

客户端:可以用JavaScript编写

const socket = new WebSocket('ws://localhost:8080/echo');socket.onopen = function(e) {console.log("Connection established!");socket.send("Hello Server!");
};socket.onmessage = function(event) {console.log(`Data received from server: ${event.data}`);
};socket.onclose = function(event) {if (event.wasClean) {console.log(`Connection closed cleanly, code=${event.code}, reason=${event.reason}`);} else {console.error('Connection died');}
};socket.onerror = function(error) {console.error(`[Error] ${error.message}`);
};

这段JavaScript代码创建了一个WebSocket客户端,连接到ws://localhost:8080/echo。客户端发送消息到服务器,然后服务器将相同的消息回传回来。客户端也处理打开、接收消息、关闭和错误事件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/622131.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring MVC中的方法的返回值!!!

参考入门案例的工程代码:Spring MVC入门案例!!!-CSDN博客 1.使用ModelAndView对象并返回 :这里我们在方法内部new了一个ModelAndView对象,通过这个对象,设置你想向jsp页面传达的信息。 modelA…

QT笔记 - 加载带有提升为自定义部件类的“.ui“文件 - 重写QUiLoader::createWidget()函数

说明 如果ui设计中有提升过小部件,则无法直接使用QUiLoader加载。完成加载需要重新实现UiLoader::createWidget()函数。 函数 virtual QWidget * QUiLoader::createWidget(const QString & className, QWidget * parent Q_NULLPTR, const QString & name…

RibbonGroup添加QCheckBox

RibbonGroup添加 QCheckBox: QCheckBox* pCheck new QCheckBox(tr("Check")); pCheck->setToolTip(tr("Check")); groupClipboard->addWidget(pCheck); connect(pCheck, SIGNAL(stateChanged(int)), this, SLOT(checkClick(int))); …

[学习笔记]刘知远团队大模型技术与交叉应用-汇总

参考资料: 视频:【清华NLP】刘知远团队大模型公开课全网首发|带你从入门到实战 课程计划 L1-NLP&Big Model Basics [学习笔记]刘知远团队大模型技术与交叉应用L1-NLP&Big Model Basics L2-Neural Network Basics [学习笔记]刘知…

微调深度学习模型:初级指南

引言 在深度学习领域,微调(Fine-tuning)是一种常见的实践,旨在优化预训练模型以适应特定任务或数据集。这对于那些希望利用已有模型来解决类似问题的初学者而言,是一个非常有用的技巧。 预训练模型的选择 微调开始于选…

计算机二级Python基本排序题-序号42(补充)

请在屏幕上输出以下杨辉三角形: 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 a [] for i in range(8) :a.append([])for j in range(8) :a[i].append(0) for i in range(8) :a[i][0] 1a[i][i] 1 for i in range(2, 8) :f…

【Java JVM】栈帧

执行引擎是 Java 虚拟机核心的组成部分之一。 在《Java虚拟机规范》中制定了 Java 虚拟机字节码执行引擎的概念模型, 这个概念模型成为各大发行商的 Java 虚拟机执行引擎的统一外观 (Facade)。 不同的虚拟机的实现中, 通常会有 解释执行 (通过解释器执行)编译执行 (通过即时编…

Github Copilot最全的安装与使用教程:一款非常好用的AI编程工具

Github Copilot最全的安装与使用教程 第一章 安装1.安装 GitHub Copilot2.获取资格第二章 使用1.产生建议1.1 键入你想要完成的操作的注释1.2 CtrlI 2. 接受建议3.查看下一个建议3.接受部分建议4.在新选项卡接受建议5.完成多项功能6.聊天 GitHub Copilot 供经过验证的学生、教师…

C++中的23种设计模式精讲

目录 1 单例模式2 工厂方法模式3 抽象工厂模式4参考 1 单例模式 题目链接为&#xff1a;小明的购物车 C代码如下&#xff0c; #include <iostream> #include <string> #include <vector>using namespace std;class ShoppingCart { public:static Shopping…

C语言经典算法之直接排序算法

目录 前言 一、代码实现 二、时空复杂度 时间复杂度&#xff1a; 空间复杂度&#xff1a; 前言 建议&#xff1a;1.学习算法最重要的是理解算法的每一步&#xff0c;而不是记住算法。 2.建议读者学习算法的时候&#xff0c;自己手动一步一步地运行算法。 tips:希尔排序算…

利用反射获取websocket,session字段的值

首先利用反射获取方法字段&#xff0c;然后取得字段的值 private static ConcurrentHashMap<String, Session> map new ConcurrentHashMap<>();OnOpenpublic void onOpen(Session session) throws IllegalAccessException {log.info(session.getId() "开始连…

Flask架构--路由和蓝图

学习视频&#xff1a;第二章&#xff1a;路由和蓝图 1 Flask查询路由的方式_哔哩哔哩_bilibili 参考&#xff1a;Flask框架之路由与蓝图的使用_flask 路由和蓝图-CSDN博客 1.路由的概念&#xff1a; 用于将http请求与特定的python函数相匹配。定义路由后&#xff0c;flask程…

模型索引:QModelIndex

一、为什么要使用模型索引&#xff1f; 从名字可以看出&#xff0c;他是模型的索引&#xff0c;只要对模型实体&#xff08;各种xxxModel的实体&#xff09;施加这个索引&#xff0c;model就会返回数据集中对应的值&#xff0c;或者通过这个索引修改对应数据集中的值。 类比数…

Java内容

目录 1.命名规范 1.命名规范 2.变量

懒得玩游戏--帮我做数独

目录 简介自动解数独思路核心思路输入解析打印 完整代码 简介 最近玩上了一款类似于数独的微信小程序游戏&#xff0c;名字叫数独趣味闯关&#xff0c;过了数独的关卡之后会给拼图&#xff0c;玩了几关之后摸清套路了就有点累了&#xff0c;但是还想集齐拼图&#xff0c;所以就…

【AUTOSAR】--01 AUTOSAR网络管理基础

AUTOSAR网络管理做了几个项目了&#xff0c;但发现还是有些理解不够深入的地方&#xff0c;最近趁着有个新项目也要做AUTOSAR网络管理&#xff0c;再从头梳理一下AUTOSAR网络管理&#xff0c;预计用2-3篇文章&#xff0c;把AUTOSAR网络重新梳理完成。 这是第一篇&#xff0c;主…

C //练习 4-13 编写一个递归版本的reverse(s)函数,以将字符串s倒置。

C程序设计语言 &#xff08;第二版&#xff09; 练习 4-13 练习 4-13 编写一个递归版本的reverse(s)函数&#xff0c;以将字符串s倒置。 注意&#xff1a;代码在win32控制台运行&#xff0c;在不同的IDE环境下&#xff0c;有部分可能需要变更。 IDE工具&#xff1a;Visual S…

Element-Puls Form表单内嵌套el-table表格,根据表格复选框多选或单选动态设置行的验证规则

需求 根据 Table 表格内的复选框来控制当前选中行是否添加必填校验规则 效果图 实现思想 我们需要设置一个 flag 来标识已勾选的行&#xff0c;el-table渲染数据结构是数组对象形式&#xff0c;我们可以在每个对象中手动加如一个标识&#xff0c;例如默认&#xff1a;selected …

Windows环境 elasticsearch 及可视化界面 安装

安装 elastic 的官网 elastic.co/downloads/elasticsearch 当你解压好了归档文件之后&#xff0c;Elasticsearch 已经准备好运行了。按照下面的操作&#xff0c;在前台(foregroud)启动 Elasticsearch&#xff1a; cd elasticsearch-<version> ./bin/elasticsearch 如…

大型语言模型综述/总结 LLM A Survey of Large Language Models

A Survey of Large Language Model AbstractINTRODUCTIONOVERVIEW背景LLM的新兴能力LLM的关键技术GPT 系列模型的技术演进 大语言模型资源公开可用的模型检查点或 API常用语料库代码库资源 预训练数据收集架构 论文标题&#xff1a;A Survey of Large Language Model 论文地址&…