本文摘自网络,作者,侵删。
本项目地址:gof 一个支持百万连接的websocket框架
本文提及的内容包含在:epoll.go
一、Epoll模型处理数据的流程
关于Linux Epoll模型的原理,这里就不在做过多介绍了,在Nginx、Redis等的网络并发模型方面,有诸多的详细解释。
Epoll模型中,应用是监听Epoll的Wait接口,来等待系统的推送,因此,比之select/poll等的实现方式略微复杂。
在整个Epoll模型的实现中,其主要的内容包括:
1、创建一个全局的句柄(以下称为 GlobalFd),并使用该句柄绑定指定的端口,从而进行数据的接收。
2、创建一个全局的Epoll模型,并将我们创建的GlobalFd放到Epoll模型中,让系统内核自己去监听该句柄。
3、调用Epoll对象的wait方法,去获取当前Epoll中是否有新的消息。当Epoll推送给我们新的消息时,包含两种情况:1. 当有新的连接进入到GlobalFd,Epoll模型会通过GlobalFd将消息推送给我们,我们可以通过一个syscall的read函数去取到对应的连接句柄(Fd),然后同样将该Fd加入到Epoll对象中。2. 如果Epoll推送给我们的消息句柄不是GlobalFd,那么就说明是某个连接中有了新的消息,这个时候我们就要读取该消息,并进行对应的处理。
二、用代码实现我们的Epoll流程
1.创建GlobalFd
我们需要需要创建一个全局的句柄,并且指定一个端口,绑定到这个句柄上,这样我们的应用就可以进行端口来进行消息的收发了。
GlobalFd, err := syscall.Socket(syscall.AF_.NET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
if err != nil {
Log.Error("getScoket err:%v", err.Error())
os.Exit(1)
}
syscall是golang的标准库,用来调用操作系统的接口。
syscall.Socket的作用是创建一个socket连接,接收三个参数,分别为:
第一个参数 domain
syscall.AF_INET,表示服务器之间的网络通信
syscall.AF_UNIX 表示同一台机器上的进程通信
syscall.AF_INET6 表示以IPv6的方式进行服务器之间的网络通信
第二个参数 typ
syscall.SOCK_RAW,表示使用原始套接字,可以构建传输层的协议头部,启用IP_HDRINCL的话,IP层的协议头部也可以构造,就是上面区分的传输层socket和网络层socket。
syscall.SOCK_STREAM, 基于TCP的socket通信,应用层socket。
syscall.SOCK_DGRAM, 基于UDP的socket通信,应用层socket。
第三个参数 proto
IPPROTO_TCP 接收TCP协议的数据
IPPROTO_IP 接收任何的IP数据包
IPPROTO_UDP 接收UDP协议的数据
IPPROTO_ICMP 接收ICMP协议的数据
IPPROTO_RAW 只能用来发送IP数据包,不能接收数据。
该接口会返回两个参数,句柄fd和错误信息,如果错误信息为空,那么我就可以通过这个句柄去绑定IP。
2. 用GlobalFd绑定IP
绑定IP依然是执行syscall中的函数来进行,首先我们需要确定IP和端口,然后再通过syscall.Listen()方法进行端口绑定。
//监听
addr := syscall.SockaddrInet4{Port: e.port}
ip := "0.0.0.0"
if e.ip != "" {
ip = e.ip
}
copy(addr.Addr[:], net.ParseIP(ip).To4())
if err := syscall.Bind(GlobalFd, &addr); err != nil {
Log.Error("bind err:%v", err.Error())
os.Exit(1)
}
if err := syscall.Listen(GlobalFd, 10); err != nil {
Log.Error("listen err:%v", err.Error())
os.Exit(1)
}
在绑定完成之后,我们就可以通过GlobalFd来进行各种消息的处理了。
3.创建Epoll对象,监听消息
对于句柄的监听,linux有select/poll,epoll等多种管理方式,其中epoll是目前大多数应用采用的方法。在使用Epoll模型的过程中,首先我们应该创建一个epoll对象。
//创建epfd
epFd, err := syscall.EpollCreate1(0)
Log.Info("getGlobalFd 创建的epfd为:%+v,e.fd:%d", epfd, e.socket)
if err != nil {
Log.Error("epoll_create1 err:%+v", err)
os.Exit(1)
}
通过EpollCreate函数可以创建一个Epoll对象。在golang中对于epoll对象的创建有两个函数:EpollCreate(size) 和EpollCreate1(size)。
EpollCreate函数需要传入一个size,手动分配可承载句柄的大小。
相关阅读 >>
linux怎么安装Golang和dep(附错两个误解决方法)
更多相关阅读请进入《Go》频道 >>

Go语言101
一个与时俱进的Go编程知识库。