golang编写tcp服务
使用golang编写一个tcp服务,包含server和client。
server
golang中提供了net包,我们可以用它来编写一个tcp服务。
可以通过net.Listen方法来创建一个地址的监听,返回一个listener。
listener, err := net.Listen("tcp", "127.0.0.1:9000")
再循环调用listener的Accept()方法,这个方法会等待并获取一个客户端的连接conn,是一个net.Conn结构体。
for {
conn, err := listener.Accept()
}
然后启动一个goroutine来处理获取到的连接conn,一般是使用一个for循环来不停读取数据。对于conn我们将其当作一个数据流来对他进行处理即可,循环从其中读取数据并根据’\n’来进行分割。
reader := bufio.NewReader(conn)
for {
line, err := reader.ReadString('\n')
}
并且可以使用conn.Write方法来对客户端连接进行数据返回。
conn.Write([]byte(line))
完整代码
package main
import (
"bufio"
"fmt"
"log"
"net"
"runtime"
"strings"
"sync"
)
func main() {
tcpServer := &TCPServer{address: "127.0.0.1:9000"}
err := tcpServer.Run()
if err != nil {
panic(err)
}
select {}
}
type TCPServer struct {
address string
wg sync.WaitGroup
}
func (t *TCPServer) Run() error {
listener, err := net.Listen("tcp", t.address)
if err != nil {
return err
}
for {
conn, err := listener.Accept()
if err != nil {
if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
// 如果是超时等临时错误,先暂停当前goruntine交出调度,时间片轮转到后再恢复后续操作
runtime.Gosched()
continue
}
if !strings.Contains(err.Error(), "use of closed network connection") {
return fmt.Errorf("listener.Accept() error - %s", err)
}
break
}
t.wg.Add(1)
go func() {
handle(conn)
t.wg.Done()
}()
}
t.wg.Wait()
return nil
}
func handle(conn net.Conn) {
reader := bufio.NewReader(conn)
for {
line, err := reader.ReadString('\n')
if err != nil {
log.Println(err)
return
}
log.Println("receive: " + line)
conn.Write([]byte(line))
}
}
client
客户端可以使用 dialer.Dial方法来对server进行连接,方法的返回值也是一个net.Conn结构体,具体使用与server没有区别。
conn, err := dialer.Dial("tcp", "127.0.0.1:9000")
我们可以给dialer的Timeout字段赋值来设置请求的超时时间,默认是没有超时。
完整代码
package main
import (
"fmt"
"net"
"time"
)
func main() {
dialer := &net.Dialer{
Timeout: time.Second * 2,
}
conn, err := dialer.Dial("tcp", "127.0.0.1:9000")
if err != nil {
panic(err)
}
for i := 0; i < 10; i++ {
conn.Write([]byte(fmt.Sprintf("%d\n", i)))
}
conn.Close()
}