每日新闻

每日新闻

GoCN每日新闻资讯
有问必答

有问必答

Go相关的问题,技术相关的问题
文章分享

文章分享

技术文章分享,让知识传播给更多的人
招聘应聘

招聘应聘

为Gopher服务的招聘应聘平台

技术实践——教你用100行写一个 go 的协程池 (任务池)!!!

有只黑白猫 发表了文章 • 0 个评论 • 276 次浏览 • 2020-01-09 16:44 • 来自相关话题

点击这里,查看封装 GetCap() 方法等重要内容实现Talk is cheap. Show me the code.任务的定义 ...查看全部

点击这里,查看封装 GetCap() 方法等重要内容

实现
Talk is cheap. Show me the code.

任务的定义
任务要包含需要执行的函数、以及函数要传的参数, 因为参数类型、个数不确定, 这里使用可变参数和空接口的形式

type Task struct {
Handler func(v ...interface{})
Params []interface{}
}

任务池的定义
任务池的定义包括了池的容量 capacity、当前运行的 worker(goroutine)数量 runningWorkers、任务队列(channel)taskC、关闭任务池的 channel closeC 以及任务池的状态 state(运行中或已关闭, 用于安全关闭任务池)

type Pool struct {
capacity uint64
runningWorkers uint64
state int64
taskC chan *Task
closeC chan bool
}

任务池的构造函数:

var ErrInvalidPoolCap = errors.New("invalid pool cap")

const (
RUNNING = 1
STOPED = 0
)

func NewPool(capacity uint64) (*Pool, error) {
if capacity <= 0 {
return nil, ErrInvalidPoolCap
}
return &Pool{
capacity: capacity,
state: RUNNING,
// 初始化任务队列, 队列长度为容量
taskC: make(chan *Task, capacity),
closeC: make(chan bool),
}, nil
}

启动 worker

新建 run() 方法作为启动 worker 的方法:

func (p *Pool) run() {
p.runningWorkers++ // 运行中的任务加一

go func() {
defer func() {
p.runningWorkers-- // worker 结束, 运行中的任务减一
}()

for {
select { // 阻塞等待任务、结束信号到来
case task, ok := <-p.taskC: // 从 channel 中消费任务
if !ok { // 如果 channel 被关闭, 结束 worker 运行
return
}
// 执行任务
task.Handler(task.Params...)
case <-p.closeC: // 如果收到关闭信号, 结束 worker 运行
return
}
}
}()
}

上述代码中, runningWorkers 的加减直接使用了自增运算, 但是考虑到启动多个 worker 时, runningWorkers 就会有数据竞争, 所以我们使用 sync.atomic 包来保证 runningWorkers 的自增操作是原子的。

对 runningWorkers 的操作进行封装:

func (p *Pool) incRunning() { // runningWorkers + 1
atomic.AddUint64(&p.runningWorkers, 1)
}

func (p *Pool) decRunning() { // runningWorkers - 1
atomic.AddUint64(&p.runningWorkers, ^uint64(0))
}

func (p *Pool) GetRunningWorkers() uint64 {
return atomic.LoadUint64(&p.runningWorkers)
}

打铁乘热, 对于 capacity 的操作也考虑数据竞争, 封装 GetCap() 方法:


关键字:网络协议 Java Go

Go语言必备技能——加快你的工作效率

有只黑白猫 发表了文章 • 0 个评论 • 249 次浏览 • 2020-01-03 15:31 • 来自相关话题

点击这里,查看 ...查看全部

点击这里,查看集合,Playground链接,依赖包管理等更多内容

一句话技巧

把你面向对象的大脑扔到家里吧,去拥抱接口。
学习如何使用Go的方式做事,不要把别的的编程风格强行用在Go里面。
多用接口总比少用好。
拥抱这种简洁、并行、工整的语言。
阅读官网golang.org上所有的文档,真是棒呆了。
别忘了用gofmt。
多读源代码。
学习工具和组件,然后创造你自己的!码代码和学代码一样对成功必不可少。
学而不思则罔,思而不学则殆。《论语》

引入package的多种方式

有几种非常规方式来引入包(package)。接下来我会使用fmt来作为例子:

