之前用到 golang
进行网络编程时,主要就是使用 net/http
和 web
框架 gin
,这些网络库的底层其实也还是用的标准库自带的 net包
,很多是对路由或者其他做封装,而且 golang
本身的长处之一也是网络IO
的处理,这也得益于其底层的 IO模型
,今天我们分享的是基于 TCP server/client
的简单实现,后面将分享相关源码分析。
TCP server
,显然这在网络模型中属于四层模型,指的是最终通过 tcp协议
进行通信,http server
则是再其之上的封装,按照 tcp socket
的连接建立流程,我们可以分为以下:
server:
- bind
- listen
- accept
- read/write
- close
client:
- connect
- write/read
- close
在 golang
中,利用 协程 我们可以便捷地对每个连接开启新的协程进行处理,达到并发处理的效果。
接下来看看相关的 server、client
的简单实现吧。
server
package main
import (
"fmt"
"net"
)
func main() {
lis, err := net.Listen("tcp", ":8000")
if err != nil {
fmt.Println(err)
return
}
fmt.Println("server is up now...")
for {
conn, err := lis.Accept()
if err != nil {
fmt.Println(err)
return
}
clientAddr := conn.RemoteAddr()
fmt.Printf("recv client [%s] connection...\n", clientAddr)
go serve(conn)
}
}
func serve(conn net.Conn) {
defer conn.Close()
buf := make([]byte, 64)
n, _ := conn.Read(buf)
conn.Write([]byte("pong: "))
conn.Write(buf[:n])
}
在代码中,我们首先通过 net.Listen()
创建 server
监听对象,接着通过 loop
对每个客户端连接都新建 goroutine
进行处理。
client
package main
import (
"fmt"
"net"
)
func main() {
conn, err := net.Dial("tcp", ":8000")
if err != nil {
panic(err)
}
conn.Write([]byte("hello world\n"))
i := 0
buf := make([]byte, 128)
for i < 2 {
n, _ := conn.Read(buf)
fmt.Println(string(buf[:n]))
i++
}
}
client
也很简单,只需要通过 net.Dial
即可创建一个连接,然后进行通信。
代码实现简单,但作为 coder,还是要了解更要理解 golang
的网络编程实现原理,比如为何 golang
简单的 server
就可以实现 高并发
,内部是怎么实现的呢,后面我们将继续分享。