图片验证码代码分享

开源程序pleas 回复了问题 • 3 人关注 • 2 个回复 • 136 次浏览 • 4 天前 • 来自相关话题

最后抛个砖 构想:在Goroutine上实现Actor?

技术讨论liangdas 回复了问题 • 5 人关注 • 4 个回复 • 315 次浏览 • 5 天前 • 来自相关话题

一起来总结一下 golang 的一些最佳实践

技术讨论chenhui7373 回复了问题 • 6 人关注 • 3 个回复 • 717 次浏览 • 5 天前 • 来自相关话题

小恩爱期待 gopher 的加入

招聘应聘mai_yang 发表了文章 • 1 个评论 • 426 次浏览 • 5 天前 • 来自相关话题

我们致力于打造最受欢迎的情侣应用。 服务器端开发语言为 Golang ,有意者请直接发邮件到 yangwen.yw#gmail.com 。

公司网站: https://w... 查看全部

我们致力于打造最受欢迎的情侣应用。
服务器端开发语言为 Golang ,有意者请直接发邮件到 yangwen.yw#gmail.com 。


公司网站: https://www.xiaoenai.com


坐标:深圳南山向南瑞峰创业中心(南山地铁站)


Golang 开发工程师


职位描述:



  1. 参与社交类、电商类业务服务端开发;

  2. 参与后端基础业务和底层架构设计;

  3. 参与提升系统性能和改进服务质量;

  4. 能主动对项目的改进提出想法。


职位要求:



  1. 本科及以上学历,3年以上开发经验;

  2. 熟悉Golang,具有高并发服务器开发经验(不会Golang也没关系,有大神手把手指导);

  3. 熟悉HTTP,TCP协议;

  4. 掌握MySQL,Redis或其他数据库;

  5. 良好的逻辑思维,能够独立解决问题;

  6. 有钻研精神,对技术充满热情,有强烈的主人翁意识;

  7. 有大型网站后台开发经验和性能优化经验的优先,有移动互联网后台开发经验优先;

  8. 开源爱好者优先,提供 Github、技术博客者优先。


薪资: 15k-25k

gokit不支持ETCD V3最新版本作为服务发现吗?

回复

有问必答elvin5 回复了问题 • 1 人关注 • 1 个回复 • 107 次浏览 • 5 天前 • 来自相关话题

Golang实现的IP代理池

开源程序henson 发表了文章 • 1 个评论 • 148 次浏览 • 5 天前 • 来自相关话题

采集免费的代理资源为爬虫提供有效的代理

项目地址: 查看全部

采集免费的代理资源为爬虫提供有效的代理


项目地址: https://github.com/henson/ProxyPool


1、代理池设计


  代理池由四部分组成:



  • Getter:


  代理获取接口,目前有9个免费代理源,每调用一次就会抓取这些网站最新的100个代理放入Channel,可自行添加额外的代理获取接口;



  • Channel:


  临时存放采集来的代理,通过访问稳定的网站去验证代理的有效性,有效则存入数据库;



  • Schedule:


  用定时的计划任务去检测数据库中代理IP的可用性,删除不可用的代理。同时也会主动通过Getter去获取最新代理;



  • Api:


  代理池的访问接口,提供get接口输出JSON,方便爬虫直接使用。


2、代码实现



  • Api:


  api接口相关代码,提供get接口,输出JSON;



  • Storage:


  数据库相关代码,数据库采用Mongo;



  • Getter:


  代理获取接口,目前抓取这九个网站的免费代理,当然也支持自己扩展代理接口;



  1. 快代理

  2. 代理66

  3. IP181

  4. 有代理

  5. 西刺代理

  6. guobanjia

  7. 讯代理

  8. 无忧代理

  9. Proxylist+



  • Schedule:


  定时任务,目前在main.go中以轮询方式实现,后期会改进;



  • Util:


  存放一些公共的模块、方法或函数,包含Config:读取配置文件config.json;



  • 其他文件:


  配置文件:config.json,数据库配置和代理获取接口配置;


{
"mongo": {
"addr": "mongodb://127.0.0.1:27017/",
"db": "temp",
"table": "pool"
},
"host": ":8080"
}

3、安装及使用


因为有些代理网站使用了加密页面、混淆代码等反爬技术,要正确采集到代理数据得用到 PhantomJS ,必须提前先装好。


另外,本项目用到的依赖库有:


gopkg.in/mgo.v2
github.com/PuerkitoBio/goquery
github.com/parnurzeal/gorequest
github.com/nladuo/go-phantomjs-fetcher

下载本项目:


go get -u github.com/henson/ProxyPool

然后配置好相应的config.json并启动:


go build
./ProxyPool

随机输出可用的代理:


GET http://localhost:8080/v1/ip

HTTP


随机输出HTTPS代理:


GET http://localhost:8080/v1/https

HTTPS


4、感谢


如果你喜欢本项目,请帮忙点个赞,谢谢!

北京/10年老厂招聘GO高级工程师(营销大数据企业,年内上市)

