Close(eventFileDescriptor)
} else if eventFileDescriptor == eventLoop.SocketFileDescriptor {
// new incoming connection
socketConnection, _, err :=
syscall.Accept(eventFileDescriptor)
if err != nil {
continue
}
socketEvent := syscall.Kevent_t{
Ident: uint64(socketConnection),
Filter: syscall.EVFILT_READ,
Flags: syscall.EV_ADD,
Fflags: 0,
Data: 0,
Udata: nil,
}
socketEventRegistered, err := syscall.Kevent(
eventLoop.KqueueFileDescriptor,
[]syscall.Kevent_t{socketEvent},
nil,
nil
)
if err != nil || socketEventRegistered == -1 {
continue
}
} else if currentEvent.Filter&syscall.EVFILT_READ != 0 {
// data available -> forward to handler
handler(&socket.Socket{
FileDescriptor: int(eventFileDescriptor)
})
}
// ignore all other events
}
}
Enter fullscreen mode
Exit fullscreen mode
The first case we want to handle are EV_EOF events. An EV_EOF event indicates that a client wants to close its connection. In that case we simply close the respective socket file descriptor. The second case represents an incoming connection on the listen socket. We can use the accept system call to pop the connection request from the queue of pending TCP connections. It then creates a new socket and a new file descriptor for that socket. Based on that newly created socket we subscribe to a new EVFILT_READ event. On accept sockets, EVFILT_READ events happen whenever there is data to be read on the socket. The third case handles the EVFILT_READ events from the previous case. These events contain the file descriptor of the client socket. We wrap it inside a Socket object and pass it to the handler function.
Hey, can you add some more context about how kqueue works compared to epoll? I’m curious to know which one is better for my project.