import format "fmt" - 为fmt创造一个别名。把代码中所有使用到fmt的内容用format.代替fmt.
import . "fmt" - 允许包内的内容不加fmt前缀而被被直接引用
import _ "fmt" - 阻止编译器为引入fmt却不使用里面的内容做引发的警告,执行package中的初始化函数。提醒一句,在这种情况下fmt是不可调用的
看这篇博客来了解更多细节。

Goimports
命令goimports可以更新您的Go导入行,添加缺少的行,并删除未引用的引导行。

它拥有和gofmt(插入式替换)相同的能力,但是goimports额外增加了修复imports的功能。

组织
Go是一种相对来说易学习的编程语言,但对于开发者来说,起初接触这门语言最困难的事情就是如何组织代码。scaffolding是人们喜欢Rails的原因之一,它可以给新晋的开发者清晰的方向,让他们明白在哪里插入代码,应该遵循怎样的编程风格。

作为扩展,Go使用go fmt这样的工具来提供开发者相同的功能。同样地,Go的编译器非常严格,它不会去编译没有使用的变量,或者没有使用的import声明。

自定义构造函数
我经常听到别人问,“我什么时候应该使用像NewJob这样的自定义构造函数?”,我的回答是“大多数情形下你没必要这么做”。然而,当你需要在初始化的时候就设置值,且你有一些默认值的时候,这就最好使用一个构造函数。在这个例子中,构造函数就比较有意义了,因此我们用如下的代码可以构建一个默认的logger:

关键字:javaScript 编译器 测试技术 Go 持续交付 C语言 开发者 Ruby

Go 语言的 10 个实用技巧

有只黑白猫 发表了文章 • 0 个评论 • 198 次浏览 • 2020-01-03 15:02 • 来自相关话题

点击这里,查看剩余7项实用技巧等更多重要内容 ...查看全部

点击这里,查看剩余7项实用技巧等更多重要内容

简介: Go语言实战学习小技巧

使用单一的 GOPATH
多个 GOPATH 的情况并不具有弹性。GOPATH 本身就是高度自我完备的(通过导入路径)。有多个 GOPATH 会导致某些副作用,例如可能使用了给定的库的不同的版本。你可能在某个地方升级了它,但是其他地方却没有升级。而且,我还没遇到过任何一个需要使用多个 GOPATH 的情况。所以只使用单一的 GOPATH,这会提升你 Go 的开发进度。

许多人不同意这一观点,接下来我会做一些澄清。像 etcd 或camlistore 这样的大项目使用了像 godep 这样的工具,将所有依赖保存到某个目录中。也就是说,这些项目自身有一个单一的 GOPATH。它们只能在这个目录里找到对应的版本。除非你的项目很大并且极为重要,否则不要为每个项目使用不同的 GOPATH。如果你认为项目需要一个自己的 GOPATH 目录,那么就创建它,否则不要尝试使用多个 GOPATH。它只会拖慢你的进度。

将 for-select 封装到函数中
如果在某个条件下,你需要从 for-select 中退出,就需要使用标签。例如:

func main() {

L:
for {
select {
case <-time.After(time.Second):
fmt.Println(“hello”)
default:
break L
}
}

fmt.Println(“ending”)
}
如你所见,需要联合break使用标签。这有其用途,不过我不喜欢。这个例子中的 for 循环看起来很小,但是通常它们会更大,而判断break的条件也更为冗长。

如果需要退出循环,我会将 for-select 封装到函数中:

`func main() {
foo()
fmt.Println(“ending”)
}

func foo() {
for {
select {
case <-time.After(time.Second):
fmt.Println(“hello”)
default:
return
}
}
}

你还可以返回一个错误(或任何其他值),也是同样漂亮的,只需要:

// 阻塞
if err := foo(); err != nil {
// 处理 err
}`

在初始化结构体时使用带有标签的语法

关键字:JavaScript 安全 数据库连接 测试技术 Go 数据库 Windows

C++ STL的go语言版本,欢迎各位大佬完善

stirlingx 发表了文章 • 0 个评论 • 389 次浏览 • 2019-11-20 11:21 • 来自相关话题

项目地址: https://github.com/liyue201/gostl目前已实现的功能data structure ...查看全部

