php个人网站源码,国家企业信用信息公示系统官网山东,潮州网站设计,设计分为几种类型TCP
TCP#xff08;Transmission Control Protocol#xff0c;传输控制协议#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议
如何保证连接的可靠性#xff1f;
三次握手四次挥手
三次握手
TCP 三次握手#xff08;Three-way Handshake#xff09;…TCP
TCPTransmission Control Protocol传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议
如何保证连接的可靠性
三次握手四次挥手
三次握手
TCP 三次握手Three-way Handshake是TCP/IP 协议用来在两个网络端点之间建立一个连接的过程。它涉及到发送者和接收者的三个步骤确保两端都准备好接收和发送数据 以下是三次握手的步骤
SYN 客户端发送一个带有 SYN同步序列编号标志的TCP段到服务器以初始化一个连接。 此时客户端进入 SYN-SENT 状态SYN-ACK 服务器接收到客户端的SYN请求后必须确认客户的SYNACK同时自己也发送一个SYN请求即SYNACK。 此时服务器进入 SYN-RECEIVED 状态ACK 客户端接收到服务器的SYNACK后发送一个确认包ACK给服务器。该包发送完毕客户端和服务器进入ESTABLISHED状态完成三次握手连接建立 如果ACK没有在预定的时间内到达服务器服务器通常会重试发送SYN-ACK并继续等待客户端的ACK。这会重复几次根据TCP实现的具体细节和配置而有所不同。如果在几次重试后仍没有收到ACK服务器最终会超时并放弃这个连接尝试连接建立失败
Go中我们不直接操作这些底层细节因为net包抽象了这些实现细节。当我们使用net.Dial去连接服务器或者服务器使用Accept接收一个连接时三次握手都在底层自动完成了
四次挥手
TCP 四次挥手Four-way Handshake是TCP/IP 协议用来在两个网络端点之间终止一个连接的过程。它比建立连接时的三次握手要多一步因为TCP连接是全双工的所以每个方向必须单独进行终止。这个过程确保了数据完全传输且双方都同意关闭连接 步骤
FIN 客户端决定数据发送完毕之后它需要关闭连接。它发送一个带有 FIN 标志的TCP段到服务器表示没有更多的数据传输。 此时客户端进入 FIN-WAIT-1 状态ACK 服务器接收到这个 FIN 段后发送一个 ACK 确认告诉客户端它的 FIN 已经收到。 服务器进入 CLOSE-WAIT 状态。客户端在收到 ACK 后进入 FIN-WAIT-2 状态FIN (from server) 一段时间后服务器准备好关闭连接时它发送一个带有 FIN 标志的TCP段回给客户端。 服务器进入 LAST-ACK 状态ACK 客户端收到服务器的 FIN 后发送一个 ACK 确认然后进入 TIME-WAIT 状态。客户端会在 TIME-WAIT 状态等待足够的时间以确保服务器收到它的 ACK。 服务器在收到客户端的 ACK 后关闭连接进入 CLOSED 状态。客户端在等待一段时间后也会关闭连接进入 CLOSED 状态
这个过程确保了双方都不会丢失任何在网络中延迟的最后数据。Go中这个过程通常是由 net 包的 Close 方法来触发的。当你调用 Close 方法时底层的 TCP 套接字会开始四次挥手过程但这个过程对于开发者来说是透明的
Golang 创建TCP服务器与客户端
创建服务端
监听一个端口接受连接读取数据写入响应关闭连接
package mainimport (bufiofmtnetos
)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))}
}创建客户端
连接到服务器发送数据读取响应关闭连接
package mainimport (bufiofmtnetos
)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.Listen 和 net.ListenTCP
net.Listen 和 net.ListenTCP都是 Go 语言标准库 net 包中的函数用于监听网络端口但它们的用途和返回的类型有所不同 net.Listen 函数用于创建一个通用的网络监听器它可以监听TCP、UDP、Unix sockets等多种类型的网络协议。该函数返回一个 net.Listener 接口它抽象了网络监听操作的细节。使用 net.Listener 接口可以接受新的连接
ln, err : net.Listen(tcp, localhost:8080)第一个参数是网络类型第二个参数是地址和端口
net.ListenTCP 函数是一个更具体的函数它只用于TCP网络协议。它返回一个 *net.TCPListener 类型的对象这个对象提供了一些TCP特定的方法比如 SetDeadline、SetKeepAlive 等
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 (fmtnet/http
)func main() {http.HandleFunc(/, func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, Hello, youve requested: %s\n, r.URL.Path)})fmt.Println(Server is running at http://localhost:8080/)http.ListenAndServe(:8080, nil)
}客户端
package mainimport (iolognet/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
RPCRemote Procedure CallRPC允许客户端像调用本地函数一样调用远程服务器上的函数。Go的net/rpc包支持通过TCP或HTTP进行通信 服务端
package mainimport (lognetnet/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 (lognet/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/websocketpackage mainimport (lognet/httpgithub.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。客户端发送消息到服务器然后服务器将相同的消息回传回来。客户端也处理打开、接收消息、关闭和错误事件