Skip to content

Instantly share code, notes, and snippets.

@tevino tevino/epoll.go
Last active Nov 16, 2019

Embed
What would you like to do?
Golang example for using epoll
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 commented Jan 25, 2019

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

@praglody

This comment has been minimized.

Copy link

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 commented Jun 15, 2019

@praglody
Try EPOLLET = 0x80000000

FYI golang/go#832

@praglody

This comment has been minimized.

Copy link

praglody commented Jun 17, 2019

It has been solved,thinks!

@andrewtw

This comment has been minimized.

Copy link

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 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 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.
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.