Home >Backend Development >Golang >An article to help you understand the basics of Go language network programming
What we have learnedTCP
and UDP
are collectively referred to as Socker
programming, also called Socket Programming.
Multiple machinesTo realize mutual communication, is actually a very complicated process. The bottom layer lays the network cable from , network cable interface,switch,router, at ProvisionsVarious protocols.
Go to the application layerQQ
,WeChat
, etc. software.
If there is no set of standards, and each programmer has to implement it by himself every time he uses it, it may not be as simple as losing his hair!
After havingSocker
, Socker
will hide various tedious underlying operations before the application layer. We may only need Socker.TCP
realizes the communication of TCP
protocol.
TCP is a stable and reliable long connection,
Since communication is involved, there must be two terminals, at least one is the server, and the other is Client, just like our Taobao, every time we open Taobao, we have to link to it. Of course, Taobao is not directly TCP
.
Implement the server in Go, and concurrency on the server is very simple. You only need to allow one protocol for each connection. Just process it!
Code
package main import ( "bufio" "fmt" "net" ) func process(conn net.Conn) { defer conn.Close() for { reader := bufio.NewReader(conn) buf := make([]byte, 128) n, err := reader.Read(buf) if err != nil { fmt.Println("数据读取失败", err) return } recvStr := string(buf[:n]) fmt.Println("客户端发送过来的值:", recvStr) } } func main() { lister, err := net.Listen("tcp", "0.0.0.0:8008") if err != nil { fmt.Println("连接失败", err) } for { fmt.Println("等待建立连接,此时会阻塞住") conn, err := lister.Accept() //等待建立连接 fmt.Println("连接建立成功,继续") if err != nil { fmt.Println("建立连接失败", err) //继续监听下次链接 continue } go process(conn) } }
Customer The end is very simple. Relatively speaking, there is no need for concurrency, only connection is required.
代码
package main import ( "bufio" "fmt" "net" "os" ) //客户端 func main() { conn, err := net.Dial("tcp", "192.168.10.148:8008") if err != nil { fmt.Println("连接服务器失败",err) } defer conn.Close() inputReader:=bufio.NewReader(os.Stdin) for{ fmt.Println(":") input,_:=inputReader.ReadString('\n') _, err = conn.Write([]byte(input)) if err != nil { fmt.Println("发送成功") } } }
就这样,我们实现了服务端并发的处理所有客户端的请求。
我们先看一下什么是粘包。
package main import ( "bufio" "fmt" "io" "net" ) func process(conn net.Conn) { defer conn.Close() reader := bufio.NewReader(conn) buf := make([]byte, 1024) for { n, err := reader.Read(buf) //读完了 if err == io.EOF { fmt.Println("读完了") break } //读错了 if err != nil { fmt.Println("数据读取失败", err) return } recvStr := string(buf[:n]) fmt.Println("客户端发送过来的值:", recvStr) } } func main() { lister, err := net.Listen("tcp", "0.0.0.0:8008") if err != nil { fmt.Println("连接失败", err) return } defer lister.Close() for { fmt.Println("等待建立连接,此时会阻塞住") conn, err := lister.Accept() //等待建立连接 fmt.Println("连接建立成功,继续") if err != nil { fmt.Println("建立连接失败", err) //继续监听下次链接 continue } go process(conn) } }
package main import ( "fmt" "net" ) //客户端 func main() { conn, err := net.Dial("tcp", "192.168.10.148:8008") if err != nil { fmt.Println("连接服务器失败", err) } defer conn.Close() for i := 0; i < 10; i++ { sendStr := "hello world ads asdf asd fads fadsf ads ads asd asd ads " conn.Write([]byte(sendStr)) time.Sleep(time.Second) } }
注意:18行代码睡眠了1s
If I comment the 18th line of code
It’s all in one line, what? What's happening? Shouldn't it be the same as before? ? ?
Every time a value is sent, it is received over there. How come this is all in one piece! ! !
The main reason is because we are the application layerSoftware is software running on the operating system. When we send a data to the server, it is Call the related interface of the operating system to send it. The operating system then goes through various complex operations and sends it to the other machine.
But the operating system has a buffer for sending data. By default, if the buffer has a size and the buffer is not full, the data will not be sent, so the above client is When sending data, the system's buffer was not full, and it was kept in the operating system's buffer. Finally, it was found that there was no data, so it was sent to the server all at once
But why does sleep(1)
work again? This is because the buffer is used by more than one program, and 1s is enough Other programs fill up the buffer and then send their own data. This is why the first operation is fine, but the second operation is problematic, because the second time is all filled up by our client
We will solve Encapsulate the function of the encapsulation package
socker_sitck/stick.go
package socker_stick import ( "bufio" "bytes" "encoding/binary" "fmt" ) //Encode 将消息编码 func Encode(message string) ([]byte, error) { length := int32(len(message)) var pkg = new(bytes.Buffer) //写入消息头 err := binary.Write(pkg, binary.LittleEndian, length) if err != nil { fmt.Println("写入消息头失败", err) return nil, err } //写入消息实体 err = binary.Write(pkg, binary.LittleEndian, []byte(message)) if err != nil { fmt.Println("写入消息实体失败", err) return nil, err } return pkg.Bytes(), nil } //Decode解码消息 func Decode(reader *bufio.Reader) (string, error) { //读取信息长度 lengthByte, _ := reader.Peek(4) lengthBuff := bytes.NewBuffer(lengthByte) var length int32 err := binary.Read(lengthBuff, binary.LittleEndian, &length) if err != nil { return "", err } //BuffRead 返回缓冲区现有的可读的字节数 if int32(reader.Buffered()) < length+4 { return "", err } pack := make([]byte, int(4+length)) _, err = reader.Read(pack) if err != nil { return "", err } return string(pack[4:]), nil }
package main import ( "a3_course/socker_stick" "bufio" "fmt" "io" "net" ) func process(conn net.Conn) { defer conn.Close() reader := bufio.NewReader(conn) for { msg, err := socker_stick.Decode(reader) //读完了 if err == io.EOF { fmt.Println("读完了") break } //读错了 if err != nil { fmt.Println("数据读取失败", err) return } fmt.Println("客户端发送过来的值:", msg) } } func main() { lister, err := net.Listen("tcp", "0.0.0.0:8008") if err != nil { fmt.Println("连接失败", err) return } defer lister.Close() for { fmt.Println("等待建立连接,此时会阻塞住") conn, err := lister.Accept() //等待建立连接 fmt.Println("连接建立成功,继续") if err != nil { fmt.Println("建立连接失败", err) //继续监听下次链接 continue } go process(conn) } }
package main import ( "a3_course/socker_stick" "fmt" "net" ) //客户端 func main() { conn, err := net.Dial("tcp", "192.168.10.148:8008") if err != nil { fmt.Println("连接服务器失败", err) } defer conn.Close() for i := 0; i < 10; i++ { sendStr := "hello world ads asdf asd fads fadsf ads ads asd asd ads " data, err := socker_stick.Encode(sendStr) if err != nil { fmt.Println("编码失败",err) return } conn.Write(data) //time.Sleep(time.Second) } }
这次真的不管执行几次,都是这样的结果
对了,只有TCP
才有粘包
UDP
是一个无连接协议,客户端不会在乎服务端有没有问题,客户端只管发,通常用于实时性比较高的领域
例如直播行业
package main import ( "fmt" "net" ) func main() { listen, err := net.ListenUDP("udp", &net.UDPAddr{ IP: net.IPv4(0, 0, 0, 0), Port: 8009, }) if err != nil { panic(fmt.Sprintf("udp启动失败,err:%v", err)) } defer listen.Close() for{ var data = make([]byte,1024) n, addr, err := listen.ReadFromUDP(data) if err != nil { panic(fmt.Sprintf("读取数据失败,err:%v", err)) } fmt.Println(string(data[:n]),addr,n) } }
package main import ( "fmt" "net" ) func main() { socker, err := net.DialUDP("udp", nil, &net.UDPAddr{ IP: net.IPv4(0, 0, 0, 0), Port: 8009, }) if err != nil { panic(fmt.Sprintf("连接服务器失败,err:%v", err)) } defer socker.Close() sendStr:="你好呀" _, err = socker.Write([]byte(sendStr)) if err != nil { panic(fmt.Sprintf("数据发送失败,err:%v", err)) } }
本次章节我们讲述了什么是TCP,什么是UDP。
并且编写了代码如何实现TCP服务端,TCP客户端,UDP服务端,UDP客户端。
讲述了为什么会出现粘包,该怎么解决粘包。
The above is the detailed content of An article to help you understand the basics of Go language network programming. For more information, please follow other related articles on the PHP Chinese website!