Git Product home page Git Product logo

panjf2000 / gnet Goto Github PK

View Code? Open in Web Editor NEW
9.1K 164.0 998.0 33.89 MB

🚀 gnet is a high-performance, lightweight, non-blocking, event-driven networking framework written in pure Go./ gnet 是一个高性能、轻量级、非阻塞的事件驱动 Go 网络框架。

Home Page: https://gnet.host

License: Apache License 2.0

Go 100.00%
event-driven event-loop networking non-blocking epoll kqueue go golang reactor tcp

gnet's Introduction

Hi there, I'm Andy Pan 🎉

The best way to reach out to me is by email: [email protected]

I'm a programmer / blogger / traveler / photographer, ...

I have a keen interest in Go, Rust, Cloud Native, Kubernetes, Docker, Network (Gnet/Netty/libuv/libevent/gRPC/Thrift/HAProxy/Nginx/Envoy/Traefik, etc.), Service Mesh (Istio/Linkerd/Consul/Maesh), NoSQL (Redis/MongoDB/Elasticsearch/Neo4j/Dgraph/ArangoDB, etc.), Vector Databases (Milvus/Qdrant, etc.), [AI-tech](ChatGPT/Stable Diffusion/Midjourney, etc.)

Please visit Golang China Contributor Club to learn more about my work.

gnet's People

Contributors

0-haha avatar 0xflotus avatar callthingsoff avatar cscps avatar daynobug avatar dependabot[bot] avatar drinktee avatar eruca avatar firedtoad avatar fufuok avatar gxke avatar hellodudu avatar henryaj avatar hihaha avatar jdamick avatar jemmyh avatar jinxing3114 avatar leki75 avatar leslie-fei avatar panjf2000 avatar polyzy avatar rdmrcv avatar ricardo-evans avatar shoothzj avatar theonelee avatar verthandii avatar wathenjiang avatar zhongweikang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gnet's Issues

win system go module

github.com/panjf2000/gnet

D:\GoWorks\pkg\mod\github.com\panjf2000\[email protected]\gnet.go:129:4: undefined: sniffError
D:\GoWorks\pkg\mod\github.com\panjf2000\[email protected]\gnet.go:159:14: too many arguments in call to serve
have (Events, []*listener, bool)
want (Events, []*listener)

React接口优化

我注意到,在调用React的前后,有判断action与goto进行loop循环调用,我们大家都知道,尽量避免goto调用,还有这里的action判断逻辑有点混乱不直观,让人难以理解什么时候goto

loopReact:
	out, action := lp.eventHandler.React(c)
	if out != nil {
		if frame, err := lp.codec.Encode(c, out); err == nil {
			c.write(frame)
		}
	}
	switch c.action == action {
	case true:

		goto loopReact
	case false:
		c.action = action
	}

深入阅读代码之后,发现这里的loop是为了循环调用ReadFrame(),来实现每次React只处理一帧有效数据,但是React里面还要二次判断是否为有效帧,实为浪费性能。
因此觉得优化此处代码取消goto,有以下两种方案:
Plan A: 在业务层内实现for循环遍历每一帧数据

func (hs *httpServer) React(c gnet.Conn) (out []byte, action gnet.Action) {
	for _, data := range c.ReadFrame() {
		...
	}
}

Plan B: 在React上层,for循环分好data数据
image

通过此样修改之后,可以取消所有关于 c.action = Skip 的判断与代码,Plan B可以收缩减少gnet暴露的接口,增加代码性能与可读性,减少React的代码量。

非阻塞模式

老哥,最新tag版本
好像没有暴露异步处理的接口啊。

Auto-scaling Ring Buffer - also downscaling automatical?

First of all: many thanks for this library!

What is your question about gnet?
I have a question about the ring buffer: Does the ring buffer also downscaling automatically? I didn't find anything in the code, but maybe I'm blind.

I have 40k open websocket sessions, if I now reduce them to 20k, the memory consumption of the ring buffer remains on the same level, even after 30 min.

Thank you in advance for your answer.

