Go代码epollechoserver代码实现
基于 epoll 系统调用实现非阻塞的echo server:
这部分代码是 Go BIO/NIO探讨(7):IO多路复用之epoll 的附录
package main import ( "fmt" "log" "net" "os" "os/signal" "syscall" ) func ipToSockaddrInet4(ip net.IP, port int) (syscall.SockaddrInet4, error) { if len(ip) == 0 { ip = net.IPv4zero } ip4 := ip.To4() if ip4 == nil { return syscall.SockaddrInet4{}, &net.AddrError{Err: "non-IPv4 address", Addr: ip.String()} } sa := syscall.SockaddrInet4{Port: port} copy(sa.Addr[:], ip4) return sa, nil } func isError(ev uint32) bool { return (ev&uint32(syscall.EPOLLERR)) > 0 || (ev&uint32(syscall.EPOLLHUP)) > 0 || (ev&syscall.EPOLLIN) == 0 } func main() { var ( family = syscall.AF_INET sotype = syscall.SOCK_STREAM _ = "tcp" listenBacklog = syscall.SOMAXCONN serverip = net.IPv4(0, 0, 0, 0) serverport = 8080 ) // 创建套接字 sockfd, err := syscall.Socket(family, sotype, 0) if err != nil { panic(fmt.Errorf("fails to create socket: %s", err)) } syscall.CloseOnExec(sockfd) // epoll edge-triggered 模式支持nonblock if err := syscall.SetNonblock(sockfd, true); err != nil { syscall.Close(sockfd) panic(fmt.Errorf("setnonblock error=%v", err)) } // 接收到Ctrl+C信号后,关闭socket c := make(chan os.Signal) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c log.Println("r- Ctrl+C pressed in Terminal") if err := syscall.Close(sockfd); err != nil { log.Printf("Close sockfd %d fails, err=%v ", sockfd, err) } else { log.Printf("Server stopped successfully!!!") } // 收到信号后需要处理, 否则程序会永久hang住, 需要kill -9 // os.Exit 会导致所有goroutine都会立即停止执行 os.Exit(0) }() addr, err := ipToSockaddrInet4(serverip, serverport) if err != nil { panic(fmt.Sprintf("fails to convert address %s:%d to socket addr, err=%s", serverip, serverport, err)) } if err := syscall.Bind(sockfd, &addr); err != nil { panic(fmt.Sprintf("fails to bind socket %d to address %s:%d, err=%s", sockfd, serverip, serverport, err)) } if err := syscall.Listen(sockfd, listenBacklog); err != nil { log.Printf("listen sockfd %d to addr error=%v ", sockfd, err) panic(fmt.Sprintf("fails to listen socket %d", sockfd)) } else { log.Printf("Started listening on %s:%d", serverip, serverport) } epfd, err := syscall.EpollCreate1(0) if err != nil { panic(fmt.Sprintf("create epoll instance fails, err=%s", err)) } // 默认是 level-triggered,效率更高的poll epEvent := syscall.EpollEvent{ Fd: int32(sockfd), Events: uint32(syscall.EPOLLIN) | uint32(-syscall.EPOLLET), } if err := syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, sockfd, &epEvent); err != nil { panic(fmt.Errorf("epoll_ctl %v fails, err=%s", epfd, err)) } events := make([]syscall.EpollEvent, 128, 128) var buf [32 * 1024]byte for { // msec < 0, EpollWait 会被阻塞直到有一个 fd 可用 nReady, err := syscall.EpollWait(epfd, events, -1) if err != nil { log.Printf("epoll_wait error=%v ", err) panic(fmt.Errorf("epoll_wait error=%v", err)) } for i := 0; i < nReady; i++ { ev := &events[i] if isError(ev.Events) { /* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */ log.Printf("epoll error: %s ", err) // 取消监听 _ = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_DEL, int(ev.Fd), ev) _ = syscall.Close(int(events[i].Fd)) continue } if ev.Fd == int32(sockfd) { for { // 监听套接字(server端套接字 clientfd, _, err := syscall.Accept(sockfd) if err == syscall.EAGAIN || err == syscall.EWOULDBLOCK { // 所有新创建的tcp conn均已被处理 break } // 设置为nonblock if err := syscall.SetNonblock(clientfd, true); err != nil { log.Printf("fails to set client socket %v as nonblock, err=%s ", clientfd, err) continue } epEvent.Fd = int32(clientfd) epEvent.Events = uint32(syscall.EPOLLIN) | uint32(-syscall.EPOLLET) if err := syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, clientfd, &epEvent); err != nil { log.Printf("register client socket %v fails, err=%s ", clientfd, err) syscall.Close(clientfd) continue } } } else { // 已连接套接字 tcp conn for { nRead, err := syscall.Read(int(ev.Fd), buf[:]) if err == syscall.EAGAIN || err == syscall.EWOULDBLOCK { // 数据已经读完了 break } else if err != nil { log.Printf("fails to read data from sockfd %d, err=%v ", ev.Fd, err) _ = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_DEL, int(ev.Fd), ev) _ = syscall.Close(int(ev.Fd)) break } else if nRead == 0 { // EOF // Client closed log.Printf("client sock %d closed ", ev.Fd) _ = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_DEL, int(ev.Fd), ev) _ = syscall.Close(int(ev.Fd)) break } else { log.Printf("read %d bytes from sock %d ", nRead, ev.Fd) if _, err := syscall.Write(int(ev.Fd), buf[:nRead]); err != nil { log.Printf("fails to write data %s into sockfd %d, err=%v ", buf[:nRead], sockfd, err) } } } } } } }
美国建成先进粒子探测器来源抚顺市科技局科技动态(外)美国布鲁克海文国家实验室的先进粒子探测器sPHENIX首次亮相。这个探测器重达1000吨,计划于2023年春天起在该实验室的相对论重离子对撞机(RHI
梦幻西游3月21日维护公告解读大家好,我是梦幻新之助。本周所有服务器将于2023年3月21日上午800至上午930分进行例行维护,来一起看一看本周的更新内容。一hr1妙笔丹青玩法调整,新增精力拍卖玩法,在部分服
实况足球手游国服大更时精选要删卡?近段时间的精选包中,出现了一些不错的卡,部分玩家想要入手,又听说大更时这些精选就要删卡,想放弃又怕错过好货,所以在打听网传大更删精选卡一事是否属实。网传精选在大更时即会删卡的原因,
小儿夜啼哭闹之罪魁祸首猪毛痧?httpsmp。weixin。qq。comsBinMGwO6j5qZsgFJqGMhA原创二哥2014a收录于合集二哥医案小故事70个猪毛痧,流传于民间的一种神奇说法,其实它离我们
耳廓形态畸形?需抓住黄金时间矫治矫治前后对比。红网时刻新闻3月20日讯(通讯员杨慕)近日,湖南省妇幼保健院儿童五官科诊室来了一对特别的父母,为什么说是特别?因为该父母生下的两个宝宝都患有先天性耳廓形态畸形,但是时
上午1130,央视新闻直播探访京西古街模式口,石景山融媒同步转播春游模式口2023年3月20日探访直播来啦京西古道模式口,悠悠驼铃数百年。模式口自古以来就是京都通往塞外的驼铃古道,是一个拥有深厚底蕴的历史文化街区,也是西山永定河文化带的重要节点
爆料!港人在泰国蹦极险丧命,仅获赔2000元!旅游复常,很多人抢着外游松一松,但要尽量避免玩高危活动!有港人报称在泰国一个乐园玩笨猪跳,遇上断绳险赔命,园方仅赔二千多港元汤药费。事件引起市民关注外游保障。笨猪跳受追求刺激的游客
太萌了!2023山东省旅发大会的吉祥物,你喜欢吗?3月26日27日,2023山东省旅游发展大会将在青岛举办。提前亮相的大会吉祥物和Logo造型备受人们喜爱,它们背后蕴藏着怎么样的内涵?青岛市文化和旅游局局长潘峰为您解密。潘峰介绍,
耒阳春芽吐新正采时茶韵飘香促振兴位于耒阳市黄市镇蔡伦竹海风景区内的500亩春茶吐露新芽。茶农们正抢时采摘新年的第一波春茶。红网时刻衡阳3月20日讯(通讯员刘喜陈金龙)春暖花开,茶叶飘香。近日,位于耒阳市黄市镇蔡伦
埃及努比亚村关于古村落开发与保护的思考在埃及古城阿斯旺镇尼罗河西岸的大象岛,有两个努比亚聚居的村庄,分别是西欧村(Siou)和扣媞村(Koti),这两个村庄由一条人行道相连,人们习惯上将它们统称为努比亚村。村庄一面靠近
长沙市赴长治举办红色讲解员培训班湖南日报新湖南客户端3月20日讯(记者刘涛)今日,由长沙市文化旅游广电局主办的追寻革命足迹讲好红色故事2023年长沙市讲解员赴红色革命根据地沉浸式学习培训班在长治市开班,来自全市的
亏损扩大靠长城输血,蜂巢能源能撑起600亿估值吗?雷达财经出品文李亦辉编深海证监会官网显示,11月18日,蜂巢能源科技股份有限公司(下称蜂巢能源)科创板IPO获上交所受理,中信证券为其保荐机构,拟募资150亿元。蜂巢能源专注于新能
LG新能源只盯宁王,却遭比亚迪反杀?撰文陈邓新编辑高智动力电池排位赛,出现了微妙的变化。日前,全球动力电池2022年第三季度排名发布,宁德时代装机量48。9GWh稳居行业第一,比亚迪以微弱优势反超了LG新能源,上跃至
正副董事长全被监视居住千亿白马股一字板跌停正副董事长全被监视居住,云南千亿白马股跌停,22万手卖单排队出逃,市值一天蒸发超138亿元!11月22日,恩捷股份(002812)一字板跌停,股价报收140。17元,跌停板封单超2
36氪首发热醒Rexing获数百万人民币天使轮融资,重新定义户外运动品牌文沈广丽编辑潘潇雨36氪获悉,户外功能性服装品牌热醒Rexing已于近日完成数百万人民币天使轮融资。本轮融资由唯品会战略投资,融资资金将主要用于团队拓展品牌搭建和完善供应链体系。户
揭秘刘强东刚宣布设立的百亿住房保障基金11月22日,京东创始人刘强东以你们的东哥署名发布全员信。除了要给高管降薪20,还宣布未来十年京东将投入数百亿为基层员工提供购房无息贷款。刘强东在信中表示,集团拿出100亿元,为包
顶级操盘手直言为什么股票早上快速拉高然后慢慢下跌?作为大众投资理财方式之一的股票投资,已经得到广大投资者的认可,投资股票市场也已经成为一种时尚。投资者都想在股市中挣大钱,但作为一种投资,有赚就必然有赔,而且赔钱的比例往往比较大。也
2057亿总负债悬顶!归来的黄其森能力挽狂澜吗?时隔八个月,曾被业内誉为第二代豪宅教父的黄其森终于回来了。11月17日,ST泰禾发布公告称,对于近日有媒体发布了关于泰禾集团董事长黄其森结束配合调查回归的报道,公司董事长兼总经理黄
在沙特阿拉伯否认有关欧佩克增加供应的报道后,油价暴跌后反弹周一油价在震荡的交易时段小幅收低。有报道称,欧佩克正在权衡增加产量,这将有助于抵消俄罗斯原油供应的损失,但在沙特阿拉伯断然否认后,油价暴跌后反弹。国际基准布伦特原油收跌0。2,至8
心宽无烦恼,心静人则安!(生活感悟)头条创作挑战赛人的这颗心,是情绪的制造厂,它既可以制造快乐,又可以生产烦忧。情绪是可以控制的,烦忧也是可以解除的。开心快乐是一天,烦恼围绕也是一天,既然快乐能让人感到幸福,干嘛让烦
试驾奥迪Q5etron豪华品牌杀入纯电动车市场一个新的事实是,新能源汽车正在以肉眼可见的速度,经历着对传统燃油车的替代。在中国,今年17月,新能源乘用车渗透率已跃升至24。7,零售销量达到了273。3万辆,8月,国内每卖4辆车
汽油需求已经达峰?文丁少恒中国汽车工业协会发布数据,2022年前三季度国内新能源乘用车销量为435。6万辆,按照汽车行业常用的渗透率指标(即占乘用车销量的比例)评价,已经达到25。7,其中4月8月9