您现在的位置是:首页 >学无止境 >【Go】五、网络编程网站首页学无止境
【Go】五、网络编程
文章目录
网络编程
1、互联网协议介绍
2、Socket编程
2.1、socket图解
1、socket又称套接字,应用程序通过套接字向网络发出请求或者应答网络请求
2、常用的socket类型有两种:流式socket和数据报socket,流式是一种面向连接(TCP)、数据报是一种无连接(UDP)
3、TCP:比较靠谱、面向连接、比较慢
4、UDP:不大靠谱、无连接、比较快
2.2、TCP编程
1、TCP协议:TCP/IP协议即传输控制协议/网络协议,是一种面向连接、可靠的、基于字节流的传输层通信协议,因为是面向连接的协议,数据像流水一样传输,存在粘包的问题
2、TCP服务端:一个TCP服务端可以同时连接多个客户端,例如世界各地的用户使用自己电脑上的浏览器访问淘宝网,因为Go语言中创建多个goroutine实现并发非常方便和高效,所以我们可以每建立一次连接久创建一个goroutine去处理。
1)监听端口;2)接收客户端请求建立连接;3)创建goroutine处理链接
使用Go语言的net包实现TCP服务端代码
// tcp/server/main.go
// TCP server端
// 处理函数
func process(conn net.Conn) {
defer conn.Close() // 关闭连接
for {
reader := bufio.NewReader(conn)
var buf [128]byte
n, err := reader.Read(buf[:]) // 读取数据
if err != nil {
fmt.Println("read from client failed, err:", err)
break
}
recvStr := string(buf[:n])
fmt.Println("收到client端发来的数据:", recvStr)
conn.Write([]byte(recvStr)) // 发送数据
}
}
func main() {
listen, err := net.Listen("tcp", "127.0.0.1:20000")
if err != nil {
fmt.Println("listen failed, err:", err)
return
}
for {
conn, err := listen.Accept() // 建立连接
if err != nil {
fmt.Println("accept failed, err:", err)
continue
}
go process(conn) // 启动一个goroutine处理连接
}
}
3、TCP客户端
1)建立与服务端的连接;2)进行数据收发;3)关闭连接
// tcp/client/main.go
// 客户端
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:20000")
if err != nil {
fmt.Println("err :", err)
return
}
defer conn.Close() // 关闭连接
inputReader := bufio.NewReader(os.Stdin)
for {
input, _ := inputReader.ReadString('
') // 读取用户输入
inputInfo := strings.Trim(input, "
")
if strings.ToUpper(inputInfo) == "Q" { // 如果输入q就退出
return
}
_, err = conn.Write([]byte(inputInfo)) // 发送数据
if err != nil {
return
}
buf := [512]byte{}
n, err := conn.Read(buf[:])
if err != nil {
fmt.Println("recv failed, err:", err)
return
}
fmt.Println(string(buf[:n]))
}
}
2.3、UDP编程
1、UDP协议:用户数据报协议,是OSI参考模型中一种无连接的传输层协议,不需要建立连接就能直接进行数据发送和接收,属于不可靠,没有时序的通信,但UDP协议的实时性比较好,通常用于视频直播相关领域。
2、UDP服务端
// UDP/server/main.go
// UDP server端
func main() {
listen, err := net.ListenUDP("udp", &net.UDPAddr{
IP: net.IPv4(0, 0, 0, 0),
Port: 30000,
})
if err != nil {
fmt.Println("listen failed, err:", err)
return
}
defer listen.Close()
for {
var data [1024]byte
n, addr, err := listen.ReadFromUDP(data[:]) // 接收数据
if err != nil {
fmt.Println("read udp failed, err:", err)
continue
}
fmt.Printf("data:%v addr:%v count:%v
", string(data[:n]), addr, n)
_, err = listen.WriteToUDP(data[:n], addr) // 发送数据
if err != nil {
fmt.Println("write to udp failed, err:", err)
continue
}
}
}
3、UDP客户端
// UDP 客户端
func main() {
socket, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: net.IPv4(0, 0, 0, 0),
Port: 30000,
})
if err != nil {
fmt.Println("连接服务端失败,err:", err)
return
}
defer socket.Close()
sendData := []byte("Hello server")
_, err = socket.Write(sendData) // 发送数据
if err != nil {
fmt.Println("发送数据失败,err:", err)
return
}
data := make([]byte, 4096)
n, remoteAddr, err := socket.ReadFromUDP(data) // 接收数据
if err != nil {
fmt.Println("接收数据失败,err:", err)
return
}
fmt.Printf("recv:%v addr:%v count:%v
", string(data[:n]), remoteAddr, n)
}
2.4、粘包(❌没有详细看代码,但是大概知道怎么实现)
1、为什么会出现粘包?
1)tcp数据传输模式是流模式,在保持长连接的时候可以进行多次收和发
2)我们提交一段数据给TCP发送的时候,TCP没有立即发送此段数据,而是等待一小段时间看看是否还有要发送的数据,若有则会把这两段数据发送出去
3)接受端不及时接收数据,导致粘包
2、解决办法:关键在于接收方不知道传输的数据包大小,因此我们可以对数据包进行封包和拆包的操作
1)封包:给一段数据加上包头,这样以来数据包久分为包头和包体两个部分内容,包头长度是固定的,并且存储了包体的长度,根据包头长度以及包头中包体长度的变量就可以正确的拆分出一个完整的数据包。
3、Http编程
1、web工作流程
1、客户机通过TCP/IP协议建立服务器到TCP连接
2、客户端向服务器发送HTTP协议请求包,请求服务器里的资源文档
3、服务器向客户机发送HTTP协议应答包,如果请求的资源包含有动态语言的内容,那么服务器会调用动态语言的解释引擎负责处理“动态内容”,并将处理得到的数据返回给客户端
4、客户机与服务器断开,由客户端解释HTML文档,在客户端屏幕上渲染图形结果
2、HTTP协议
称为超文本传输协议,是互联网上应用最为广泛的一种网络协议,它详细的规定了浏览器和万维网服务器之间相互通信的规则,通过因特网传送万维网文档的数据传送协议;HTTP协议通常承载于TCP协议之上
4、WebSocket编程
1、webScoket编程是什么?
1、WebSocket是一种单个TCP连接上进行全双工通信的协议
2、WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据
3、WebSocket API中,浏览器和服务器只需要一次握手,二者之间就可以直接创建持久性连接,并进行简单双向数据传输
4、需要安装第三方包: go get -u -v github.com/gorilla/websocket -> 11之后的版本 使用 go install