Skip to content

Instantly share code, notes, and snippets.

@tevino

tevino/epoll.go

Last active Sep 9, 2020
Embed
What would you like to do?
An example of using epoll in Go
package main
import (
"fmt"
"net"
"os"
"syscall"
)
const (
EPOLLET = 1 << 31
MaxEpollEvents = 32
)
func echo(fd int) {
defer syscall.Close(fd)
var buf [32 * 1024]byte
for {
nbytes, e := syscall.Read(fd, buf[:])
if nbytes > 0 {
fmt.Printf(">>> %s", buf)
syscall.Write(fd, buf[:nbytes])
fmt.Printf("<<< %s", buf)
}
if e != nil {
break
}
}
}
func main() {
var event syscall.EpollEvent
var events [MaxEpollEvents]syscall.EpollEvent
fd, err := syscall.Socket(syscall.AF_INET, syscall.O_NONBLOCK|syscall.SOCK_STREAM, 0)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer syscall.Close(fd)
if err = syscall.SetNonblock(fd, true); err != nil {
fmt.Println("setnonblock1: ", err)
os.Exit(1)
}
addr := syscall.SockaddrInet4{Port: 2000}
copy(addr.Addr[:], net.ParseIP("0.0.0.0").To4())
syscall.Bind(fd, &addr)
syscall.Listen(fd, 10)
epfd, e := syscall.EpollCreate1(0)
if e != nil {
fmt.Println("epoll_create1: ", e)
os.Exit(1)
}
defer syscall.Close(epfd)
event.Events = syscall.EPOLLIN
event.Fd = int32(fd)
if e = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, fd, &event); e != nil {
fmt.Println("epoll_ctl: ", e)
os.Exit(1)
}
for {
nevents, e := syscall.EpollWait(epfd, events[:], -1)
if e != nil {
fmt.Println("epoll_wait: ", e)
break
}
for ev := 0; ev < nevents; ev++ {
if int(events[ev].Fd) == fd {
connFd, _, err := syscall.Accept(fd)
if err != nil {
fmt.Println("accept: ", err)
continue
}
syscall.SetNonblock(fd, true)
event.Events = syscall.EPOLLIN | EPOLLET
event.Fd = int32(connFd)
if err := syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, connFd, &event); err != nil {
fmt.Print("epoll_ctl: ", connFd, err)
os.Exit(1)
}
} else {
go echo(int(events[ev].Fd))
}
}
}
}
@JoveYu

This comment has been minimized.

Copy link

@JoveYu JoveYu commented Jan 25, 2019

use so many syscall, why not use C instead of GO

@praglody

This comment has been minimized.

Copy link

@praglody praglody commented Jun 15, 2019

为什么 EPOLLET 是一个负数,我这里会报错,请问下是什么原因呢?

EpollCtl(epfd, EPOLL_CTL_ADD, ufd, &EpollEvent{
        Fd:     int32(ufd),
	Events: EPOLLIN | EPOLLERR | EPOLLET,
})

command-line-arguments

./server.go:73:23: constant -2147483647 overflows uint32

@tevino

This comment has been minimized.

Copy link
Owner Author

@tevino tevino commented Jun 15, 2019

@praglody
Try EPOLLET = 0x80000000

FYI golang/go#832

@praglody

This comment has been minimized.

Copy link

@praglody praglody commented Jun 17, 2019

It has been solved,thinks!

@andrewtw

This comment has been minimized.

Copy link

@andrewtw andrewtw commented Sep 13, 2019

use so many syscall, why not use C instead of GO

Using C inside Go is okay but it causes performance issue at the moment

@deardeng

This comment has been minimized.

Copy link

@deardeng deardeng commented Sep 16, 2019

客户端关闭,echo 函数不能退出,goroutine死循环,要添加

	if nbytes == 0{
		if err := syscall.EpollCtl(epfd, syscall.EPOLL_CTL_DEL, fd, nil); err != nil{
			fmt.Println("epoll_ctl: ", err)
			os.Exit(1)
		}
		break
	}
@tevino

This comment has been minimized.

Copy link
Owner Author

@tevino tevino commented Sep 16, 2019

客户端关闭,echo 函数不能退出,goroutine死循环,要添加

	if nbytes == 0{
		if err := syscall.EpollCtl(epfd, syscall.EPOLL_CTL_DEL, fd, nil); err != nil{
			fmt.Println("epoll_ctl: ", err)
			os.Exit(1)
		}
		break
	}

man 7 epoll:

 6.  Will closing a file descriptor cause it to be removed from all epoll interest lists?

           Yes,  but  be  aware of the following point.  A file descriptor is a reference to an open file description (see open(2)).  Whenever a file descriptor is duplicated via dup(2), dup2(2), fcntl(2) F_DUPFD, or fork(2), a new
           file descriptor referring to the same open file description is created.  An open file description continues to exist until all file descriptors referring to it have been closed.
@lasselj

This comment has been minimized.

Copy link

@lasselj lasselj commented Apr 22, 2020

use so many syscall, why not use C instead of GO

If the compiler is a C compiler or a GO compiler what difference does it make? It is not the case that the binary produced by one is inherently "slower" than the other.

@VVilaplana

This comment has been minimized.

Copy link

@VVilaplana VVilaplana commented Apr 29, 2020

If the compiler is a C compiler or a GO compiler what difference does it make? It is not the case that the binary produced by one is inherently "slower" than the other.

Yes, of course there's a huge difference.
GO compilers compiles your code to run inside a runtime, which is essentially an abstraction layer doing all the dirty work that C programmers manually do (memory management, process scheduling, and all of that).

But then again, this is the most important reason in my opinion:
epoll() is normally used because it provides a performance orders of magnitude bigger than a normal poll() or a select().
When you require very high performance, you don't want to ruin in because the garbage collector kicks in.

@Togou98

This comment has been minimized.

Copy link

@Togou98 Togou98 commented Jun 26, 2020

package syscall define the EPOLLET = -0x8000000 ,but epoll_event field "Events" need uint32 I'm confused 🤣

@lasselj

This comment has been minimized.

Copy link

@lasselj lasselj commented Jun 26, 2020

package syscall define the EPOLLET = -0x8000000 ,but epoll_event field "Events" need uint32 I'm confused 🤣

There's more than one way to skin a cat. Try something like: const EPOLLET uint32 = 1<<31

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.