In the previous chapter we made a most basic demo, we can initially realize the information between the server and the client exchange of ~ This chapter I will explain how to implement a simple communication protocol between server and client, thus enhancing the stability of the whole information communication process.
In the interaction between server and client, it is sometimes difficult to avoid the network fluctuations, and when the quality of communication is poor, the client may not be able to send the flow of information to complete one time, eventually uploading to the server is likely to become many segments.
As shown, it should be a sub-stripe of the JSON, the result for some reason connected together, this time there will be problems, the server side how to determine whether the message received is complete? ~
Well, the answer is the subject of this article: when the server interacts with the client, add a communication protocol (protocol) that allows the interaction of the two to be encapsulated by this protocol, allowing the server to determine whether the received information is a complete paragraph. (i.e. to solve the problem of subcontracting)
Because the main purpose is to allow the server to determine whether the information sent by the client is complete, the core idea of the entire protocol is not very complex:
the core of the protocol is to design a head (headers) that encapsulates the header each time the client sends a message, and then allows the server to parse the message in a predetermined format each time it receives the message, depending on whether the data from the client contains headers, it is easy to determine whether the information received is complete ~
If the information is complete, the message is sent to the next logic for processing, and if the information is incomplete (missing headers), then the server will merge this information with the previous information to continue processing.
The following is the protocol part of the code, mainly divided into data encapsulation (Enpack) and parsing (depack) two parts, where Enpack for the client side will be passed to the server data encapsulation, and Depack is used by the server to parse the data, Where the const section is used to define headers,headerlength is the length of the headers for subsequent server-side parsing. Here's the Constmlength, which represents the length of the incoming message for the client, because in Golang, the int goes to byte and takes up 4 of the length of space, so it is set to 4. Each time the client sends a message to the server, the length of the incoming information is also encapsulated in addition to the headers encapsulation, which makes it easier for the server to parse and verify.
Communication protocol Processing Package Protocolimport ("bytes" "Encoding/binary") const (Constheader = "Headers" constheaderlength = 7Cons Tmlength = 4)//packet func enpack (message []byte) []byte {return append (append ([]byte (Constheader), inttobytes (LEN (message) ) ...), message ...)} Unpacking func depack (buffer []byte, Readerchannel Chan []byte) []byte {length: = Len (buffer) var i intfor i = 0; i < length; i = i + 1 {if length < I+constheaderlength+constmlength {break}if string (buffer[i:i+constheaderlength]) = = Constheader {messagelength: = Bytestoint (Buffer[i+constheaderlength:i+constheaderlength+constmlength]) if length < i+ constheaderlength+constlength+messagelength {break}data: = buffer[i+constheaderlength+constmlength:i+ Constheaderlength+constmlength+messagelength]readerchannel <-data}}if i = = length {return make ([]byte, 0)}return buffer[i:]}//shaping translates into byte func inttobytes (n int) []byte {x: = Int32 (n) Bytesbuffer: = bytes. Newbuffer ([]byte{}) binary. Write (Bytesbuffer, Binary. Bigendian, X) return Bytesbuffer. Bytes ()}//bytes are converted to reshape func bytestoint (b []byte) int {bytesbuffer: = Bytes. Newbuffer (b) var x int32binary. Read (Bytesbuffer, Binary. Bigendian, &x) return int (x)}
After the protocol is written, the next step is to apply the protocol in the server and client code, which is the server-side code that is primarily responsible for parsing the information flow that the client sends through the protocol:
Package main import ("protocol" "FMT" "NET" "OS") Func main () {netlisten, err: = Net. Listen ("TCP", "localhost:6060") checkerror (Err) defer netlisten.close () Log ("Waiting for Clients") For {conn, err: = Netlisten.accept () if err! = nil {Continue}//tim Eousec: =10//conn. LOG (Conn. Remoteaddr (). String (), "TCP Connect Success") go Handleconnection (conn)}} func handleconnection (conn net. Conn) {//buffer, store truncated data tmpbuffer: = Make ([]byte, 0)//Receive unpack Readerchannel: = Make (chan []byte, 1 6) Go Reader (readerchannel) Buffer: = Make ([]byte, 1024x768) for {n, err: = conn. Read (buffer) if err! = Nil {LOG (conn. Remoteaddr (). String (), "Connection error:", err) return} tmpbuffer = protocol. Depack (Append (Tmpbuffer, buffer[:n] ...), Readerchannel)} defer conn. Close ()}Func Reader (Readerchannel Chan []byte) {for {select {case data: = <-readerchannel: Log (string Data)}}} func Log (v. ... interface{}) {FMT. Println (v ...) } func checkerror (err error) {if err! = Nil {fmt. fprintf (OS. Stderr, "Fatal Error:%s", err. Error ()) OS. Exit (1)}}
then the client side of the code, this is much simpler, as long as the information to encapsulate it can be ~:
Package main import ("protocol" "FMT" "NET" "OS" "Time" "StrConv") func Send (conn net. Conn) {for i: = 0; i <; i++ {session:=getsession () words: = "{\" id\ ":" + StrConv. Itoa (i) + "\", \ "session\": "+session +" 2015073109532345\ ", \" meta\ ": \" golang\ ", \" content\ ": \" Message\ "}" conn. Write (protocol. Enpacket ([]byte (words))} fmt. PRINTLN ("Send Over") defer Conn. Close ()} func getsession () string{gs1:=time. Now (). Unix () Gs2:=strconv. Formatint (gs1,10) return GS2} func main () {server: = "localhost:6060" tcpaddr, err: = Net. RESOLVETCPADDR ("TCP4", server) if err! = Nil {fmt. fprintf (OS. Stderr, "Fatal Error:%s", err. Error ()) OS. Exit (1)} conn, err: = Net. DIALTCP ("TCP", nil, tcpaddr) if err! = Nil {fmt. fprintf (OS. Stderr, "Fatal Error:%s", err. Error ()) OS. Exit (1)} FMT. PRINTLN ("Connect Success") Send (conn)}
So that we can successfully implement a set of custom basic communication protocols between server and client let's run a look at the effect:
successful identification of each client sent the message ~ ~
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
[Golang] Starting from scratch socket Server (2): Custom Communication protocol