go 使用 epoll 实现高性能tcp服务器 - 简书


本站和网页 https://www.jianshu.com/p/cd070318062a 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

go 使用 epoll 实现高性能tcp服务器 - 简书登录注册写文章首页下载APP会员IT技术go 使用 epoll 实现高性能tcp服务器QxQx关注赞赏支持go 使用 epoll 实现高性能tcp服务器在go中实现一个tcp服务器还是很简单的,至少和C/C++相比还是很简单的了。
一个简单的例子
listen, err := net.Listen("tcp", "0.0.0.0:8088")
只需要这样一行就可以监听了,就能等待客户端连接了。是不是还是很简单的
在C/C++中,需要依次 调用socket() bind() listen() accept()函数,完成打开,绑定,监听,等待操作,才能完成等待客户端来连接。
这还没完,想要提高性能还需要自己通过 epoll等手段完成多路复用。
其实在C/C++中是通过调用系统函数来完成的,只是go把这部分东西都给包装了,只需要简单的一行就可以完成了。
其实在go中也可以通过系统函数自己来完成些事情。只是这些事情比较复杂,跨平台还不好弄,像使用了epoll就只能在linux系统上编译运行了。
废话不多说了,直接上函数吧。在go中和C/C++中区别不大,同样是通过系统调用这些函数来完成。
func Socket(domain, typ, proto int) (fd int, err error)
func Bind(fd int, sa Sockaddr) (err error)
func Listen(s int, n int) (err error)
func Accept(fd int) (nfd int, sa Sockaddr, err error)
在go开启tcp 服务需要用到的函数.
func EpollCreate(size int) (fd int, err error)
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
在go中使用epoll需要的函数
这些函数都是在syscall 包下,所以这些函数不是所有系统下都有的,
像epoll 相关的函数,就只能在linux下才能编译过。
所以,在这里就引申出一个东西就是 条件编译
在C/C++中可以通过宏定义来实现条件编译
#ifdef linux
cout<<"It is in Linux OS!"<<endl;
#endif
这段代码就只能在linux系统上才会被编译
go虽然没有这么强大的宏命令来判断,但是go中可以通过编译标签 和 文件后缀来判断。
比如在文件的第一行加上
// +build linux
.....
.....
这样,这个文件就只能在linux上才会被编译(注意,// +build linux下面一定要有一个空行)
详细用法看这里 go条件编译
下面开始具体的代码
//定义一个结构体存储相关的数据
type EpollM struct {
conn map[int]*ServerConn
socketFd int //监听socket的fd
epollFd int //epoll的fd
//开启监听
func (e *EpollM) Listen(ipAddr string, port int) error {
//使用系统调用,打开一个socket
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
if err != nil {
return err
//ip地址转换
var addr [4]byte
copy(addr[:], net.ParseIP(ipAddr).To4())
net.ParseIP(ipAddr).To4()
err = syscall.Bind(fd, &syscall.SockaddrInet4{
Port: port,
Addr: addr,
})
if err != nil {
return err
//开启监听
err = syscall.Listen(fd, 10)
if err != nil {
return err
e.socketFd = fd
return nil
这样就完成了监听
下面是 epoll 处理部分
//处理epoll
func (e *EpollM) HandlerEpoll() error {
events := make([]syscall.EpollEvent, 100)
//在死循环中处理epoll
for {
//msec -1,会一直阻塞,直到有事件可以处理才会返回, n 事件个数
n, err := syscall.EpollWait(e.epollFd, events, -1)
if err != nil {
return err
for i := 0; i < n; i++ {
//先在map中是否有这个链接
conn := e.GetConn(int(events[i].Fd))
if conn == nil { //没有这个链接,忽略
continue
if events[i].Events&syscall.EPOLLHUP == syscall.EPOLLHUP || events[i].Events&syscall.EPOLLERR == syscall.EPOLLERR {
//断开||出错
if err := e.CloseConn(int(events[i].Fd)); err != nil {
return err
} else if events[i].Events == syscall.EPOLLIN {
//可读事件
conn.Read()
从连接中读写数据
//读取数据
func (s *ServerConn) Read() {
data := make([]byte, 100)
//通过系统调用,读取数据,n是读到的长度
n, err := syscall.Read(s.fd, data)
if n == 0 {
return
if err != nil {
fmt.Printf("fd %d read error:%s\n", s.fd, err.Error())
} else {
fmt.Printf("%d say: %s \n", s.fd, data[:n])
s.Write([]byte(fmt.Sprintf("hello %d", s.fd)))
//向这个链接中写数据
func (s *ServerConn) Write(data []byte) {
_, err := syscall.Write(s.fd, data)
if err != nil {
fmt.Printf("fd %d write error:%s\n", s.fd, err.Error())
最后在依次调用这些函数
package main
func main() {
epollM := NewEpollM()
//开启监听
err := epollM.Listen("0.0.0.0", 8088)
if err != nil {
panic(err)
//创建epoll
err = epollM.CreateEpoll()
if err != nil {
panic(err)
//异步处理epoll
go func() {
err := epollM.HandlerEpoll()
epollM.Close()
panic(err)
}()
//等待client的连接
err = epollM.Accept()
epollM.Close()
panic(err)
到这整个服务就运行起来了,代码已经上传到github了,传送门
整个过程看下来,和C/C++实现过程还是非常相似的,都是通过系统调用完成的。也没有什么难点,就这样吧
推荐阅读更多精彩内容linux下 C++ 使用 epoll 多路复用 实现高性能的tcpserverlinux系统中,实现socket多路复用的技术有select 、poll 、epoll 等多种方式。这些不同方式...QxQx阅读 790评论 0赞 2高性能服务器架构思路,不仅是思路在服务器端程序开发领域,性能问题一直是备受关注的重点。业界有大量的框架、组件、类库都是以性能为卖点而广为人知。然而...dreamer_lk阅读 937评论 0赞 17高性能服务器架构思路在服务器端程序开发领域,性能问题一直是备受关注的重点。业界有大量的框架、组件、类库都是以性能为卖点而广为人知。然而...零一间阅读 761评论 0赞 12C#高性能Socket服务器IOCP实现引言 我一直在探寻一个高性能的Socket客户端代码。以前,我使用Socket类写了一些基于传统异步编程模型的代码...编程小世界阅读 346评论 0赞 0图文详解 epoll 原理【Redis,Netty,Nginx实现高性能IO的核心原理】epo...【Redis,Netty,Nginx 等实现高性能IO的核心原理】 I/O 输入输出(input/output)的...禅与计算机程序设计艺术阅读 384评论 0赞 9跟随业务场景的优化-10大高性能开发宝石,我要消灭一半程序员转发来源:https://www.toutiao.com/a6862279929489261070/ 程序员经常要...薛延祥阅读 288评论 0赞 010大高性能开发宝石,我要消灭一半程序员!来自公众号:编程技术宇宙作者:轩辕之风O 程序员经常要面临的一个问题就是:如何提高程序性能? 这篇文章,我们循序渐...夜空_2cd3阅读 298评论 0赞 710大高性能开发宝石,我要消灭一半程序员!来自公众号:编程技术宇宙作者轩辕之风O 程序员经常要面临的一个问题就是:如何提高程序性能? 这篇文章,我们循序渐进...码农小光阅读 2,967评论 3赞 6410大高性能开发宝石,我要消灭一半程序员!程序员经常要面临的一个问题就是:如何提高程序性能? 这篇文章,我们循序渐进,从内存、磁盘I/O、网络I/O、CPU...程序员知识圈阅读 1,761评论 4赞 39Linux高性能服务器开发公众号:畅游码海 更多高质量原创文章都在里面~ 主机字节序和网络字节序: 在32位机器上,累加器一次能装载4个字...CallMeEngineer阅读 374评论 0赞 1读书笔记| 高性能linux服务器编程date: 2016-08-02 22:37 来源: swoole - 学习Swoole需要掌握哪些基础知识: h...daydaygo阅读 1,425评论 0赞 3<<Linux高性能服务器编程>>(基础API与Reactor等内容)1.Linux网络编程基础API: 字节序分为大端字节序和小端字节序.小端字节序是指低位地址存放在内存的低位地址处...angel_贝贝阅读 183评论 0赞 0Linux高性能服务器处理框架本文为转载,文中所提到的知识点是每个Linux开发人员都需要考虑的问题。 终于开始学习epoll了,虽然不明白的地...C_GO流媒体后台开发阅读 481评论 0赞 5【腾云阁】高性能服务器架构思路(三)——分布式系统概念文章作者:韩伟 — 腾讯游戏高级架构师, 版权归原作者所有,未经作者同意,请勿转载文章来源:腾讯云技术社区——腾...腾讯云技术社区_腾云阁阅读 656评论 1赞 11Substrate的transaction-payment模块分析Substrate的transaction-payment模块分析 transaction-payment模块提供...建怀阅读 7,532评论 0赞 42019-11-28 17316宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...yichen大刀阅读 5,390评论 0赞 42019-11-28三数灯谜分析公元:2019年11月28日19时42分农历:二零一九年 十一月 初三日 戌时干支:己亥乙亥己巳甲戌当月节气:立冬...石放阅读 6,449评论 0赞 2零基础也不怕!CAD新手快速入门技巧,后悔没有早知道!想要快速入门CAD,对于零基础的新手来说的确有一定的困难。不过只要你掌握了以下这些CAD快速入门技巧,你就跨进了C...努力的王榆阅读 2,661评论 0赞 32019-11-27昨天考过了阿里规范,心里舒坦了好多,敲代码也犹如神助。早早完成工作回家喽常亚星阅读 2,789评论 0赞 1军争 下三军可夺气,将军可夺心。是故朝气锐,昼气惰,暮气归。善用兵者,避其锐气,击其惰归,此治气者也。以治待乱,以静待哗,...生姜牛奶泡腾片阅读 1,434评论 0赞 1评论0赞11赞2赞赞赏更多好文