golang网络库中tcp的几种报错

63 阅读2分钟
package main

import (
	"fmt"
	"net"
	"time"
)

func Serve() {
	l, err := net.Listen("tcp", ":8888")
	if err != nil {
		fmt.Println("err:", err.Error())
	}
	fmt.Println("listen ok")
	for {
		conn, err := l.Accept()
		fmt.Println("accept new conn")
		if err != nil {
			fmt.Println("accept err:", err.Error())
			return
		}
		go ProcessConn(conn)
	}
}
func ProcessConn(c net.Conn) {
	for {
		c.SetReadDeadline(time.Now().Add(5 * time.Second))
		buf := make([]byte, 1025)
		_, err := c.Read(buf)
		if err != nil {
			fmt.Println("read err:", err.Error())
			return
		}
		fmt.Println("buf:", string(buf))
	}
}

func ProcessConnReDDL(c net.Conn) {
	//设置的DDL超时以后,如果重新设置ddl,则新的ddl会覆盖老的,进行read的时候以新的ddl来判断是否超时
	c.SetReadDeadline(time.Now().Add(1 * time.Second))
	time.Sleep(2 * time.Second)
	for {
		c.SetReadDeadline(time.Now().Add(5 * time.Second))
		buf := make([]byte, 1025)
		_, err := c.Read(buf)
		if err != nil {
			fmt.Println("read err:", err.Error())
			return
		}
		fmt.Println("buf:", string(buf))
	}
}

func ProcessConnDDL(c net.Conn) {
	c.SetReadDeadline(time.Now().Add(1 * time.Second))
	for {
		//设置了read ddl以后,在对应时间内没read到数据,或者没进行read操作,则报错read tcp 127.0.0.1:8888->127.0.0.1:56600: i/o timeout
		c.SetReadDeadline(time.Now().Add(1 * time.Second))
		time.Sleep(3 * time.Second)
		buf := make([]byte, 1025)
		_, err := c.Read(buf)
		if err != nil {
			fmt.Println("read err:", err.Error())
			return
		}
		fmt.Println("buf:", string(buf))
	}
}

//设置完read ddl以后,只要在ddl内读到了,这个设置就失效了,即使后面sleep更长的时间,后面再读也不会报错
func ProcessConnWithDDl(c net.Conn) {
	for {
		c.SetReadDeadline(time.Now().Add(5 * time.Second))
		buf := make([]byte, 1025)
		_, err := c.Read(buf)
		fmt.Println("buf:", string(buf))
		if err != nil {
			fmt.Println("read err:", err.Error())
			return
		}
		time.Sleep(10 * time.Second)
	}
}

//正常关闭,客户端主动四次挥手
func Client() {
	dial, err := net.Dial("tcp", ":8888")
	if err != nil {
		fmt.Println("dial err:", err.Error())
		return
	}
	dial.Write([]byte("xxx"))
	dial.Close()
	fmt.Println("client close")
}

//客户端发送RST
func RSTClient() {
	dial, err := net.Dial("tcp", ":8888")
	if err != nil {
		fmt.Println("RST dial err:", err.Error())
		return
	}
	dial.Write([]byte("xxx"))
	time.Sleep(3 * time.Second)
	dial.(*net.TCPConn).SetLinger(0)
	dial.Close()
	fmt.Println("RST client close")
}

//客户端自己到DDL了,golang里面客户端ddl以后,不会四次挥手,也不会发RST。如果服务端不设置readddl,就永远不知道客户端断开了。TCP的KeepAlive默认是没开的,即使开,也太长了
func DDlClient() {
	dial, err := net.Dial("tcp", ":8888")
	if err != nil {
		fmt.Println("RST dial err:", err.Error())
		return
	}
	dial.Write([]byte("xxx"))
	dial.(*net.TCPConn).SetDeadline(time.Now().Add(1 * time.Second))
	time.Sleep(10 * time.Second)
	//dial.SetDeadline(time.Now().Add(3 * time.Second))
}

//客户端发了数据之后,长时间不动,服务端ddl到了以后,服务端报错read tcp 127.0.0.1:8888->127.0.0.1:56783: i/o timeout。这种情况对服务端来说和上种情况一样,只是客户端这里表现不一样
func SleepClient() {
	dial, err := net.Dial("tcp", ":8888")
	if err != nil {
		fmt.Println("RST dial err:", err.Error())
		return
	}
	dial.Write([]byte("xxx"))
	time.Sleep(30 * time.Second)
}

//每秒写一次
func WriteClient() {
	dial, err := net.Dial("tcp", ":8888")
	if err != nil {
		fmt.Println("RST dial err:", err.Error())
		return
	}
	for {
		dial.Write([]byte("xxx"))
		time.Sleep(3 * time.Second)
	}
}

//1.client向server发请求,如果server没有监听对应的端口,会报错 connection refused,底层server会给client发RST
//2.client写完数据以后正常调用close关闭【四次挥手】,server会读到EOF错误,客户端主动断连,客户端进入timewait
//3.client写完数据以后异常关闭【RST】,server报错如下: read tcp 127.0.0.1:8888->127.0.0.1:51136: read: connection reset by peer
//4.client写完数据以后,客户端不四次挥手,也不发心跳,server到达read ddl以后,报错: read tcp 127.0.0.1:8888->127.0.0.1:52595: i/o timeout
func main() {
	go Serve()
	time.Sleep(3 * time.Second)
	//go Client()
	//time.Sleep(3 * time.Second)
	//fmt.Println("==========RST")
	//go RSTClient()
	//time.Sleep(3 * time.Second)
	fmt.Println("==========DDl")
	go DDlClient()
	//fmt.Println("===========SLEEP")
	//go SleepClient()
	//fmt.Println("======WRITE")
	//go WriteClient()
	time.Sleep(30 * time.Second)
}