go語言網路程式設計 TCP程式設計

2021-10-11 08:19:42 字數 2942 閱讀 2850

一. tcp socket程式設計

go的tcp服務端流程分為三步:

(1)監聽埠

(2)接收客戶端請求連線,返回conn

(3)建立goroutine處理請求

乙個例項如下:

tcp服務端

package main

import (

"fmt"

"net"

"bufio"

)func process(conn net.conn)

recvstr := string(buf[:n])

fmt.println("收到client端發來的資料:", recvstr)

conn.write(byte(recvstr)) //傳送資料 }}

func main()

for

go process(conn) //啟動goroutine處理連線

}}

tcp客戶端

package main

import (

"net"

"fmt"

"bufio"

"os"

"strings"

)func main()

defer conn.close()

inputreader := bufio.newreader(os.stdin)

for

_, err := conn.write(byte(inputinfo))

if err != nil

buf := [512]byte{}

n, err := conn.read(buf[:])

if err != nil

fmt.println(string(buf[:n]))

}}

以上**可實現乙個服務端與多個客戶端的通訊

二、 tcp粘包

產生原因:tcp資料傳遞模式是流模式,在保持長連線的時候可以進行多次的收和發

「粘包」可發生在傳送端也可發生在接收端:

1.由nagle演算法造成的傳送端的粘包:nagle演算法是一種改善網路傳輸效率的演算法。簡單來說就是當我們提交一段資料給tcp傳送時,tcp並不立刻傳送此段資料,而是等待一小段時間看看在等待期間是否還有要傳送的資料,若有則會一次把這兩段資料傳送出去。

2.接收端接收不及時造成的接收端粘包:tcp會把接收到的資料存在自己的緩衝區中,然後通知應用層取資料。當應用層由於某些原因不能及時的把tcp的資料取出來,就會造成tcp緩衝區中存放了幾段資料。

解決辦法:

出現」粘包」的關鍵在於接收方不確定將要傳輸的資料報的大小,因此我們可以對資料報進行封包和拆包的操作。

封包:封包就是給一段資料加上包頭,這樣一來資料報就分為包頭和包體兩部分內容了(過濾非法包時封包會加入」包尾」內容)。包頭部分的長度是固定的,並且它儲存了包體的長度,根據包頭長度固定以及包頭中含有包體長度的變數就能正確的拆分出乙個完整的資料報。

我們可以自己定義乙個協議,比如資料報的前4個位元組為包頭,裡面儲存的是傳送的資料的長度。

自定義編譯碼proto.go

package proto

import (

"bufio"

"bytes"

"encoding/binary"

)func encode(message string) (byte, error)

//寫入訊息實體

err = binary.write(pkg, binary.littleendian, byte(message))

if err != nil

return pkg.bytes(), nil

}func decode(reader *bufio.reader) (string, error)

if int32(reader.buffered()) < length + 4

//讀取真正的資料

pack := make(byte, int(length+4))

_, err = reader.read(pack)

if err != nil

return string(pack[4:]), nil

}

tcp服務端**server\main.go

package main

import (

"awesomeproject/proto"

"bufio"

"fmt"

"io"

"net"

)func process(conn net.conn)

if err != nil

fmt.println("the message receive from client is: ", msg) }}

func main()

defer listen.close()

for

go process(conn)

}}

tcp客戶端**client\main.go

package main

import (

"fmt"

"net"

"awesomeproject/proto"

"strconv"

)func main()

fmt.println("已與伺服器建立連線……")

defer conn.close()

for i := 0; i < 20; i++

conn.write(encode_msg)

}}

伺服器端收到的資料如下,可以看到,使用封包加解包策略後,不再發生粘包現象

go語言網路程式設計之tcp

go語言網路程式設計之tcp go語言網路程式設計需要匯入包 net如下 import fmt net 重要函式 func listen net,laddr string listener,error func accept cconn,errerror func read b byte n int...

GO語言TCP程式設計正規化

一直用go編寫tcp http websocket伺服器,得空總結一些簡單的正規化,供參考。在github上都可以看到。之前用c 寫tcp server,一般兩種模式 1個listener執行緒 n個processor執行緒 通過reuseport機制,n個listener執行緒,tcp包的處理可以...

go語言網路程式設計

go語言的defer,你真的懂了嗎?這篇文章通過幾個生動的例子闡述了go語言當中return的執行順序和原理,也解答了為什麼defer明明執行在return之前,但是看起來卻是在return之後進行的 package main import net fmt func main else else e...