国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Golang實(shí)現(xiàn)之TCP長(zhǎng)連接-------服務(wù)端和客戶端

這篇具有很好參考價(jià)值的文章主要介紹了Golang實(shí)現(xiàn)之TCP長(zhǎng)連接-------服務(wù)端和客戶端。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

一、數(shù)據(jù)包的數(shù)據(jù)結(jié)構(gòu) (所有字段采用大端序)

幀頭

幀長(zhǎng)度(頭至尾)

幀類(lèi)型

幀數(shù)據(jù)

幀尾

1字節(jié)

4字節(jié)

2字節(jié)

1024字節(jié)

1字節(jié)

byte

int

short

string

byte

0xC8

0xC9

二、Server端?實(shí)現(xiàn)代碼

1、main.go

func main() {

	logconfig.InitLogger()//初始化日志庫(kù),日志庫(kù)實(shí)現(xiàn)可以查閱: 
   https://blog.csdn.net/banzhuantuqiang/article/details/131403454


	//開(kāi)啟tcp server
	logconfig.SugarLogger.Info("server端啟動(dòng)中...")
	ip := "0.0.0.0"
	port := 10302
	

	go func() {
		
		server.Start(ip, port)
	}()


	logconfig.SugarLogger.Info("server端啟動(dòng)完成")

	for {
		logconfig.SugarLogger.Info("server端主進(jìn)程活躍")
		time.Sleep(5 * time.Second)
	}

}

2、server.go

//啟動(dòng)TCP服務(wù)端
func Start(ip string, port int) (bool, error) {
var ClinetConn net.Conn = nil
	//1:?jiǎn)⒂帽O(jiān)聽(tīng)
	listener, err := net.Listen("tcp", ip+":"+strconv.Itoa(port))
	//連接失敗處理
	if err != nil {
		logconfig.SugarLogger.Infof("啟動(dòng)服務(wù)失敗,err:%v", err)
		return false, err
	}

	//程序退出時(shí)釋放端口
	defer func() {
		listener.Close()
		logconfig.SugarLogger.Error("服務(wù)的退出")
	}()


	for {
		coon, err := listener.Accept() //2.建立連接
		//判斷是代理連接還是ssh連接
		reader := bufio.NewReader(coon)
	
		
			if ClinetConn != nil {
				ClinetConn.Close()
			}
			ClinetConn = coon
			if err != nil {
				logconfig.SugarLogger.Errorf("接收客戶連接失敗,err:%v", err)
				continue
			}

			logconfig.SugarLogger.Infof("接收客戶連接成功,%s", coon.RemoteAddr().String())
			
			//啟動(dòng)一個(gè)goroutine處理客戶端連接
			go process(coon, reader)
	}
}

func process(coon net.Conn, reader *bufio.Reader) {
	defer func() {
		coon.Close()
		logconfig.SugarLogger.Infof("客戶連接斷開(kāi),%s", coon.RemoteAddr().String())
	}()
	for {
		msg, err := protocol.Decode(reader, coon)
		if err != nil {
			logconfig.SugarLogger.Infof("decode失敗,err:%v", err)
			if msg.Type == 1 {
				continue
			} else {
				logconfig.SugarLogger.Errorf("客戶端連接處理異常......")
				return
			}
		}
		logconfig.SugarLogger.Infof("收到客戶端%s的消息:%v", coon.RemoteAddr().String(), msg)
		//TODO 解析數(shù)據(jù)和回應(yīng)消息,參照下面response.go
        //這里另起一個(gè)線程去解析數(shù)據(jù),一般是json數(shù)據(jù)
	}
}

3、protocol.go

const HEAD byte = 0xC8
const TAIL byte = 0xC9