gout: 流式http client v0.0.3版本发布

guonaihong 发表了文章 • 0 个评论 • 275 次浏览 • 2019-11-18 09:31 • 来自相关话题

简介    gout是golang写的流式http client,易用的接口和丰富的数据绑定,比标准库更爽的使用感受。目前可用于RESTful 接口开发。流式构架设计方便水平扩张功能,下个版本支持benckmark模式 ...查看全部

简介

    gout是golang写的流式http client,易用的接口和丰富的数据绑定,比标准库更爽的使用感受。目前可用于RESTful 接口开发。流式构架设计方便水平扩张功能,下个版本支持benckmark模式


Changlog

<main>
  • #78 debug模式下-支持json语法高亮
  • #84 支持x-www-form-urlencoded
  • #82 新增example目录,存放使用示例
  • #83 SetForm支持更多数据类型
  • #81 代码测试覆盖度达到90%
</main>

    Excelize 发布 2.0.2 版本, Go 语言 Excel 文档基础库

    xuri 发表了文章 • 0 个评论 • 455 次浏览 • 2019-10-10 14:32 • 来自相关话题


    Excelize 是 Go 语言编写的用于操作 Office Excel 文档类库,基于 ECMA-376 Office Open XML 标准。可以使用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创建的 XLSX 文档。相比较其他的开源类库,Excelize 支持写入原本带有图片(表)、透视表和切片器等复杂样式的文档,还支持向 Excel 文档中插入图片与图表,并且在保存后不会丢失文档原有样式,可以应用于各类报表系统中。入选 2018 开源中国码云 Gitee 最有价值开源项目 GVP,目前已成为 Go 语言最受欢迎的 Excel 文档基础库。

    开源代码

    GitHub: github.com/xuri/excelize
    Gitee: gitee.com/xurime/excelize
    中文文档: xuri.me/excelize/zh-hans

    Excelize 知名用户

    Go Excelize 知名用户

    2019年10月9日,社区正式发布了 2.0.2 版本,该版本包含了多项新增功能、错误修复和兼容性提升优化。下面是有关该版本更新内容的摘要,完整的更改列表可查看 change log

    有关更改的摘要,请参阅 Release Notes。完整的更改列表可查看 change log

    Release Notes

    此版本中最显著的变化包括:

    兼容性提示

    升级至该版本需要您的 Go 语言版本高于 1.10。

    新增功能

    问题修复

    • 修复部分情况下读取批注内容文本不完整的问题,解决 issue #434
    • 修复由于内部合并单元格偏移量计算错误导致的部分情况下使用 RemoveRow() 删除行出现下标越界问题,解决 issue #437
    • 修复部分情况下数据验证下拉菜单中的公式失效问题
    • 修复在循环迭代中调用 Save() 方法保存导致的文档损坏问题,解决 issue #443
    • 提升文档内部 workbook.xml.rels 中相对路径格式解析的兼容性,解决 issue #442
    • 修复部分情况下,删除带有合并单元格的文档所导致的文件损坏问题
    • 修复部分情况下设置保护工作表属性失效的情况,解决 issue #454
    • 修复部分情况下 GetSheetName 获取工作表名称为空的问题, 解决 issue #457
    • 增加单元格内多行文本解析的支持, 相关 issue #464
    • 修复 32 位操作系统环境下数字溢出问题,相关 issue #386
    • 修复 go module 依赖版本不匹配问题, 相关 issue #466 和 issue #480
    • 修复部分情况下调用 SetSheetPrOptions() 所致的文档损坏问题,解决 issue #483

    性能表现

    • 性能优化,减少读取文档时的内存开销和耗时,相关 issue #439

    其他

    • 完善 SetSheetRow() 函数中的异常处理
    • 代码精简优化, 合并了下列内部函数:

    将函数 workBookRelsWriterdrawingRelsWriter 合并为 relsWriter;
    将函数 drawingRelsReaderworkbookRelsReaderworkSheetRelsReader 合并为 relsReader;
    将函数 addDrawingRelationshipsaddSheetRelationships 合并为 addRels

    [gev] 一个轻量、快速的基于 Reactor 模式的非阻塞 TCP 网络库

    惜朝 发表了文章 • 0 个评论 • 439 次浏览 • 2019-09-25 16:45 • 来自相关话题

    `gev` 是一个 ...查看全部

    `gev` 是一个轻量、快速的基于 Reactor 模式的非阻塞 TCP 网络库。

    ➡️➡️ https://github.com/Allenxuxu/gev

    特点

    - 基于 epoll 和 kqueue 实现的高性能事件循环
    - 支持多核多线程
    - 动态扩容 Ring Buffer 实现的读写缓冲区
    - 异步读写
    - SO_REUSEPORT 端口重用支持

    网络模型

    `gev` 只使用极少的 goroutine, 一个 goroutine 负责监听客户端连接,其他 goroutine (work 协程)负责处理已连接客户端的读写事件,work 协程数量可以配置,默认与运行主机 CPU 数量相同。

    性能测试

    > 测试环境 Ubuntu18.04 | 4 Virtual CPUs | 4.0 GiB

    吞吐量测试

    限制 GOMAXPROCS=1(单线程),1 个 work 协程


    限制 GOMAXPROCS=4,4 个 work 协程


    其他测试

    速度测试


    和同类库的简单性能比较, 压测方式与 evio 项目相同。
    - gnet
    - eviop
    - evio
    - net (标准库)

    限制 GOMAXPROCS=1,1 个 work 协程


    限制 GOMAXPROCS=1,4 个 work 协程


    限制 GOMAXPROCS=4,4 个 work 协程


    安装 gev


    ```bash
    go get -u github.com/Allenxuxu/gev
    ```

    快速入门


    ```go
    package main

    import (
    "log"

    "github.com/Allenxuxu/gev"
    "github.com/Allenxuxu/gev/connection"
    "github.com/Allenxuxu/ringbuffer"
    )

    type example struct{}

    func (s *example) OnConnect(c *connection.Connection) {
    log.Println(" OnConnect : ", c.PeerAddr())
    }

    func (s *example) OnMessage(c *connection.Connection, buffer *ringbuffer.RingBuffer) (out []byte) {
    log.Println("OnMessage")
    first, end := buffer.PeekAll()
    out = first
    if len(end) > 0 {
    out = append(out, end...)
    }
    buffer.RetrieveAll()
    return
    }

    func (s *example) OnClose(c *connection.Connection) {
    log.Println("OnClose")
    }

    func main() {
    handler := new(example)

    s, err := gev.NewServer(handler,
    gev.Address(":1833"),
    gev.NumLoops(2),
    gev.ReusePort(true))
    if err != nil {
    panic(err)
    }

    s.Start()
    }
    ```

    Handler 是一个接口,我们的程序必须实现它。

    ```go
    type Handler interface {
    OnConnect(c *connection.Connection)
    OnMessage(c *connection.Connection, buffer *ringbuffer.RingBuffer) []byte
    OnClose(c *connection.Connection)
    }

    func NewServer(handler Handler, opts ...Option) (server *Server, err error) {
    ```

    在消息到来时,gev 会回调 OnMessage ,在这个函数中可以通过返回一个切片来发送数据给客户端。

    ```go
    func (s *example) OnMessage(c *connection.Connection, buffer *ringbuffer.RingBuffer) (out []byte)
    ```

    Connection 还提供 Send 方法来发送数据。Send 并不会立刻发送数据,而是先添加到 event loop 的任务队列中,然后唤醒 event loop 去发送。

    更详细的使用方式可以参考示例:[服务端定时推送]

    ```go
    func (c *Connection) Send(buffer []byte) error
    ```

    Connection ShutdownWrite 会关闭写端,从而断开连接。

    更详细的使用方式可以参考示例:[限制最大连接数]

    ```go
    func (c *Connection) ShutdownWrite() error
    ```


    ➡️➡️ https://github.com/Allenxuxu/gev



    花了半天用go写一个带ui的redis客户端

    ownGolang 回复了问题 • 6 人关注 • 5 个回复 • 1596 次浏览 • 2019-09-18 10:17 • 来自相关话题

    go + koa = ? 一个新的web框架 goa 诞生

    nicholascao 发表了文章 • 1 个评论 • 548 次浏览 • 2019-08-08 15:52 • 来自相关话题

    ## koajs 相信绝大部分使用nodejs的开发者都知道[koa](https://koa.bootcss.com/),甚至每天都在跟koa打交道。 ## goa 最近因工作需要 ...查看全部
    ## koajs

    相信绝大部分使用nodejs的开发者都知道[koa](https://koa.bootcss.com/),甚至每天都在跟koa打交道。

    ## goa

    最近因工作需要从nodejs转到go,因此开发了一个koa for golang的web框架--goa。
    几乎一样的语法,一样基于中间件。

    github地址:[goa](https://github.com/goa-go/goa)

    demo:

    ``` golang
    package main

    import (
    "fmt"
    "time"

    "github.com/goa-go/goa"
    "github.com/goa-go/goa/router"
    )

    func logger(c *goa.Context, next func()) {
    start := time.Now()

    fmt.Printf("[%s] <-- %s %s\n", start.Format("2006-6-2 15:04:05"), c.Method, c.URL)
    next()
    fmt.Printf("[%s] --> %s %s %d%s\n", time.Now().Format("2006-6-2 15:04:05"), c.Method, c.URL, time.Since(start).Nanoseconds()/1e6, "ms")
    }

    func json(c *goa.Context) {
    c.JSON(goa.M{
    "string": "string",
    "int": 1,
    "json": goa.M{
    "key": "value",
    },
    })
    }

    func main() {
    app := goa.New()
    router := router.New()

    router.GET("/", func(c *goa.Context) {
    c.String("hello world")
    })
    router.GET("/json", json)

    app.Use(logger)
    app.Use(router.Routes())
    app.Listen(":3000")
    }
    ```
    如果觉得这个项目不错的话,请给个star给予作者鼓励,
    另外欢迎fork和加入开发团队共建。

    再次贴上地址https://github.com/goa-go/goa

    golang + qt5 开发的百度网盘不限速客户端

    peterq 发表了文章 • 1 个评论 • 634 次浏览 • 2019-07-01 15:55 • 来自相关话题

    > 百度云不限速客户端,使用golang + qt5 开发,跨平台。代码注释详细,并有附有开发文档,gopher们快来支持下吧 官网: https://github.com/peterq/pan-light ...查看全部
    > 百度云不限速客户端,使用golang + qt5 开发,跨平台。代码注释详细,并有附有开发文档,gopher们快来支持下吧

    官网: https://github.com/peterq/pan-light

    github: https://github.com/peterq/pan-light

    go游戏服务器框架

    xiaodi 发表了文章 • 1 个评论 • 554 次浏览 • 2019-06-28 21:24 • 来自相关话题

    项目地址:https://github.com/okpub/rhino 欢迎服务器爱好者入群交流,腾讯,阿里大牛在线装逼
    项目地址:https://github.com/okpub/rhino

    欢迎服务器爱好者入群交流,腾讯,阿里大牛在线装逼

    基于Golang的轻量级并发服务器框架---Zinx

    Aceld 发表了文章 • 0 个评论 • 702 次浏览 • 2019-04-18 11:48 • 来自相关话题

    # Zinx [![License](https://img.shields.io/badge/License-GPL%203.0-blue.svg)](LICENSE) [![Gitter](https://img.shields.io/badg ...查看全部
    # Zinx
    [![License](https://img.shields.io/badge/License-GPL%203.0-blue.svg)](LICENSE) [![Gitter](https://img.shields.io/badge/在线交流-Gitter-green.svg)](https://gitter.im/zinx_go/community) [![zinx详细教程](https://img.shields.io/badge/zinx详细教程-简书-red.svg)](https://www.jianshu.com/p/23d07c0a28e5) [![zinx原创书籍下载](https://img.shields.io/badge/原创书籍下载-Gitbook-black.svg)](https://legacy.gitbook.com/book/aceld/zinx/details)

    Zinx 是一个基于Golang的轻量级并发服务器框架

    ###源码地址:
    [https://github.com/aceld/zinx](https://github.com/aceld/zinx)

    ### 开发人员

    - 刘丹冰([@aceld](https://github.com/aceld))
    - 张超([@zhngcho](https://github.com/zhngcho))


    ## 一、写在前面

    我们为什么要做Zinx,Golang目前在服务器的应用框架很多,但是应用在游戏领域或者其他长链接的领域的轻量级企业框架甚少。

    设计Zinx的目的是我们可以通过Zinx框架来了解基于Golang编写一个TCP服务器的整体轮廓,让更多的Golang爱好者能深入浅出的去学习和认识这个领域。

    Zinx框架的项目制作采用编码和学习教程同步进行,将开发的全部递进和迭代思维带入教程中,而不是一下子给大家一个非常完整的框架去学习,让很多人一头雾水,不知道该如何学起。

    教程会一个版本一个版本迭代,每个版本的添加功能都是微小的,让一个服务框架小白,循序渐进的曲线方式了解服务器框架的领域。

    当然,最后希望Zinx会有更多的人加入,给我们提出宝贵的意见,让Zinx成为真正的解决企业的服务器框架!在此感谢您的关注!

    ## 二、初探Zinx架构
    ![1-Zinx框架.png](https://upload-images.jianshu.io/upload_images/11093205-21a249a83fec62e9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    ## 三、Zinx详细教程(代码教程同步更新)
    [《Zinx框架教程-基于Golang的轻量级并发服务器》](https://www.jianshu.com/p/23d07c0a28e5)

    ## 四、Zinx开发API文档

    ### 快速开始

    #### server
    基于Zinx框架开发的服务器应用,主函数步骤比较精简,最多主需要3步即可。
    1. 创建server句柄
    2. 配置自定义路由及业务
    3. 启动服务

    ```go
    func main() {
    //1 创建一个server句柄
    s := znet.NewServer()

    //2 配置路由
    s.AddRouter(0, &PingRouter{})

    //3 开启服务
    s.Serve()
    }
    ```

    其中自定义路由及业务配置方式如下:
    ```go
    import (
    "fmt"
    "zinx/ziface"
    "zinx/znet"
    )

    //ping test 自定义路由
    type PingRouter struct {
    znet.BaseRouter
    }

    //Ping Handle
    func (this *PingRouter) Handle(request ziface.IRequest) {
    //先读取客户端的数据
    fmt.Println("recv from client : msgId=", request.GetMsgID(), ", data=", string(request.GetData()))

    //再回写ping...ping...ping
    err := request.GetConnection().SendBuffMsg(0, []byte("ping...ping...ping"))
    if err != nil {
    fmt.Println(err)
    }
    }
    ```

    #### client
    Zinx的消息处理采用,`[MsgLength]|[MsgID]|[Data]`的封包格式
    ```go
    package main

    import (
    "fmt"
    "io"
    "net"
    "time"
    "zinx/znet"
    )

    /*
    模拟客户端
    */
    func main() {

    fmt.Println("Client Test ... start")
    //3秒之后发起测试请求,给服务端开启服务的机会
    time.Sleep(3 * time.Second)

    conn,err := net.Dial("tcp", "127.0.0.1:7777")
    if err != nil {
    fmt.Println("client start err, exit!")
    return
    }

    for n := 3; n >= 0; n-- {
    //发封包message消息
    dp := znet.NewDataPack()
    msg, _ := dp.Pack(znet.NewMsgPackage(0,[]byte("Zinx Client Test Message")))
    _, err := conn.Write(msg)
    if err !=nil {
    fmt.Println("write error err ", err)
    return
    }

    //先读出流中的head部分
    headData := make([]byte, dp.GetHeadLen())
    _, err = io.ReadFull(conn, headData) //ReadFull 会把msg填充满为止
    if err != nil {
    fmt.Println("read head error")
    break
    }
    //将headData字节流 拆包到msg中
    msgHead, err := dp.Unpack(headData)
    if err != nil {
    fmt.Println("server unpack err:", err)
    return
    }

    if msgHead.GetDataLen() > 0 {
    //msg 是有data数据的,需要再次读取data数据
    msg := msgHead.(*znet.Message)
    msg.Data = make([]byte, msg.GetDataLen())

    //根据dataLen从io中读取字节流
    _, err := io.ReadFull(conn, msg.Data)
    if err != nil {
    fmt.Println("server unpack data err:", err)
    return
    }

    fmt.Println("==> Recv Msg: ID=", msg.Id, ", len=", msg.DataLen, ", data=", string(msg.Data))
    }

    time.Sleep(1*time.Second)
    }
    }
    ```

    ### Zinx配置文件
    ```json
    {
    "Name":"Zinx Game",
    "Host":"0.0.0.0",
    "TcpPort":8999,
    "MaxConn":3000,
    "WorkerPoolSize":10
    }
    ```

    `Name`:服务器应用名称

    `Host`:服务器IP

    `TcpPort`:服务器监听端口

    `MaxConn`:允许的客户端链接最大数量

    `WorkerPoolSize`:工作任务池最大工作Goroutine数量


    ### I.服务器模块Server
    ```go
    func NewServer () ziface.IServer
    ```
    创建一个Zinx服务器句柄,该句柄作为当前服务器应用程序的主枢纽,包括如下功能:

    #### 1)开启服务
    ```go
    func (s *Server) Start()
    ```
    #### 2)停止服务
    ```go
    func (s *Server) Stop()
    ```
    #### 3)运行服务
    ```go
    func (s *Server) Serve()
    ```
    #### 4)注册路由
    ```go
    func (s *Server) AddRouter (msgId uint32, router ziface.IRouter)
    ```
    #### 5)注册链接创建Hook函数
    ```go
    func (s *Server) SetOnConnStart(hookFunc func (ziface.IConnection))
    ```
    #### 6)注册链接销毁Hook函数
    ```go
    func (s *Server) SetOnConnStop(hookFunc func (ziface.IConnection))
    ```
    ### II.路由模块

    ```go
    //实现router时,先嵌入这个基类,然后根据需要对这个基类的方法进行重写
    type BaseRouter struct {}

    //这里之所以BaseRouter的方法都为空,
    // 是因为有的Router不希望有PreHandle或PostHandle
    // 所以Router全部继承BaseRouter的好处是,不需要实现PreHandle和PostHandle也可以实例化
    func (br *BaseRouter)PreHandle(req ziface.IRequest){}
    func (br *BaseRouter)Handle(req ziface.IRequest){}
    func (br *BaseRouter)PostHandle(req ziface.IRequest){}
    ```


    ### III.链接模块
    #### 1)获取原始的socket TCPConn
    ```go
    func (c *Connection) GetTCPConnection() *net.TCPConn
    ```
    #### 2)获取链接ID
    ```go
    func (c *Connection) GetConnID() uint32
    ```
    #### 3)获取远程客户端地址信息
    ```go
    func (c *Connection) RemoteAddr() net.Addr
    ```
    #### 4)发送消息
    ```go
    func (c *Connection) SendMsg(msgId uint32, data []byte) error
    func (c *Connection) SendBuffMsg(msgId uint32, data []byte) error
    ```
    #### 5)链接属性
    ```go
    //设置链接属性
    func (c *Connection) SetProperty(key string, value interface{})

    //获取链接属性
    func (c *Connection) GetProperty(key string) (interface{}, error)

    //移除链接属性
    func (c *Connection) RemoveProperty(key string)
    ```


    ---
    ### 关于作者:

    作者:`Aceld(刘丹冰)`
    简书号:`IT无崖子`

    `mail`:
    [danbing.at@gmail.com](mailto:danbing.at@gmail.com)
    `github`:
    [https://github.com/aceld](https://github.com/aceld)
    `原创书籍gitbook`:
    [http://legacy.gitbook.com/@aceld](http://legacy.gitbook.com/@aceld)

    beego:在go1.10中在没设置GOPATH的情况下将不会工作

    回复

    hanchao 发起了问题 • 1 人关注 • 0 个回复 • 706 次浏览 • 2019-03-13 11:28 • 来自相关话题

    go-telnet包如何非阻塞得读

    回复

    zhougb3 发起了问题 • 1 人关注 • 0 个回复 • 519 次浏览 • 2019-03-08 18:30 • 来自相关话题

    有没有能接go的,请联系我

    回复

    Mandy 发起了问题 • 1 人关注 • 0 个回复 • 663 次浏览 • 2019-02-19 20:00 • 来自相关话题