Windows support?

github.com/panjf2000/gnet

....\go\pkg\mod\github.com\panjf2000\[email protected]\gnet.go:129:4: undefined: sniffError
....\go\pkg\mod\github.com\panjf2000\[email protected]\gnet.go:159:14: too many arguments in call to serve
have (Events, []*listener, bool)
want (Events, []*listener)

Shutting down the listener.

Hello,

I would like to request if it is possible for lifecycle methods to be exposed to synchronously/asynchronously shutdown the listener, and to have another method/channel exposed to block the current goroutine until the listener has completed.

I'm currently doing a hack for it using the Ticker of the event loop to periodically see if an atomic integer has been set to a certain value, and if so, shut down the event loop.

Too many connections opened on OS

2019/12/21 14:21:41 close tcp:[::]:9761->: file already closed
2019/12/21 14:21:41 close tcp [::]:9761: use of closed network connection
2019/12/21 14:21:41

UBUNTU上开启服务,然后WIN上,不断建立连接发送关闭,服务端出现上面问题,不知道如何排查,在EPOLL里面打了很多日志,但是都没显示,是不是ACCEPT这里?

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

System Info (please complete the following information):

  • OS (e.g. Ubuntu 18.04):
  • Go version (e.g. Go 1.13):
  • gnet version (e.g. v1.0.0):

Additional context
Add any other context about the problem here.

HTTP 压测问题

Describe the bug

在macbook 下使用ab测试官方给出的http例子,全部超时,浏览器可正常访问,不管是否带-k,请问你是用什么工具测试的,怎样设置超时

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

System Info (please complete the following information):

  • OS (e.g. Ubuntu 18.04):
  • Go version (e.g. Go 1.13):
  • gnet version (e.g. v1.0.0):

Additional context
Add any other context about the problem here.

UDP RemoteAddr() returns always (wrong) IPv6

Describe the bug
gnet.Conn.RemoteAddr() returns always IPv6 for UDP.
E.g. [::7f00:1]:52815 instead of 127.0.0.1:52815

To Reproduce

func (this *Server) React(c gnet.Conn) (out []byte, action gnet.Action) {
        data := c.Read()
        log.Debugf("DATA from %v to %v: %v", c.RemoteAddr(), c.LocalAddr(), data)
        c.ResetBuffer()
        return
}

func (this *Server) listen() error {                                                                                                                                                              
        listenAddr := fmt.Sprintf("udp://%s", this.cfg.Bind)                                                                                                                                      
        err := gnet.Serve(this, listenAddr, gnet.WithMulticore(true), gnet.WithReusePort(true))
        if err != nil {                                                                                                                                                                                   return fmt.Errorf("Failed to create listening udp socket: %v", err)
        }

        return nil
}   

Expected behavior
Correct RemoteAddr

System Info (please complete the following information):

  • OS (e.g. Linux): Linux
  • Go Version (e.g. Go 1.13): go1.12.10 linux/amd64
  • gnet Version (e.g. v1.0.0-beta.3): [email protected]

Additional context

in eventloop.go SockaddrToUDPAddr gets always called with sa6 = unix.SockaddrInet6

func (lp *loop) loopUDPIn(fd int) error {
        c := &conn{
                fd:            fd,
                localAddr:     lp.svr.ln.lnaddr,
                remoteAddr:    netpoll.SockaddrToUDPAddr(&sa6),
                inboundBuffer: lp.svr.bytesPool.Get().(*ringbuffer.RingBuffer),
        }
}

in netpoll/socktoaddr.go

func SockaddrToUDPAddr(sa unix.Sockaddr) *net.UDPAddr {
        case *unix.SockaddrInet6:
                return &net.UDPAddr{IP: ip, Port: sa.Port, Zone: zone}
        }
}

So you always get an SockaddrInet converted to SockaddrInet6 for UDP.

关于React中阻塞逻辑的疑问

在Readme中给出的样例代码中,带有阻塞逻辑的部分都有一个

data := append([]byte{}, frame...)