func Encode(message Msg) ([]byte, error) {
	var pkg = new(bytes.Buffer)
	// 寫(xiě)入消息頭
	err := binary.Write(pkg, binary.BigEndian, message.Head)
	if err != nil {
		return nil, err
	}
	// 寫(xiě)入長(zhǎng)度
	err = binary.Write(pkg, binary.BigEndian, message.Length)
	if err != nil {
		return nil, err
	}
	// 寫(xiě)入類(lèi)型
	err = binary.Write(pkg, binary.BigEndian, message.Type)
	if err != nil {
		return nil, err
	}
	err = binary.Write(pkg, binary.BigEndian, []byte(message.Data))
	if err != nil {
		return nil, err
	}
	err = binary.Write(pkg, binary.BigEndian, message.Tail)
	if err != nil {
		return nil, err
	}
	return pkg.Bytes(), nil
}


// 解碼(這里考慮了粘包和分包問(wèn)題)
func Decode(reader *bufio.Reader, conn net.Conn) (Msg, error) {
	//|幀頭    |幀長(zhǎng)度(頭至尾)   	|幀類(lèi)型  	|幀數(shù)據(jù)    	|幀尾
	//|1字節(jié)   |4字節(jié)    			|2字節(jié)   	|1024字節(jié)  	|1字節(jié)
	//|byte   |int     			|short   	|string   	|byte
	//|0xC8   |        			|        	|         	|0xC9

	for {
		headbyte, headError := reader.ReadByte()
		if headError != nil {
			return Msg{}, headError
		} else if headbyte == HEAD {
			//已讀取到正確頭
			break
		} else {
			logconfig.SugarLogger.Infof("讀到錯(cuò)誤字節(jié):%v 錯(cuò)誤的連接地址:%s", headbyte, conn.RemoteAddr().String())
		}
	}
	// 讀消息長(zhǎng)度,不移動(dòng)位置
	lengthByte, _ := reader.Peek(4)
	lengthBuff := bytes.NewBuffer(lengthByte)
	var length int32
	//將長(zhǎng)度buff轉(zhuǎn)換為 int32,大端序
	err := binary.Read(lengthBuff, binary.BigEndian, &length)
	if err != nil {
		return Msg{Type: 1}, err
	}
	//如果消息體超過(guò) 4096(默認(rèn)長(zhǎng)度)
	var pack []byte
	if length > 4096 {
		pack = make([]byte, 0, int(length-1))
		readableLength := length - 1
		for {
			if readableLength < 4096 {
				slice := make([]byte, readableLength)
				_, err = reader.Read(slice)
				pack = append(pack, slice...)
				break
			}
			slice := make([]byte, int32(reader.Buffered()))
			_, err = reader.Read(slice)
			pack = append(pack, slice...)
			//更新可讀長(zhǎng)度
			readableLength = readableLength - int32(len(slice))
		}
		// buffer返回緩沖中現(xiàn)有的可讀的字節(jié)數(shù),2+length+1表示幀類(lèi)型+數(shù)據(jù)長(zhǎng)度+幀尾
	} else if length < 4096 && int32(reader.Buffered()) < length-1 {
		//退回已讀取的幀頭
		reader.UnreadByte()
		return Msg{Type: 1}, errors.New("數(shù)據(jù)長(zhǎng)度不足")
	} else {
		// 讀取剩余幀內(nèi)容
		pack = make([]byte, int(length-1))
		_, err = reader.Read(pack)
		if err != nil {
			return Msg{Type: 1}, err
		}
	}

	typeBuff := bytes.NewBuffer(pack[4:6])
	var msgType int16
	msgTypeErr := binary.Read(typeBuff, binary.BigEndian, &msgType)
	if msgTypeErr != nil {
		return Msg{Type: 1}, msgTypeErr
	}
	data := string(pack[6 : len(pack)-1])
	tail := pack[len(pack)-1]
	if tail != TAIL {
		reader.UnreadByte()
		return Msg{Type: 1}, errors.New("幀尾錯(cuò)誤,丟棄已讀取的字節(jié)")
	}
	msg := Msg{Head: HEAD, Length: length, Type: msgType, Data: data, Tail: TAIL}
	return msg, nil
}

type Msg struct {
	Head   byte
	Length int32
	Type   int16
	Data   string
	Tail   byte
}

4、response.go

func tcpReturn(coon net.Conn, result *dto.Result, msgType int16) {
	marshal, _ := json.Marshal(result)//這里根據(jù)定義的消息體解析成json字符串
	msg := protocol.Msg{protocol.HEAD, 8 + int32(len(marshal)), msgType, string(marshal), protocol.TAIL}
	encode, _ := protocol.Encode(msg)
	coon.Write(encode)
	logconfig.SugarLogger.Infof("結(jié)束消息處理,tpc連接:%s,回復(fù)結(jié)果:%s", coon.RemoteAddr().String(), string(encode))
}

5、result.go

type Result struct {
	DataType string `json:"data_type"`
	// 消息標(biāo)識(shí)
	CallBackKey string `json:"call_back_key"`
	// 狀態(tài)碼
	Status string `json:"status"`
	// 返回描述
	Message string `json:"message"`
	// 消息體
	Data interface{} `json:"data"`
}

三、Client端?實(shí)現(xiàn)代碼文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-730753.html

package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"net"
	"time"
)
const HEAD byte = 0xC8
const TAIL byte = 0xC9
func main() {
	
		conn, err := net.Dial("tcp", "127.0.0.1:10301")
		if err != nil {
			fmt.Println("連接服務(wù)端失敗,err:", err)
			return
		}
		conn.SetReadDeadline(time.Now().Add(100 * time.Second))

		

		strJosn:="66666"http://這里寫(xiě)自己的json字符串
		//Type 0x01  0x02.....
		message := Msg{HEAD, 8 + int32(len(strJosn)), 0x10, string(strJosn), TAIL} // 板卡ROM重置狀態(tài)查詢

		b, err := Encode(message)
		if err != nil {
			fmt.Println("Encode失敗,err:", err)
		}
		_, error := conn.Write(b)
		if error != nil {
			fmt.Println("發(fā)送失敗,err:", error)
			return
		}
		fmt.Println("發(fā)送成功...,msg:", b)
		fmt.Println("發(fā)送成功...,msg:", message)
	    parseServerResponseMesage(conn)
	
}

//服務(wù)端返回消息
func parseServerResponseMesage(coon net.Conn) {
	for {
		dataByte := make([]byte, 4096)
		n, _ := coon.Read(dataByte)
		bytes := dataByte[0:n]
		fmt.Println("收到服務(wù)端消息:", string(bytes))
	}
}


type Msg struct {
	Head   byte
	Length int32
	Type   int16
	Data   string
	Tail   byte
}

func Encode(message Msg) ([]byte, error) {
	var pkg = new(bytes.Buffer)
	// 寫(xiě)入消息頭
	err := binary.Write(pkg, binary.BigEndian, message.Head)
	if err != nil {
		return nil, err
	}
	// 寫(xiě)入長(zhǎng)度
	err = binary.Write(pkg, binary.BigEndian, message.Length)
	if err != nil {
		return nil, err
	}
	// 寫(xiě)入類(lèi)型
	err = binary.Write(pkg, binary.BigEndian, message.Type)
	if err != nil {
		return nil, err
	}
	err = binary.Write(pkg, binary.BigEndian, []byte(message.Data))
	if err != nil {
		return nil, err
	}
	err = binary.Write(pkg, binary.BigEndian, message.Tail)
	if err != nil {
		return nil, err
	}
	return pkg.Bytes(), nil
}