招聘应聘mikerr 回复了问题 • 3 人关注 • 3 个回复 • 988 次浏览 • 6 天前 • 来自相关话题

GoCN每日新闻(2017-05-17)

回复

文章分享astaxie 发起了问题 • 2 人关注 • 0 个回复 • 277 次浏览 • 6 天前 • 来自相关话题

用 beego手工搭建的博客 大家支持一下吧

有问必答gch 回复了问题 • 6 人关注 • 6 个回复 • 406 次浏览 • 6 天前 • 来自相关话题

GOLANG实现超时对象检测的最好理解的方式

技术讨论winlin 发表了文章 • 0 个评论 • 143 次浏览 • 6 天前 • 来自相关话题

依赖于心跳的系统,都需要超时检测。比如P2P系统中客户端每隔120秒向数据服务器发送一次数据汇总,服务器就需要维护一个超时时间。比如一个UDP服务器,在和客户端之间创建Session之后,如果没有数据包,一般会有Ping包,说明这个Session是存活的... 查看全部

依赖于心跳的系统,都需要超时检测。比如P2P系统中客户端每隔120秒向数据服务器发送一次数据汇总,服务器就需要维护一个超时时间。比如一个UDP服务器,在和客户端之间创建Session之后,如果没有数据包,一般会有Ping包,说明这个Session是存活的,服务器在发现Session超时后也需要清理。


首先,服务器一般需要维护一个列表,以Peer为例:


type Peer struct {
id uint64
heartbeat time.Time
}

type Server struct {
peers map[uint64]*Peer
lock sync.Mutex
}

创建Peer,同时在收到Ping消息后,更新Peer的心跳时间:


func (v *Server) Create(id uint64) *Peer {
v.lock.Lock()
defer v.lock.UnLock()

p = &Peer { id:id, heartbeat: time.Now(), }
v.peers[id] = p
return p
}

func (v *Server) OnPing(id uint64) {
v.lock.Lock()
defer v.lock.UnLock()

if p,ok := v.peers[id]; ok {
p.heatbeat = time.Now()
}
}

当然,需要起一个goroutine定期扫描这个列表, 假设300秒超时:


go func(v *Server) {
for {
func(){
v.lock.Lock()
defer v.lock.UnLock()

now := time.Now()
for id,p := range v.peers {
if p.heartbeat.Add(300 * time.Second).Before(now) {
delete(v.peers, id)
}
}
}()
time.Sleep(30 * time.Second)
}
}(server)

如果Peers的数目非常多,那么扫描时每次都需要锁定v.peers,会导致其他的业务都无法进行。特别是清理Peer这个过程如果比较复杂,譬如需要发起io请求,是一个费时的操作时,就会造成系统的等待。


一般来说,超时的Peer不会很多,因此可以用chan放一个超时的peer,每个peer专门起一个goroutine来看什么时候超时,这样就可以在检测超时时避免用锁了:


timeout := make(chan *Peer)

func (v *Server) Create(id uint64) *Peer {
v.lock.Lock()
defer v.lock.UnLock()

p = &Peer { id:id, heartbeat: time.Now(), }
v.peers[id] = p
return p

go func(p *Peer) {
for {
tm := p.heartbeat
<- time.After(300 * time.Second)
if tm.Equal(p.heartbeat) {
timeout <- p
break
}
}
}(p)
}

go func(v *Server){
for gw := range timeout {
func(){
lgateways.Lock()
defer lgateways.Unlock()

delete(gateways, gw.port)
}()

// Do something cleanup about the gateway.
}
}(server)

这样就只有在有Peer超时时,才真正锁住Server.peers

【北京丰台】--Golang工程师

招聘应聘pcy096 发表了文章 • 3 个评论 • 152 次浏览 • 2017-05-16 14:28 • 来自相关话题

岗位职责:

1.基于GO语言开发大规模分布式信息系统

任职要求:

1.熟悉golang语言编程,掌握socket、HTTP等相关技术

2.熟悉TCP、UDP协议

3.计算机相关本科或者... 查看全部

岗位职责:


1.基于GO语言开发大规模分布式信息系统


任职要求:


1.熟悉golang语言编程,掌握socket、HTTP等相关技术


2.熟悉TCP、UDP协议


3.计算机相关本科或者以上学历,1年以上工作经验


4.有分布式业务处理、大规模服务端数据处理工作经验优先,熟悉nsq、kafka消息平台中间件使用经验者优先


5.精通linux系统,熟练编写shell脚本,掌握awk的使用


6.责任心强,具备良好的团队合作精神和承受压力的能力


福利待遇:五险一金、餐补、带薪年假、弹性工作、定期体检


工作地址: 北京市方庄


有意者请把简历投到:pcy096@qq.com,请注明是GOCN看见的 ~~

go 如何优雅的实现这个面试题

有问必答loplop 回复了问题 • 9 人关注 • 9 个回复 • 624 次浏览 • 2017-05-16 10:36 • 来自相关话题

GoCN每日新闻(2017-05-16)

回复

文章分享astaxie 发起了问题 • 1 人关注 • 0 个回复 • 275 次浏览 • 2017-05-16 10:03 • 来自相关话题

为什么导入syslog包后,一直显示undefine?

有问必答voidint 回复了问题 • 2 人关注 • 1 个回复 • 100 次浏览 • 2017-05-16 09:29 • 来自相关话题

GOLANG接口适配,组合方式的灵活接口演化

技术讨论winlin 发表了文章 • 0 个评论 • 174 次浏览 • 2017-05-15 20:49 • 来自相关话题

在OO(Object Oriented)原则中,有一条叫做:优先使用组合,而不是继承。虽然GOLANG并不是OO的语言(没有继承和多态),但是不妨碍GOLANG使用这条原则,而GOLANG的作者就强调过这一点,在GOLANG中是使用组合而非继承来扩展。<... 查看全部

在OO(Object Oriented)原则中,有一条叫做:优先使用组合,而不是继承。虽然GOLANG并不是OO的语言(没有继承和多态),但是不妨碍GOLANG使用这条原则,而GOLANG的作者就强调过这一点,在GOLANG中是使用组合而非继承来扩展。


装逼的说来,继承是一种名词化的语言体系,先进行业务抽象然后设计类体系和继承关系。而组合,强制使用接口,因为组合中使用的总是另外一个对象的接口,通过动词的组合,实现目标,比如不管是什么只要有Write([]byte)(int,error)这个动作,就实现了这个接口,其他对象组合这个接口后,对外也看起来就是个io.Writer的接口。


比如,GOALNG1.8支持了writev,一般在面向对象会这么的搞:


class Socket {
int Write(void*, int);
int Writev(const iovec*, int);
};

对的吧?一个Socket可以写数据,也可以用writev写iovec向量,就是一次性写入多个内存块。



Note: 有时候内存块是不连续的,比如一个Video帧,发送给不同的客户端时,Header是需要修改的,但是Payload都一样,那么可以针对每个客户端只创建一个header,然后公用payload,但是这时候两个内存指针是不连续的,特别是需要同时写入多个视频帧时,writev就很神奇的避免了内存拷贝writev(header+payload),具体参考下writev的资料哈。



这样有个问题,并非所有系统都支持Writev的,并非所有Socket都支持Writev的,如果是自己写个代码,当然是可以随便这么搞的,但是作为标准库,GOLANG当然是不能这么做的。GOLANG就加了一个接口(一个新动作)叫做net.buffersWriter,如果实现了这个接口就用writev。先看用法:


    conn,err := net.Dial("tcp", "127.0.0.1:1935")

buffers := Buffers{
[]byte("once upon a time in "),
[]byte("Gopherland ... "),
}

buffers.WriteTo(conn)

在Buffers的WriteTo方法会判断是否是writev的接口,如果是则用writev写,否则就一个个的写:


func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) {
if wv, ok := w.(buffersWriter); ok {
return wv.writeBuffers(v)
}

实际上conn是net.TcpConn,里面有个fd *net.netFD,它实现了net.buffersWriter接口,所以最后调用的就是(fd *netFD) writeBuffers(v *Buffers)


func (c *conn) writeBuffers(v *Buffers) (int64, error) {
n, err := c.fd.writeBuffers(v)

func (fd *netFD) writeBuffers(v *Buffers) (n int64, err error) {
iovecs = append(iovecs, syscall.Iovec{Base: &chunk[0]})
wrote, _, e0 := syscall.Syscall(syscall.SYS_WRITEV,
uintptr(fd.sysfd),
uintptr(unsafe.Pointer(&iovecs[0])),
uintptr(len(iovecs)))

对于其他没有实现这个接口的对象,就每个向量循环的写。


在看一个例子http.Get(url string),客户端发起一个HTTP请求:


http.Get("http://localhost:1985/api/v1/versions")
// 实际上调用的是:
func (c *Client) Get(url string)
// 然后调用:
(c *Client) Do(req *Request)

在GOLANG1.7中引入了context的概念,用来支持cancel,怎么用的:


ctx,cancel := context.WithCancel(context.Background())

select {
case <- ctx.Done():
// Cancelled.
case <- time.After(...):
// Timeout
case <- other events:
// Other events.
}

如何支持取消的HTTP请求呢?给http.Get加个ctx参数?例如http.Get(ctx, url)这样?那改动得多大啊,而且还不能兼容之前的API,泪奔~看看GOLANG的解决:


ctx,cancel := context.WithCancel(context.Background())
go func(){
req,err := http.NewRequest("http://...")
res,err := http.DefaultClient.Do(req.WithContext(ctx))
defer res.Body.Close()
// 读取res响应结果。
}()

select {
case <- ctx.Done():
case <- time.After(3 * time.Second):
cancel() // Timeout to cancel all requests.
}

使用组合,通过req.WithContext再返回一个*http.Request,实现同样的目的。