请问这是不是意味着如果frame所带的数据如果没有被及时处理,可能会被回收或者复用覆盖?

另外如果处理的速度跟不上网络的速度,上述的这种方法似乎会导致内存占用不断上升,有没有什么办法可以限制网络的吞吐量?

Error with disruptor when using `go get -u`

To reproduce:

go get -u github.com/panjf2000/gnet

Result:

go: finding github.com/panjf2000/gnet v0.1.3
go: downloading github.com/panjf2000/gnet v0.1.3
go: extracting github.com/panjf2000/gnet v0.1.3
go: downloading golang.org/x/sys v0.0.0-20190412213103-97732733099d
go: downloading github.com/libp2p/go-reuseport v0.0.1
go: downloading github.com/smartystreets-prototypes/go-disruptor v0.0.0-20180723194425-e0f8f9247cc2
go: downloading github.com/gobwas/pool v0.2.0
go: extracting github.com/libp2p/go-reuseport v0.0.1
go: extracting github.com/gobwas/pool v0.2.0
go: extracting github.com/smartystreets-prototypes/go-disruptor v0.0.0-20180723194425-e0f8f9247cc2
go: extracting golang.org/x/sys v0.0.0-20190412213103-97732733099d
go: finding golang.org/x/sys latest
go: finding github.com/gobwas/pool v0.2.0
go: finding github.com/libp2p/go-reuseport v0.0.1
go: finding github.com/smartystreets-prototypes/go-disruptor latest
go: downloading golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab
go: downloading github.com/smartystreets-prototypes/go-disruptor v0.0.0-20191016010027-c1aa45f7f564
go: extracting github.com/smartystreets-prototypes/go-disruptor v0.0.0-20191016010027-c1aa45f7f564
go: extracting golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab
# github.com/panjf2000/gnet
../../../../go/pkg/mod/github.com/panjf2000/[email protected]/reactor.go:77:16: undefined: disruptor.Configure
../../../../go/pkg/mod/github.com/panjf2000/[email protected]/reactor.go:83:14: undefined: disruptor.InitialSequenceValue

关于异步任务处理的疑问

感谢潘少的项目 ∩^∩
有个疑问啊,你在文中提到如果有大量的goroutine会给go的调度带来压力,我印象中go官方提到过不会带来压力。是我理解错了吗?谢谢。

type Poller struct {
	fd            int    // epoll fd
	wfd           int    // wake fd
	wfdBuf        []byte // wfd buffer to read packet
	asyncJobQueue internal.AsyncJobQueue
}

另外能大概解析一下上面 wfd 具体作用吗?谢谢。

在处理EpollWait返回事件有以下代码,请问wfd有什么作用呢?

	if fd := int(el.events[i].Fd); fd != p.wfd { // 为什么要做这个判断呢?
		if err = callback(fd, el.events[i].Events); err != nil {
			return
		}
	} else {
		wakenUp = true
		fmt.Println("wfdbuf: ", p.wfdBuf)
		_, _ = unix.Read(p.wfd, p.wfdBuf)
	}

-------------分割线 补上

了解了eventfd的用法,对应上面的wfd,为了让异步执行的任务也统一通过epollWait来处理,但有两个疑问:
1,为什么要统一通过epollWait来统一调度呢,不可以想写数据的时候直接就往connfd中write呢?这样会有什么问题呢?谢谢。
2,

func (q *AsyncJobQueue) ForEach() (err error) {
	q.mu.Lock()
	jobs := q.jobs
	q.jobs = nil
	q.mu.Unlock()
	for i := range jobs {
		if err = jobs[i](); err != nil {
			return err
		}
	}
	return
}

ForEach 这个函数会遍历所有的jobs并执行,那么只要一个jobs写入的eventfd被调度了,那么就会执行所有的jobs,而且定时器也会定时触发这个调度。这样感觉会导致一些异步任务的执行并不是由这个任务本身去触发的,而是由其他的任务触发的,而且还会有多次write(eventfd)后,多次read(eventfd)没必要的情况(因为jobs一次就已经全部执行完了)。 请问是我哪里理解错了吗?谢谢。

