Commit 23196e55 authored by alexstocks's avatar alexstocks

network lib in golang

parent f938af14
# getty # getty #
*a netty like asynchronous network I/O library* ---
*a netty like asynchronous network I/O library*
## introdction ##
---
> DESC : a asynchronous network I/O library in golang
LICENCE : Apache License 2.0
AUTHOR : https://github.com/sanbit
MAINTAINER : Alex Stocks
EMAIL : alexstocks@foxmail.com
## develop history ##
---
- 2016/08/22
> rename (Session)OnIdle to (Session)OnCron
> rewrite server.go: add Server{done, wg}
> add utils.go
> version: 0.2.03
- 2016/08/21
> add name for Session
> add OnError for Codec
- 2016/08/18
> delete last clause of handleRead
> add reqQ handle case in last clause of handleLoop
> add conditon check in (*Session)RunEventLoop()
> version: 0.2.02
- 2016/08/16
> rename all structs
> add getty connection
> rewrite (Session)handleRead & (Session)handleEventLoop
> version: 0.2.01
/******************************************************
# DESC : codec interface
# MAINTAINER : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-08-17 11:20
# FILE : codec.go
******************************************************/
package getty
import (
"bytes"
)
// Reader is used to unmarshal a complete pkg from buffer
type Reader interface {
// Parse pkg from buffer and if possible return a complete pkg
Read(*Session, *bytes.Buffer) (interface{}, error)
}
// Writer is used to marshal pkg and write to session
type Writer interface {
Write(*Session, interface{}) error
}
// packet handler interface
type ReadWriter interface {
Reader
Writer
}
// EventListener is used to process pkg that recved from remote session
type EventListener interface {
// invoked when session opened
OnOpen(*Session)
// invoked when session closed
OnClose(*Session)
// invoked when got error
OnError(*Session, error)
// invoked periodically, its period can be set by (Session)SetCronPeriod
OnCron(*Session)
// invoked when receive packge. Pls attention that do not handle long time logic processing in this func.
OnMessage(*Session, interface{})
}
/******************************************************
# DESC : getty server
# MAINTAINER : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-08-17 11:21
# FILE : server.go
******************************************************/
package getty
import (
"errors"
"net"
"sync"
"time"
)
import (
log "github.com/AlexStocks/log4go"
)
type SessionCallback func(*Session)
type Server struct {
// net
host string
port int
listener net.Listener
sync.Once
done chan struct{}
wg sync.WaitGroup
}
func NewServer() *Server {
return &Server{done: make(chan struct{})}
}
func (this *Server) stop() {
select {
case <-this.done:
return
default:
close(this.done)
this.Once.Do(func() {
// 把listener.Close放在这里,既能防止多次关闭调用,
// 又能及时让Server因accept返回错误而从RunEventloop退出
this.listener.Close()
})
}
}
func (this *Server) IsClosed() bool {
select {
case <-this.done:
return true
default:
return false
}
return false
}
func (this *Server) Bind(network string, host string, port int) error {
if port <= 0 {
return errors.New("port<=0 illegal")
}
this.host = host
this.port = port
listener, err := net.Listen(network, HostAddress(host, port))
if err != nil {
return err
}
this.listener = listener
return nil
}
func (this *Server) RunEventloop(newSessionCallback func(*Session)) {
this.wg.Add(1)
go func() {
defer this.wg.Done()
var (
err error
client *Session
delay time.Duration
)
for {
if this.IsClosed() {
log.Warn("Server{%s:%d} stop acceptting client connect request.", this.host, this.port)
return
}
if delay != 0 {
time.Sleep(delay)
}
client, err = this.Accept(newSessionCallback)
if err != nil {
if ne, ok := err.(net.Error); ok && ne.Temporary() {
if delay == 0 {
delay = 5 * time.Millisecond
} else {
delay *= 2
}
if max := 1 * time.Second; delay > max {
delay = max
}
continue
}
log.Info("Server{%s:%d}.Accept() = err {%+v}", this.host, this.port, err)
continue
}
delay = 0
client.RunEventloop()
}
}()
}
func (this *Server) Listener() net.Listener {
return this.listener
}
func (this *Server) Accept(newSessionCallback func(*Session)) (*Session, error) {
conn, err := this.listener.Accept()
if err != nil {
return nil, err
}
session := NewSession(conn)
newSessionCallback(session)
return session, nil
}
func (this *Server) Close() {
this.stop()
this.wg.Wait()
}
This diff is collapsed.
/******************************************************
# DESC : getty utility
# AUTHOR : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-08-22 17:44
# FILE : utils.go
******************************************************/
package getty
import (
"bytes"
"encoding/binary"
"net"
"strconv"
"time"
)
func HostAddress(host string, port int) string {
return net.JoinHostPort(host, strconv.Itoa(port))
}
func dial(addr string) (net.Conn, error) {
return net.Dial("tcp", addr)
}
func dialTimeout(addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout("tcp", addr, timeout)
}
////////////////////////////////////////
// enc/dec
////////////////////////////////////////
func Int2Bytes(x int32) []byte {
var buf = bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, x)
return buf.Bytes()
}
func Bytes2Int(b []byte) int32 {
var (
x int32
buf *bytes.Buffer
)
buf = bytes.NewBuffer(b)
binary.Read(buf, binary.BigEndian, &x)
return x
}
/******************************************************
# DESC : getty version
# MAINTAINER : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-08-17 11:23
# FILE : version.go
******************************************************/
package getty
var (
Version = "0.2.03"
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment