什麼是粘包php
一個完成的消息可能會被TCP拆分紅多個包進行發送,也有可能把多個小的包封裝成一個大的數據包發送,這個就是TCP的拆包和封包問題git
TCP粘包和拆包產生的緣由服務器
應用程序寫入數據的字節大小大於套接字發送緩衝區的大小併發
進行MSS大小的TCP分段。MSS是最大報文段長度的縮寫。MSS是TCP報文段中的數據字段的最大長度。數據字段加上TCP首部纔等於整個的TCP報文段。因此MSS並非TCP報文段的最大長度,而是:MSS=TCP報文段長度-TCP首部長度tcp
以太網的payload大於MTU進行IP分片。MTU指:一種通訊協議的某一層上面所能經過的最大數據包大小。若是IP層有一個數據包要傳,並且數據的長度比鏈路層的MTU大,那麼IP層就會進行分片,把數據包分紅託乾片,讓每一片都不超過MTU。注意,IP分片能夠發生在原始發送端主機上,也能夠發生在中間路由器上。大數據
TCP粘包和拆包的解決策略.net
參考(http://blog.csdn.net/initphp/article/details/41948919)code
咱們的處理方式server
解決粘包問題有多種多樣的方式, 咱們這裏的作法是:blog
在實驗環境中的主文件夾內, 新建一個名爲codec的文件夾在其之下新建一個文件codec.go, 將咱們的Encode和Decode方法寫入其中, 這裏給出Encode與Decode相應的代碼:
codec.go
package codec import ( "bufio" "bytes" "encoding/binary" ) func Encode(message string) ([]byte, error) { // 讀取消息的長度 var length int32 = int32(len(message)) var pkg *bytes.Buffer = new(bytes.Buffer) // 寫入消息頭 err := binary.Write(pkg, binary.LittleEndian, length) if err != nil { return nil, err } // 寫入消息實體 err = binary.Write(pkg, binary.LittleEndian, []byte(message)) if err != nil { return nil, err } return pkg.Bytes(), nil } func Decode(reader *bufio.Reader) (string, error) { // 讀取消息的長度 lengthByte, _ := reader.Peek(4) lengthBuff := bytes.NewBuffer(lengthByte) var length int32 err := binary.Read(lengthBuff, binary.LittleEndian, &length) if err != nil { return "", err } if int32(reader.Buffered()) < length+4 { return "", err } // 讀取消息真正的內容 pack := make([]byte, int(4+length)) _, err = reader.Read(pack) if err != nil { return "", err } return string(pack[4:]), nil }
這裏就不帖服務器與客戶端的調用代碼了, 同窗們本身動手試試~
相關源碼: https://git.oschina.net/victoriest/go-simple-tcp-server.git