日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Golang——TCP、UDP实现并发(服务端与客户端)

發(fā)布時(shí)間:2025/3/15 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Golang——TCP、UDP实现并发(服务端与客户端) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Server端常用函數(shù)、接口:

Listen函數(shù):func Listen(network, address string) (Listener, error)network:選用的協(xié)議:TCP、UDP, 如:“tcp”或 “udp”address:IP地址+端口號(hào), 如:“127.0.0.1:8000”或 “:8000”Listener 接口: type Listener interface {Accept() (Conn, error)Close() errorAddr() Addr }Conn 接口: type Conn interface {Read(b []byte) (n int, err error)Write(b []byte) (n int, err error)Close() errorLocalAddr() AddrRemoteAddr() AddrSetDeadline(t time.Time) errorSetReadDeadline(t time.Time) errorSetWriteDeadline(t time.Time) error }

TCP-服務(wù)端實(shí)現(xiàn):

func main() {// 指定服務(wù)器的通訊協(xié)議、ip、端口,Listen本身不做監(jiān)聽(tīng),這一步是創(chuàng)建了一個(gè)用于監(jiān)聽(tīng)的Socketlisten, err := net.Listen("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Listen出錯(cuò):", err)return}defer listen.Close()fmt.Println("服務(wù)器啟動(dòng)完畢,等待客戶端連接")// 阻塞監(jiān)聽(tīng)客戶端連接請(qǐng)求,成功建立連接后會(huì)返回用于通信的Socketaccept, err := listen.Accept()if err != nil {fmt.Println("listen.Accept出錯(cuò):", err)return}defer accept.Close()fmt.Println("服務(wù)器與客戶端連接成功")// 讀取客戶端發(fā)動(dòng)的請(qǐng)求buf := make([]byte, 4096)read, err := accept.Read(buf)if err != nil {fmt.Println("accept.Read出錯(cuò):", err)return}// 接收數(shù)據(jù)后處理數(shù)據(jù)fmt.Println("服務(wù)器獲取到:", string(buf[:read])) }

Mac可以通過(guò)netcat進(jìn)行測(cè)試:

TCP-客戶端實(shí)現(xiàn):

func main() {// 指定用戶端的通訊協(xié)議、ip、端口,Listen本身不做監(jiān)聽(tīng),這一步是創(chuàng)建了一個(gè)用于監(jiān)聽(tīng)的Socketdial, err := net.Dial("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Dial出錯(cuò):", err)return}defer dial.Close()// 發(fā)送數(shù)據(jù)dial.Write([]byte("我是客戶端"))// 接收服務(wù)器返回的數(shù)據(jù)buf := make([]byte, 4096)read, err := dial.Read(buf)if err != nil {fmt.Println("accept.Read出錯(cuò):", err)return}// 接收數(shù)據(jù)后處理數(shù)據(jù)fmt.Println("客戶端獲取到:", string(buf[:read])) }

TCP實(shí)現(xiàn)并發(fā)-服務(wù)器:

上面都是單機(jī)版的客戶端通信,如果想要實(shí)現(xiàn)并發(fā),需要使用Goroutine+循環(huán)實(shí)現(xiàn)

  • 循環(huán)讀取客戶端發(fā)送的數(shù)據(jù)
  • 如果客戶端強(qiáng)制關(guān)閉連接需要做處理
  • 客戶端發(fā)送exit時(shí)

演示:

package mainimport ("fmt""net""strings" )func main() {// 創(chuàng)建監(jiān)聽(tīng)套接字listen, err := net.Listen("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Listen出錯(cuò):", err)return}defer listen.Close()// 創(chuàng)建客戶端連接請(qǐng)求fmt.Println("服務(wù)器啟動(dòng)成功,等待客戶端連接!")for {accept, err := listen.Accept()if err != nil {fmt.Println("listen.Accept出錯(cuò):", err)return}// 調(diào)用服務(wù)器和客戶端通信的函數(shù)go HandlerConnect(accept)} }func HandlerConnect(accept net.Conn) {defer accept.Close()// 獲取客戶端發(fā)送的數(shù)據(jù)// 獲取連接客戶端的網(wǎng)絡(luò)地址addr := accept.RemoteAddr()fmt.Println(addr, "客戶端連接成功!")buf := make([]byte, 4096)for {read, err := accept.Read(buf)if err != nil {fmt.Println("accept.Read出錯(cuò):", err)return}fmt.Println("服務(wù)器讀到數(shù)據(jù):", string(buf[:read]))// 模擬服務(wù)器收到數(shù)據(jù)后,回發(fā)給客戶端,小寫(xiě)轉(zhuǎn)大寫(xiě)data := strings.ToUpper(string(buf[:read]))accept.Write([]byte(data))} }

TCP實(shí)現(xiàn)并發(fā)-客戶端:

演示:

package mainimport ("fmt""net""os" )func main() {//主動(dòng)發(fā)送連接請(qǐng)求dial, err := net.Dial("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("et.Dial出錯(cuò)了", err)return}defer dial.Close()// os.Stdin():獲取用戶鍵盤(pán)錄入,go func() {str := make([]byte, 4096)for {read, err := os.Stdin.Read(str)if err != nil {fmt.Println("os.Stdin.Read出錯(cuò)了", err)continue}// 讀到的數(shù)據(jù)寫(xiě)給服務(wù)器,讀多少寫(xiě)多少dial.Write(str[:read])}}()buf := make([]byte, 4096)// 回顯服務(wù)器發(fā)送的數(shù)據(jù),轉(zhuǎn)成大寫(xiě)for {read, err := dial.Read(buf)// read=0的說(shuō)明對(duì)端關(guān)閉連接,如果關(guān)閉連接這里就不需要往下讀數(shù)據(jù)了if read == 0 {fmt.Println("檢測(cè)到服務(wù)端端已經(jīng)斷開(kāi)連接!")return}if err != nil {fmt.Println("回顯服務(wù)器發(fā)送的數(shù)據(jù)dial.Read出錯(cuò)了", err)return}fmt.Println("客戶端讀到服務(wù)器的回顯數(shù)據(jù)", string(buf[:read]))} }

UDP實(shí)現(xiàn)并發(fā)-服務(wù)器:

由于UDP是“無(wú)連接”的,所以,服務(wù)器端不需要額外創(chuàng)建監(jiān)聽(tīng)套接字,只需要指定好IP和port,然后監(jiān)聽(tīng)該地址,等待客戶端與之建立連接,即可通信。

創(chuàng)建監(jiān)聽(tīng)地址:

func ResolveUDPAddr(network, address string) (*UDPAddr, error)

創(chuàng)建監(jiān)聽(tīng)連接:

func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error)

接收udp數(shù)據(jù):

func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error)

寫(xiě)出數(shù)據(jù)到udp:

func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error)

演示:

package mainimport ("fmt""net" )func main() {// 指定服務(wù)器的ip和端口,和TCP協(xié)議不一樣,需要先寫(xiě)好再傳給ListenUDP使用ServerAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8000")if err != nil {fmt.Println("net.ResolveUDPAddr err:", err)return}fmt.Println("服務(wù)器啟動(dòng)成功!")// 創(chuàng)建用戶通信的SocketudpConnect, err := net.ListenUDP("udp", ServerAddr)if err != nil {fmt.Println("net.ListenUDP err:", err)return}defer udpConnect.Close()fmt.Println("服務(wù)器創(chuàng)建Socket成功!")// 讀寫(xiě)客戶端的數(shù)據(jù)buf := make([]byte, 4096)count := 0for {// 返回值:n int(讀到的字節(jié)數(shù)), addr *UDPAddr(客戶端的地址), err errorudpBytes, ConnectAddr, err := udpConnect.ReadFromUDP(buf)if err != nil {fmt.Println("udpConnect.ReadFromUDP err:", err)return}count++// 模擬處理數(shù)據(jù)fmt.Printf("服務(wù)器讀到第%v條數(shù)據(jù) %v :%s\n", count, ConnectAddr, string(buf[:udpBytes]))go func() {// 回寫(xiě)數(shù)據(jù)到客戶端udpConnect.WriteToUDP([]byte("回寫(xiě)數(shù)據(jù)到客戶端\n"), ConnectAddr)}()} }

UDP實(shí)現(xiàn)并發(fā)-客戶端:

package mainimport ("fmt""net""time" )func main() {dial, err := net.Dial("udp", "127.0.0.1:8000")if err != nil {fmt.Println("net.Dial出錯(cuò):", err)return}defer dial.Close()for {// 發(fā)送數(shù)據(jù)dial.Write([]byte("我是客戶端"))// 接收服務(wù)器返回的數(shù)據(jù)buf := make([]byte, 4096)read, err := dial.Read(buf)if err != nil {fmt.Println("accept.Read出錯(cuò):", err)return}// 接收數(shù)據(jù)后處理數(shù)據(jù)fmt.Println("客戶端獲取到:", string(buf[:read]))time.Sleep(time.Second)} }

總結(jié)

以上是生活随笔為你收集整理的Golang——TCP、UDP实现并发(服务端与客户端)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。