windows编译失败

Describe the bug
编译失败, 显示
C:\Users\Administrator\go\pkg\mod\github.com\panjf2000\[email protected]\gnet.go:129:4: undefined: sniffError
C:\Users\Administrator\go\pkg\mod\github.com\panjf2000\[email protected]\gnet.go:159:14: too many arguments in call to serve
have (Events, []*listener, bool)
want (Events, []*listener)

To Reproduce
Steps to reproduce the behavior:
执行的examples下的echo-server

Expected behavior
编译成功

Screenshots
If applicable, add screenshots to help explain your problem.

System Info (please complete the following information):

  • OS (e.g. Ubuntu 18.04): win10
  • Go version (e.g. Go 1.13): go 1.13
  • gnet version (e.g. v1.0.0): v0.1.3

Additional context
Add any other context about the problem here.

AsyncWrite阻塞 event-loop 线程

你好,我实现了一个websocket服务器,客户端是异步收发信息,由于代码问题,客户端读取消息速度非常慢,发送消息很迅速。服务器每处理1个ws消息,就会回复一条十几字节的数据。
我的测试流程大概如下:
1.客户端打开一个tcp连接到gnet,预处理完毕后,连续发送1000次30字节的数据
2.服务器大概收到4次React,最后一次读取到1W字节(其实后面还有1W字节数据)
3.没有goroutine,顺序从1w字节里面一条一条消息解析,处理,并回复数据。
4.大概处理到200-300个消息的时候,整个server被阻塞,无法处理任何请求
打开pprof的goroutine查看,发现是gnet.(*conn).AsyncWrite->syscall.Syscall阻塞,代码如下

0x4ce654 syscall.Syscall+0x4 /data/server/go/src/syscall/asm_linux_amd64.s:18

0x9d3e99 golang.org/x/sys/unix.write+0x59 /mnt/e/sg_svr/src/golang.org/x/sys/unix/zsyscall_linux_amd64.go:1569

0x9d57d8 golang.org/x/sys/unix.Write+0x78 /mnt/e/sg_svr/src/golang.org/x/sys/unix/syscall_unix.go:173

0x9d579f github.com/panjf2000/gnet/netpoll.(*Poller).Trigger+0x3f /mnt/e/sg_svr/src/github.com/panjf2000/gnet/netpoll/epoll.go:58

0x9d795b github.com/panjf2000/gnet.(*conn).AsyncWrite+0x8b /mnt/e/sg_svr/src/github.com/panjf2000/gnet/connection.go:96

Example using ReadN

I'm trying to create a tcp protocol for my game using gnet. I put it under stress and received an incomplete message. The http example comes pretty close to my use case and does handle incomplete messages, but it's pretty complicated.

There is a large comment about the function ReadN that describes what it might be used for but not how. When should I use Read and when should I use ReadN? An example using ReadN as intended would help a great deal.

gnet 和 gev 的压测结果不一致问题

gev,gnet都很优秀,感谢你们开源付出。但是目前看你两出的基准测试结果还是有差异的,这样让使用者比较困惑,建议你两能否商量一下拿出一个统一的基准测试。

大量连接断开nil错误

Steps to reproduce the behavior:

  1. 监听tcp端口,使用多核,使用端口重用
  2. 客户端打开1W个连接,并且等到1W个连接,连接成功
  3. 关掉客户端
  4. 服务器抛出一个nil错误,并且退出

image

System Info (please complete the following information):

  • OS (e.g. Linux): ubuntu 19.10
  • Go Version (e.g. Go 1.13): 1.13.3
  • gnet Version (e.g. v1.0.0-beta.3): v1.0.0-beta7

Additional context
客户端协议使用 github.com/gorilla/websocket 实现,服务端协议轻微修改

支持内置Reactors + goroutine pool网络模型?

Is your feature request related to a problem? Please describe.
No

