64 lines of code to implement 0 copy of Go TCP unpacking sticky pack
Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed. # 64 lines of code to implement 0 copy go tcp unpacking Sticky bag # # # Preface this time want to write a simple IM system with go, think about the go language TCP unpacking sticky packet. There are generally three solutions for the removal of packets from TCP. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # The length of the message content can be transmitted using binary, high efficiency, recommended. Let's see how it's implemented. # # # Try to use the bytes that comes with the system library. Buffer Implementation code implementation: "' Gopackage tcpimport (" FMT "" Net "" Log "" bytes "" Encoding/binary ") const (bytes_size uint16 = 1024head_ SIZE int = 2) func startserver (address string) {listener, err: = Net. Listen ("TCP", address) if err! = Nil {log. Println ("Error listening", err.) Error ()) return}for {conn, err: = Listener. Accept () fmt. PRINTLN (Conn. REMOTEADDR ()) if err! = Nil {fmt. Println ("Error accepting", err.) Error ()) return//Termination program}go DOCONN (conn)}}func Doconn (conn net. Conn) {var (buffer = bytes. Newbuffer (Make ([]byte, 0, bytes_size)) BYTES = make ([]byte, bytes_size); ishead bool = truecontentsize Inthead = make ([]byt E, head_size) content = Make ([]byte, Bytes_size)) for {Readlen, err: = conn. Read (bytes); if err! = Nil {log. Println ("Error reading", err.) Error ())Return}_, err = buffer. Write (Bytes[0:readlen]) if err! = Nil {log. Println ("Error Writing to Buffer", err. Error ()) Return}for {if Ishead {if buffer. Len () >= Head_size {_, Err: = buffer. Read (head) if err! = Nil {fmt. Println ("Error reading", err.) Error ()) return}contentsize = int (binary). Bigendian.uint16 (head)) Ishead = false} else {break}}if!ishead {if buffer. Len () >= Contentsize {_, Err: = buffer. Read (Content[:contentsize]) if err! = Nil {fmt. Println ("Error reading", err.) Error ()) return}fmt. Println (String (content[:contentsize))) Ishead = true} else {break}}}} "' Test case: ' ' Gopackage tcpimport (" Testing "" NET "" FMT "" Encoding/binary ") func teststartserver (t *testing. T) {startserver ("localhost:50002")}func testclient (t *testing. T) {conn, err: = Net. Dial ("TCP", "localhost:50002") if err! = Nil {fmt. Println ("Error dialing", err.) Error ()) return//Termination program}var headsize Intvar headbytes = make ([]byte, 2) s: = "Hello world" content: = []byte (s) headsize = Len (content) binary. Bigendian.putuint16 (Headbytes, UInt16 (headsize)) Conn. Write (headbytes) Conn. Write (content) s = "Hello go" content = []byte (s) headsize = len (content) binary. Bigendian.putuint16 (Headbytes, UInt16 (headsize)) Conn. Write (headbytes) Conn. Write (content) s = "Hello tcp" content = []byte (s) headsize = len (content) binary. Bigendian.putuint16 (Headbytes, UInt16 (headsize)) Conn. Write (headbytes) Conn. Write (content)} ' execution result ' ' 127.0.0.1:51062hello worldhello gohello tcp ' with Go system library buffer, is not feel code particularly awkward, Two major drawbacks 1. Write a large amount of logic code to compensate for the non-applicability of the buffer to this scenario. 2. Performance is not high, there are three times memory copy, Coon->[]byte->buffer->[]byte. # # # own realization since the wheel is not suitable, you build the wheel, the first to achieve a own buffer, very simple, only more than 60 lines of code, all processes only one copy of the byte array, Conn->buffer, the rest of the operation is in the original buffer byte array operation "' Gopackage tcpimport (" Errors "" IO ") type buffer struct {reader IO. Readerbuf []bytestart intend Int}func newbuffer (reader io. Reader, Len int) buffer {buf: = make ([]byte, Len) return Buffer{reader, buf, 0, 0}}func (b *buffer) len () int {return b.end -b.start}//to move useful bytes forward Func (b *buffer) grow () {if B.start = = 0 {return}copy (b.buf, B.buf[b.start:b.end]) b.end-= B.staRtb.start = 0;} Read data from reader, if reader is blocked, there will be blocking func (b *buffer) Readfromreader () (int, error) {B.grow () n, err: = B.reader.read (b.buf[ B.end:]) if (err! = nil) {return n, err}b.end + = Nreturn N, nil}//returns n bytes without generating a shift func (b *buffer) Seek (n int) ([]byte, error) {if B.end-b.start >= n {buf: = B.buf[b.start:b.start+n]return buf, Nil}return Nil, errors. New ("Not Enough")}//discards the offset field, reads N fields func (b *buffer) read (offset, n int) ([]byte) {B.start + = Offsetbuf: = B.buf[b.start : B.start+n]b.start + = Nreturn buf} "and look at how to use it, and change the Doconn function above. "' Gofunc doconn (conn net. Conn) {var (buffer = Newbuffer (Conn, +) headbuf []bytecontentsize intcontentbuf []byte] for {_, Err: = Buffer.readfromreade R () If Err! = Nil {fmt. PRINTLN (Err) return}for {headbuf, err = Buffer.seek (head_size); if err! = Nil {break}contentsize = int (binary). Bigendian.uint16 (HEADBUF)) if (buffer. Len () >= contentsize-head_size) {contentbuf = Buffer.read (head_size, contentsize) fmt. Println (String (CONTENTBUF)) Continue}break}} ' ' Run down the test case and look at the result '' 127.0.0.1:51062hello worldhello Gohello TCP ' Source address: Https://github.com/alberliu/goim You have a better way to email me, alber_ Liu@qq.com, let me learn. 1875 views ∙ 2 likes
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.