A go mini-network library

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

The Go Language Infrastructure provides great convenience for writing network programs. A high-performance, stable asynchronous network program can be written with a small amount of code.
This article describes a mini, event callback-based asynchronous network library.

Let's start with a brief introduction to the concurrency model.

Go provides a goroutine-based synchronization network interface, so you can create a separate goroutine for each network connection to receive network data. This goroutine is the execution of a dead loop, constant recv data, Unpack and then send the complete logical package to a unique Chan for each connection for logical consumption.

In addition to the network receive Goroutine, each connection also has a special goroutine that handles logic messages, and its job is to constantly extract the logical packets from the associated Chan and process them.

Similar to the previous Chuck-lua, in order to allow users to easily customize their own package structure, I provide the abstraction of packet and decoder.

Packet.go

package packetconst (    RAWPACKET = 1    RPACKET   = 2    WPACKET   = 3    EPACKET   = 4)type Packet interface{    MakeWrite()(*Packet)    MakeRead() (*Packet)    Clone()    (*Packet)    PkLen()    (uint32)    DataLen()  (uint32)    Buffer()   (*ByteBuffer)    GetType()  (byte)}

Decoder.go

Package Packetimport ("NET" "Encoding/binary" "FMT" "Io") var (errpackettoolarge = Fmt. Errorf ("Packet too Large") erreof = Fmt. Errorf ("Eof")) type Decoder interface{dorecv (Conn net. Conn) (packet,error)}type rpacketdecoder struct{maxpacket uint32}func newrpacketdecoder (maxpacket uint32) ( Rpacketdecoder) {return Rpacketdecoder{maxpacket:maxpacket}}func (this rpacketdecoder) dorecv (Conn net. Conn) (Packet,error) {header: = make ([]byte,4) n, err: = Io. Readfull (Conn, header) if n = = 0 && Err = = Io. EOF {return nil,erreof}else if err! = Nil {return Nil,err} size: = Binary. Littleendian.uint32 (header) If size > This.maxpacket {return nil,errpackettoolarge} buf: = Make ([]byt e,size+4) Copy (buf[:],header[:]) n, err = io. Readfull (conn,buf[4:]) if n = = 0 && Err = = Io. EOF {return nil,erreof}else if err! = Nil {return Nil,err} return Newrpacket (NewbuffeRbybytes (buf, (UInt32) (Len (BUF))), Nil}type Rawdecoder struct{}func newrawdecoder () (Rawdecoder) {return rawdecoder{} }func (This rawdecoder) dorecv (Conn net. Conn) (packet,error) {buff: = make ([]byte,4096) N,err: = Conn.read (buff) if n = = 0 && Err = = Io. EOF {return nil,erreof}else if err! = Nil {return Nil,err} return Newrawpacket (newbufferbybytes (Buff, (UInt32) (n))), nil}

There are 2 types of packages built in, namely Rawpacket,rpacket/wpacket.

Rawpacket is actually the raw binary data stream, without distinguishing between logical boundaries.

The Rpacket/wpacket provides a 4-byte header with a binary flow packet structure.

Eventpacket is used as an internal use, and is currently used to communicate to logic that the connection is closed, errors, and so on.

The following is the core part of the entire network library, Tcpsession, which provides processing of TCP connections.

Package Tcpsessionimport ("NET" packet "Kendynet-go/packet" "FMT") var (errunpackerror = FMT.E Rrorf ("Tcpsession:unpackerror") Errsendclose = Fmt. Errorf ("Send Close") Errsocketclose = Fmt. Errorf ("socket Close")) type tcpsession struct{Conn net. Conn Packet_que Chan Packet. Packet decoder Packet. Decoder socket_close BOOL UD Interface{}}func (this *tcpsession) Setud (UD interface{}) {This.ud = Ud}fu NC (This *tcpsession) Ud () (interface{}) {return This.ud}func Dorecv (session *tcpsession) {for{P,err: = Sessi ON.DECODER.DORECV (session. Conn) if session.socket_close{break} if err! = Nil {session. Packet_que <-Packet. Neweventpacket (ERR) break} session. Packet_que <-P} close (session. Packet_que)}func processsession (tcpsession *tcpsession,decoder Packet. Decoder, Process_packet func (*tcpsession,packEt.    Packet,error)) (error) {if tcpsession.socket_close{return errsocketclose} Tcpsession.decoder = Decoder Go Dorecv (tcpsession) for{Msg,ok: = <-tcpsession. Packet_que if!ok {//log error return nil} if Packet. Epacket = = Msg. GetType () {Process_packet (tcpsession,nil,msg) (packet. Eventpacket).            GetError ())}else{Process_packet (Tcpsession,msg,nil)} if tcpsession.socket_close{ Return nil}}}func newtcpsession (conn net. Conn) (*tcpsession) {session: = new (Tcpsession) session. Conn = Conn session. Packet_que = Make (chan Packet. packet,1024) Session.socket_close = False return Session}func (this *tcpsession) Send (WPK Packet. Packet) (Error) {if this.socket_close{return errsocketclose} idx: = (UInt32) (0) for{Buff: = W Pk. Buffer (). Bytes () End: = WPK. Pklen () N,err: = this.      Conn.write (Buff[idx:end])  If err! = Nil | |            N < 0 {return errsendclose} idx + = (UInt32) (n) if IDX >= (UInt32) (end) { Break}} return Nil}func (this *tcpsession) Close () {if this.socket_close{return} THIS.SOC Ket_close = True this. Conn.close ()}

The code is very brief only 100 lines out of the point, here key place when, Dorecv,send and processsession three functions.

What DORECV do is keep calling decoder. DORECV extracts the network packets from the network and writes them to the Packet_que.

The Send function guarantees that the data to be sent is written to the Neihu buffer or the error is returned.

Processsession is the core of the entire library, and after receiving a new connection, call Processsession with the new connection as a parameter. Callback functions provided by the consumer are called back when a network packet arrives or is faulted. From the implementation it is just simple to create a goroutine execution dorecv, and then in a for loop constantly read the arrival network packet and then call the callback function.

Here is an example of use, for more examples please refer to: https://github.com/sniperHW/kendynet-go

  Package Mainimport ("NET" tcpsession "kendynet-go/tcpsession" Packet "Kendynet-go/packet" "FMT") fun C Main () {service: = ": 8010" tcpaddr,err: = Net. RESOLVETCPADDR ("TCP4", service) if err! = nil{FMT. Printf ("Resolvetcpaddr")} listener, err: = Net. LISTENTCP ("TCP", TCPADDR) if err! = nil{FMT. Printf ("Listentcp")} for {conn, err: = Listener. Accept () if err! = Nil {Continue} session: = Tcpsession. Newtcpsession (conn) fmt. PRINTF ("A client comming\n") go tcpsession. Processsession (Session,packet. Newrawdecoder (), Func (Session *tcpsession. TCPSESSION,RPK packet. Packet,errno error) {if rpk = = nil{FMT. Printf ("%s\n", errno) session. Close () return} session. Send (RPK)})}}  
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.