Golang 實(shí)現(xiàn)Socket服務(wù)端和客戶端使用TCP協(xié)議通訊
Socket服務(wù)器是網(wǎng)絡(luò)服務(wù)中常用的服務(wù)器。使用go語(yǔ)言實(shí)現(xiàn)這個(gè)業(yè)務(wù)場(chǎng)景是很容易的。
這樣的網(wǎng)絡(luò)通訊,需要一個(gè)服務(wù)端和至少一個(gè)客戶端。
我們計(jì)劃構(gòu)建一個(gè)這樣的通訊工程。服務(wù)端啟動(dòng)后等待客戶端的訪問(wèn)??蛻舳税l(fā)送一段信息給服務(wù)端。服務(wù)端接收到信息后,再回饋給客戶端一段信息。
首先要建立服務(wù)端。服務(wù)端最先要做的事情就是"建立Socket端口監(jiān)聽"。
netListen, err := net.Listen("tcp", "localhost:1024")
上面的代碼,表名監(jiān)聽的是本機(jī)端口1024,而使用的通訊協(xié)議是TCP。
當(dāng)監(jiān)聽結(jié)束,模塊任務(wù)完成后,最后要close這個(gè)netListen。
defer netListen.Close()
使用日志功能,讓服務(wù)端窗口能看到服務(wù)端已經(jīng)運(yùn)行了。
Log("Waiting for clients ...")
之后使用一個(gè)for循環(huán),無(wú)盡的等待那些不知何時(shí)來(lái)訪問(wèn)的客戶端信息。
for循環(huán)體內(nèi),要監(jiān)聽netListen的信息接收情況:
conn, err := netListen.Accept()
當(dāng)有來(lái)自客戶端的訪問(wèn)時(shí),接受訪問(wèn)。并在服務(wù)端的日志記錄已經(jīng)有客戶端連接成功了。
Log(conn.RemoteAddr().String(), "tcp connect success")
conn.RemoteAddr().String()表示的就是遠(yuǎn)程客戶端。
然后,我們開啟一個(gè)goroutine處理連接任務(wù)。
go handleConnection(conn)
處理過(guò)程就是接收客戶端信息和反饋給客戶端信息。
n, err := conn.Read(buffer)
conn.Write([]byte(strTemp))
服務(wù)端代碼示例
package main import ( "net" "fmt" "os" "log" "time" ) func main() { //建立socket端口監(jiān)聽 netListen, err := net.Listen("tcp", "localhost:1024") CheckError(err) defer netListen.Close() Log("Waiting for clients ...") //等待客戶端訪問(wèn) for{ conn, err := netListen.Accept() //監(jiān)聽接收 if err != nil{ continue //如果發(fā)生錯(cuò)誤,繼續(xù)下一個(gè)循環(huán)。 } Log(conn.RemoteAddr().String(), "tcp connect success") //tcp連接成功 go handleConnection(conn) } } //處理連接 func handleConnection(conn net.Conn) { buffer := make([]byte, 2048) //建立一個(gè)slice for{ n, err := conn.Read(buffer) //讀取客戶端傳來(lái)的內(nèi)容 if err != nil{ Log(conn.RemoteAddr().String(), "connection error: ", err) return //當(dāng)遠(yuǎn)程客戶端連接發(fā)生錯(cuò)誤(斷開)后,終止此協(xié)程。 } Log(conn.RemoteAddr().String(), "receive data string:\n", string(buffer[:n])) //返回給客戶端的信息 strTemp := "CofoxServer got msg \""+string(buffer[:n])+"\" at "+time.Now().String() conn.Write([]byte(strTemp)) } } //日志處理 func Log(v ...interface{}) { log.Println(v...) } //錯(cuò)誤處理 func CheckError(err error) { if err != nil{ fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) } }
客戶端的業(yè)務(wù)邏輯是,發(fā)送信息給服務(wù)端,然后接收服務(wù)端的反饋。
conn, err := net.DialTCP("tcp", nil, tcpAddr)
用TCP協(xié)議撥號(hào)(Dial)到服務(wù)端。如果沒(méi)有發(fā)生錯(cuò)誤,就說(shuō)明撥通了。于是在客戶端日志記錄連接成功
fmt.Println("connection success")
然后在這個(gè)已經(jīng)通暢的連接里,進(jìn)行發(fā)送和接收信息的任務(wù)。conn.Write([]byte(words))是發(fā)送信息;conn.Read(buffer)是接收信息。如果接收發(fā)生錯(cuò)誤,就記錄錯(cuò)誤:
Log(conn.RemoteAddr().String(), "waiting server back msg error: ", err)
并且中斷進(jìn)程。
如果沒(méi)有發(fā)生錯(cuò)誤,酒吧接收到的信息在日志中記錄。
Log(conn.RemoteAddr().String(), "receive server back msg: ", string(buffer[:n]))
客戶端代碼示例
package main import ( "net" "fmt" "log" "os" ) //發(fā)送信息 func sender(conn net.Conn) { words := "Hello Server!" conn.Write([]byte(words)) fmt.Println("send over") //接收服務(wù)端反饋 buffer := make([]byte, 2048) n, err := conn.Read(buffer) if err != nil { Log(conn.RemoteAddr().String(), "waiting server back msg error: ", err) return } Log(conn.RemoteAddr().String(), "receive server back msg: ", string(buffer[:n])) } //日志 func Log(v ...interface{}) { log.Println(v...) } func main() { server := "127.0.0.1:1024" 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("connection success") sender(conn) }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
Go語(yǔ)言設(shè)置JSON的默認(rèn)值操作
這篇文章主要介紹了Go語(yǔ)言設(shè)置JSON的默認(rèn)值操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12使用golang編寫一個(gè)并發(fā)工作隊(duì)列
這篇文章主要介紹了使用golang編寫一個(gè)并發(fā)工作隊(duì)列的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-05-05使用golang獲取linux上文件的訪問(wèn)/創(chuàng)建/修改時(shí)間
這篇文章主要介紹了使用golang獲取linux上文件的訪問(wèn)/創(chuàng)建/修改時(shí)間,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-08-08Golang連接Redis數(shù)據(jù)庫(kù)的方法
這篇文章主要介紹了Golang連接Redis數(shù)據(jù)庫(kù)的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12