使用 Golang 构建一个简单的 TCP 服务
Golang 原生的协程使其在处理高并发方面很有优势,下面使用 Go 来简单实现个支持并发的 TCP 服务器
首先实现客户端
首先定义针对客户端的结构体,包含连接、地址和一个用来接收停止信号的 chan
type client struct {
connection *net.Conn
addr *net.TCPAddr
stopChan chan struct{}
}
然后为其定义数据处理方法,handler
func (c *client) handler() {
defer c.connection.Close()
//根据连接初始化 reader
reader := bufio.NewReader(c.connection)
//阻塞,读取数据
for {
buf := make([]byte, 1024)
//n 为读取到的数据长度
n, err := reader.Read(buf)
if err != nil {
if err == io.EOF {
//如果是 EOF 代表已经失去客户端连接,在这里直接释放这个 client
close(c.stopChan)
break
}
golog.Errorf("read error: %v", err)
continue
}
bytes := buf[:n]
golog.Infof("recv: %s", bytes)
//直接将发送过来的数据回写
_, err = c.connection.Write(bytes)
if err != nil {
golog.Errorf("write error: %v", err)
continue
}
}
}
完整代码如下
package main
import (
"bufio"
"io"
"net"
"github.com/kataras/golog"
)
type client struct {
connection *net.TCPConn
addr *net.TCPAddr
stopChan chan struct{}
}
func (c *client) handler() {
defer c.connection.Close()
//根据连接初始化 reader
reader := bufio.NewReader(c.connection)
//阻塞,读取数据
for {
buf := make([]byte, 1024)
//n 为读取到的数据长度
n, err := reader.Read(buf)
if err != nil {
if err == io.EOF {
//如果是 EOF 代表连接断开,在这里直接释放这个 client
close(c.stopChan)
break
}
golog.Errorf("read error: %v", err)
continue
}
bytes := buf[:n]
golog.Infof("recv: %s", bytes)
//直接将发送过来的数据回写
_, err = c.connection.Write(bytes)
if err != nil {
golog.Errorf("write error: %v", err)
continue
}
}
}
func main() {
//建立 TCP 连接
addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:8000")
if err != nil {
golog.Fatalf("resolve addr error: %v", err)
}
conn, err := net.DialTCP("tcp", nil, addr)
if err != nil {
golog.Fatalf("dial tcp error: %v", err)
}
client := &client{
connection: conn,
addr: addr,
stopChan: make(chan struct{}),
}
//开启协程处理
go client.handler()
//开启 channel 等待,当 chan 被关闭时退出
<-client.stopChan
}
实现服务端
封装服务端结构体,包含 listener 和 addr
type server struct {
listener *net.TCPListener
addr *net.TCPAddr
}
定义连接处理方法
//处理方法
func handle(conn net.Conn) {
defer conn.Close()
golog.Infof("new client: %s", conn.RemoteAddr().String())
reader := bufio.NewReader(conn)
for {
buf := make([]byte, 1024)
n, err := reader.Read(buf)
if err != nil {
if err == io.EOF {
golog.Errorf("client closed: %s", conn.RemoteAddr().String())
return
}
continue
}
//回写
conn.Write(buf[:n])
}
}
建立连接,完整代码如下
package main
import (
"bufio"
"io"
"net"
"github.com/kataras/golog"
)
type server struct {
listener *net.TCPListener
addr *net.TCPAddr
}
//处理方法
func handle(conn net.Conn) {
//此处可定义状态机,处理连接的不同状态和数据包结构
defer conn.Close()
golog.Infof("new client: %s", conn.RemoteAddr().String())
reader := bufio.NewReader(conn)
for {
buf := make([]byte, 1024)
n, err := reader.Read(buf)
if err != nil {
if err == io.EOF {
golog.Errorf("client closed: %s", conn.RemoteAddr().String())
return
}
continue
}
//回写
conn.Write(buf[:n])
}
}
func main() {
//建立连接
addr, err := net.ResolveTCPAddr("tcp", ":8000")
if err != nil {
golog.Fatalf("resolve addr error: %v", err)
}
listener, err := net.ListenTCP("tcp", addr)
if err != nil {
golog.Fatalf("listen error: %v", err)
}
defer listener.Close()
//构造 server 对象
s := &server{
listener: listener,
addr: addr,
}
for {
conn, err := s.listener.Accept()
if err != nil {
continue
}
//进入协程处理该连接
go handle(conn)
}
}