到了這里,關(guān)于Golang實(shí)現(xiàn)之TCP長(zhǎng)連接-------服務(wù)端和客戶端的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 服務(wù)端和客戶端通信-TCP(含完整源代碼)

    服務(wù)端和客戶端通信-TCP(含完整源代碼)

    目錄 簡(jiǎn)單TCP通信實(shí)驗(yàn) 分析 1、套接字類(lèi)型 2、socket編程步驟 3、socket編程實(shí)現(xiàn)具體思路 實(shí)驗(yàn)結(jié)果截圖 程序代碼 實(shí)驗(yàn)設(shè)備: ??? 目標(biāo)系統(tǒng):windows 軟件工具:vs2022/VC6/dev 實(shí)驗(yàn)要求: 完成TCP服務(wù)端和客戶端的程序編寫(xiě); 實(shí)現(xiàn)簡(jiǎn)單字符串的收發(fā)功能。 需附上代碼及運(yùn)行結(jié)果截圖

    2024年02月07日
    瀏覽(30)
  • SpringBoot搭建Netty+Socket+Tcp服務(wù)端和客戶端

    yml配置:? ? 完成,啟動(dòng)項(xiàng)目即可自動(dòng)監(jiān)聽(tīng)對(duì)應(yīng)端口 這里為了測(cè)試,寫(xiě)了Main方法,可以參考服務(wù)端,配置啟動(dòng)類(lèi) ,實(shí)現(xiàn)跟隨項(xiàng)目啟動(dòng) ? ......想寫(xiě)就參考服務(wù)端...... 有測(cè)試的,,,但是忘記截圖了................

    2024年02月15日
    瀏覽(25)
  • C++實(shí)現(xiàn)WebSocket通信(服務(wù)端和客戶端)

    C++實(shí)現(xiàn)WebSocket通信(服務(wù)端和客戶端)

    天行健,君子以自強(qiáng)不息;地勢(shì)坤,君子以厚德載物。 每個(gè)人都有惰性,但不斷學(xué)習(xí)是好好生活的根本,共勉! 文章均為學(xué)習(xí)整理筆記,分享記錄為主,如有錯(cuò)誤請(qǐng)指正,共同學(xué)習(xí)進(jìn)步。 這里單純是個(gè)人總結(jié),如需更官方更準(zhǔn)確的websocket介紹可百度 websocket是一種即時(shí)通訊協(xié)

    2024年02月09日
    瀏覽(19)
  • Socket實(shí)例,實(shí)現(xiàn)多個(gè)客戶端連接同一個(gè)服務(wù)端代碼&TCP網(wǎng)絡(luò)編程 ServerSocket和Socket實(shí)現(xiàn)多客戶端聊天

    Socket實(shí)例,實(shí)現(xiàn)多個(gè)客戶端連接同一個(gè)服務(wù)端代碼&TCP網(wǎng)絡(luò)編程 ServerSocket和Socket實(shí)現(xiàn)多客戶端聊天

    Java socket(套接字)通常也稱作\\\"套接字\\\",用于描述ip地址和端口,是一個(gè)通信鏈的句柄。應(yīng)用程序通常通過(guò)\\\"套接字\\\"向網(wǎng)絡(luò)發(fā)出請(qǐng)求或者應(yīng)答網(wǎng)絡(luò)請(qǐng)求。 使用socket實(shí)現(xiàn)多個(gè)客戶端和同一客戶端通訊;首先客戶端連接服務(wù)端發(fā)送一條消息,服務(wù)端接收到消息后進(jìn)行處理,完成后再

    2024年02月12日
    瀏覽(89)
  • (二) 用QWebSocket 實(shí)現(xiàn)服務(wù)端和客戶端(詳細(xì)代碼直接使用)

    目錄 前言 一、服務(wù)器的代碼: 1、服務(wù)器的思路 2、具體服務(wù)器的代碼示例 二、客戶端的代碼: 1、客戶端的思路(和服務(wù)器類(lèi)似) 2、具體客戶端的代碼示例 前言 ????????要是想了解QWebSocket的詳細(xì)知識(shí),還得移步到上一篇文章: WebSocket 詳解,以及用QWebSocket 實(shí)現(xiàn)服務(wù)端

    2024年01月20日
    瀏覽(25)
  • 【高并發(fā)網(wǎng)絡(luò)通信架構(gòu)】2.引入多線程實(shí)現(xiàn)多客戶端連接的tcp服務(wù)端

    【高并發(fā)網(wǎng)絡(luò)通信架構(gòu)】2.引入多線程實(shí)現(xiàn)多客戶端連接的tcp服務(wù)端

    目錄 一,往期文章 二,代碼實(shí)現(xiàn) 關(guān)鍵代碼 完整代碼 運(yùn)行效果 【高并發(fā)網(wǎng)絡(luò)通信架構(gòu)】1.Linux下實(shí)現(xiàn)單客戶連接的tcp服務(wù)端 因?yàn)閍ccept是阻塞等待客戶端連接,當(dāng)客戶端連接成功后才會(huì)執(zhí)行accept后面的代碼,所以為實(shí)現(xiàn)多個(gè)客戶端連接,第一步是將accept放在master循環(huán)里。 rec

    2024年02月13日
    瀏覽(23)
  • WebSocket 詳解,以及用QWebSocket 實(shí)現(xiàn)服務(wù)端和客戶端(含代碼例子)

    WebSocket 詳解,以及用QWebSocket 實(shí)現(xiàn)服務(wù)端和客戶端(含代碼例子)

    目錄 前言: 1、WebSocket 誕生背景 2、WebSocket的特點(diǎn): 3、 WebSocket 簡(jiǎn)介 4、WebSocket 優(yōu)點(diǎn) 5、QWebSocket通訊—客戶端: 6、QWebSocket通訊—服務(wù)端: 前言: ????????要是對(duì)WebSocket 的基本知識(shí)都了解了,可以直接移步,實(shí)際如何使用這個(gè)類(lèi) (二) 用QWebSocket 實(shí)現(xiàn)服務(wù)端和客戶端(

    2024年02月16日
    瀏覽(53)
  • 基于STM32F103,利用W5500芯片實(shí)現(xiàn)TCP客戶端連接TCP服務(wù)器的實(shí)踐

    尊敬的讀者,您好!在這篇文章中,我們將一起深入了解如何使用STM32F103和W5500芯片,實(shí)現(xiàn)TCP客戶端連接到TCP服務(wù)器的過(guò)程。在詳細(xì)的步驟中,我們不僅會(huì)給出相關(guān)的理論介紹,同時(shí)也會(huì)提供實(shí)戰(zhàn)代碼以供大家參考和學(xué)習(xí)。希望大家在閱讀完這篇文章后,能夠有所收獲。 實(shí)戰(zhàn)

    2024年02月11日
    瀏覽(21)
  • (一)WebSocket 詳解,以及用QWebSocket 實(shí)現(xiàn)服務(wù)端和客戶端(含代碼例子)

    (一)WebSocket 詳解,以及用QWebSocket 實(shí)現(xiàn)服務(wù)端和客戶端(含代碼例子)

    目錄 前言: 1、WebSocket 誕生背景 2、WebSocket的特點(diǎn): 3、 WebSocket 簡(jiǎn)介 4、WebSocket 優(yōu)點(diǎn) 5、QWebSocket通訊—客戶端: 6、QWebSocket通訊—服務(wù)端: 前言: ????????要是對(duì)WebSocket 的基本知識(shí)都了解了,可以直接移步,實(shí)際如何使用這個(gè)類(lèi) (二) 用QWebSocket 實(shí)現(xiàn)服務(wù)端和客戶端(

    2024年02月03日
    瀏覽(23)
  • SpringBoot+CAS整合服務(wù)端和客戶端實(shí)現(xiàn)SSO單點(diǎn)登錄與登出快速入門(mén)上手

    SpringBoot+CAS整合服務(wù)端和客戶端實(shí)現(xiàn)SSO單點(diǎn)登錄與登出快速入門(mén)上手

    教學(xué)講解視頻地址:視頻地址 因?yàn)镃AS支持HTTP請(qǐng)求訪問(wèn),而我們是快速入門(mén)上手視頻,所以這期教程就不教大家如何配置HTTPS了,如果需要使用HTTPS,可以參考其他博客去云服務(wù)器申請(qǐng)證書(shū)或者使用JDK自行生成一個(gè)證書(shū)。 下載CAS Server(直接下載壓縮包就可以) 這里我們用的是

    2024年02月02日
    瀏覽(18)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包