Describe the solution you'd like
我看到gnet现在是通过引入第三方goroutine pool,让业务使用者自己提交耗时任务到pool,从而实现Reactors + goroutine pool,我在想能不能直接内置这个网络模型,直接把整个React方法异步化,提交到goroutine pool里执行,这样业务方就不需要自己管理耗时任务了。

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

About setting up a connections pool

func (svr *server) acceptNewConnection(fd int) error {
	nfd, sa, err := unix.Accept(fd)
	if err != nil {
		if err == unix.EAGAIN {
			return nil
		}
		return err
	}
	if err := unix.SetNonblock(nfd, true); err != nil {
		return err
	}
	lp := svr.subLoopGroup.next()
       //可以从pool里面取出来,重置一些参数就行,不然在高并发下对象和ringbuffer的消耗还是挺大的
	c := &conn{
		fd:             nfd,
		sa:             sa,
		loop:           lp,
		inboundBuffer:  ringbuffer.New(socketRingBufferSize),
		outboundBuffer: ringbuffer.New(socketRingBufferSize),
	}
	_ = lp.loopOpen(c)
	_ = lp.poller.Trigger(func() (err error) {
		if err = lp.poller.AddRead(nfd); err == nil {
			lp.connections[nfd] = c
			return
		}
		return
	})
	return nil
}

AsyncWrite是在什么时候发送的呢?

您好,根据您readme里的demo,在React里调用

_ = es.pool.Submit(func() {
	fmt.Println("Async Writing...")
	c.AsyncWrite([]byte("hello world"))
})

在client并没有及时收到数据,而是在server退出的时候才收到数据,是我使用的姿势不对吗?

何时加个主动close?

RT,还有建议加个GID等工具,使用协程本地变量,自动判断是EVENTLOOP的协程还是其他协程,这样写和关闭连接可以只用一个接口。API里那些返回 action的close感觉代码业务只会太耦合
Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

TLS support?

Is TLS support planned?

In accordance with tidwall/evio#28 there are no easy way to implement it:

The problem is in standard Go TLS implementation. It doesn't have an event-based idea mechanism and actually it can block calls like Reader.Read() during handshake, what is actually not accurate by the io.Reader contract.

Looks like custom TLS implementation is required for this.

大量连接发送与接收消息中,再断开导致map读写冲突

Steps to reproduce the behavior:

  1. 服务端监听tcp,使用多核端口复用
  2. 客户端2W连接(足够多可能就会触发)
  3. cpu是6核12线,发送与接收数据,客户端接收速度约5万qps
  4. 数据未发送与接收完毕时,关闭客户端
    image

System Info (please complete the following information):

  • OS (e.g. Linux): ubuntu 19.10
  • Go Version (e.g. Go 1.13): 1.13.3
  • gnet Version (e.g. v1.0.0-beta.3): v1.0.0-beta.7

Additional context
附加一个建议,AsyncWrite是异步写出,导致我的写出消息[]bye,需要一直make 和 copy,我修改AsyncWrite为同步写出,不需要copy一份数据就能输出无错误,所以我需要一个直接输出消息的Write接口

Connection-level codecs

Is your feature request related to a problem? Please describe.
When the gnet works with a protocols that has a connection-level configuration (like the websocket) we have a problem with the Codec abstraction.
In the websocket protocol we have a connection-level negotiation about the „extensions“ that will be applied to the connection. That means the same websocket server can handle compressed and uncompressed connections.

Describe the solution you'd like
Simple but may be hacky way to do that — have the gnet.Conn in the Encode method. When we accept a connection we can write a negotiated extensions into the conn ctx and when we make decoding — we can read it from conn.Context(). To be clear the ICodec already aware about gnet.Conn in the Decode method, why not to do that in the Encode too?

Describe alternatives you've considered
Other way might be to have a multiple codecs in the server object. And when we create the conn we should assign one of them manually (store pointer or some synthetic ID of the codec in the conn struct) into OnOpened method.

Additional context
WebSocket RFC
WebSocket permessage-deflate RFC

希望AsyncWrite添加一个回调

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

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.