Giter Site home page Giter Site logo

Comments (8)

fwhezfwhez avatar fwhezfwhez commented on July 30, 2024

Use it like:

srv := tcpx.NewTcpX(nil)
srv.BeforeExit(job1, job2, job3 ...)
srv.ListenAndServe("tcp", ":8080")

Here is part of source code:

func (tcpx TcpX) BeforeExit(f ...func()) {
	go func() {
		defer func() {
			if e := recover(); e != nil {
				fmt.Println(fmt.Sprintf("panic from %v", e))
			}
		}()
		ch := make(chan os.Signal)
		signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT)
		fmt.Println("receive signal:", <-ch)
		fmt.Println("prepare to stop server")
		for _, handler := range f {
			handler()
		}
		os.Exit(0)
	}()
}

It will catch syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT these signal and do all jobs you design as 'func()'.

Does this fit your requirement?

from tcpx.

nh-live avatar nh-live commented on July 30, 2024

I hope the listener and connection normal close, not os.exit(0)

from tcpx.

fwhezfwhez avatar fwhezfwhez commented on July 30, 2024

It'hard.Because there is not a specific pause point for ListenAndServe() to insert a context whatever it's about tcp, udp, or kcp.It means you can't run server in another goroutine and control it by the context.

Mayby you can design a middleware and using a value to control server' context Abort, it will look like:

var access bool

func main()
    srv := tcpx.NewTcpX(nil)
    srv.AddHandler(1, setAccess)
    srv.Use("server-access",Access)
    // srv.AddHandler()
    srv.ListenAndServe("tcp", ":8080")
}

func Access(c *tcpx.Context){
    if !access {
        c.Abort()
        return
    }
}

func setAccess(c *tcpx.Context) {
      access = !access
}

But I shall notice you that if you're using srv.OnMessage instead of AddHandler, middleware by Use() will not make sense. If not using srv.OnMessage, you can just ignore these.

from tcpx.

nh-live avatar nh-live commented on July 30, 2024
  1. close conn maybe use ClientPool:
type ClientPool struct {
	Clients map[string]*Context
	m       *sync.RWMutex
}

func (cp *ClientPool) Close()  {
	cp.m.Lock()
	defer cp.m.Unlock()
	for _,c := range cp.Clients{
		c.CloseConn()
	}
}
  1. close listener accept maybe like this:
type TcpX struct {
	listener *net.TCPListener
       pool        *ClientPool
	...
}

func (this *TcpX) Close()  {
        if this.pool != nil{
               this.pool.Close()
        }
	if this.listener != nil{
		this.listener.Close()
	}
}

test example:

listener,err := net.Listen("tcp","0.0.0.0:8888")
	if err != nil{
		fmt.Println("listen failed, ",err.Error())
	}
	go func() {
		for {
			_,err := listener.Accept()
			if err != nil{
				fmt.Println("accept failed, " + err.Error())
				return
			}
		}
	}()

	time.Sleep(5 * time.Second)

	err = listener.Close()
	if err != nil{
		fmt.Println("listener close failed, ",err.Error())
	}

from tcpx.

fwhezfwhez avatar fwhezfwhez commented on July 30, 2024

I seldom meet this situation. When I want to realize that stoping part of server makes no effects to another part, I ussually consider it in these layers:

  • Tear apart tcp server and http server into two progresses.Each process can restart/close as I wish and no effect to another. If there is nessasary interactions, I will start a grpc server in tcp part as grpc server side and http part as grpc client side.
  • If http part and tcp part share too many codes and I don't want to use grpc. I will use the same project code to generate two servers, like:
var serverType string
var port string
func main(){
    flag.StringVal(&serverType, "server_type", "http,tcp", "go run main.go -server_type tcp")
    flag.StringVal(&serverType, "p", ":8080", "go run main.go -p :8080")

    flag.Parse()

    if strings.Contains(serverType, "tcp") {
           go tcpServer(port)
    }
    if strings.Contains(serverType, "http") {
           go httpServer(port)
    }
}

go run main.go -server_type tcp -p 8080
go run main.go -server_type http -p 8081

If you insist on this requirement, I can realize one. But I will not design it as you like via close listener, close pool connection.
Why?
Because listener can Close but cannot Restart, as long as you make it graceful to stop tcp server, you can no longer graceful restart it.You still have to restart the whole process.

I will design it as I've said,

  • add a mux handler to stop server access
  • close all connection but listener still accepts connection, connection will stop by access handler

or I can ignore step 2, I even don't have to close all connection as long as you set heartbeat-mode on.
Because all server handlers deny requests, heartbeat will also deny , after interval receiving no heartbeat pack, connection auto-close.

from tcpx.

nh-live avatar nh-live commented on July 30, 2024

Just shut down the TCP service, simple things don't get complicated, don't grpc, don't http, why can't listen restart?

`type TcpX struct {
listener *net.TCPListener
pool *ClientPool
...
}
func (this *TcpX) Start() (err error) {
this.listener,err = net.ListenTCP("tcp","0.0.0.0:8888")
...
}

func (this *TcpX) Close() {
if this.listener != nil{
this.listener.Close()
this.listener = nil
}
}
func (this *TcpX) Restart() {
this.Close()
this.Start()
}`

Most TCP/HTTP services support shutting down services, such as xtcp, gotcp, beego and so on. Why don't you support it?

from tcpx.

fwhezfwhez avatar fwhezfwhez commented on July 30, 2024

Done.
Example refers to https://github.com/fwhezfwhez/tcpx/tree/master/examples/modules/graceful.

Have fun!

from tcpx.

nh-live avatar nh-live commented on July 30, 2024

tks.

from tcpx.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.