Go學習筆記5

来源:https://www.cnblogs.com/Gao-yubo/archive/2023/09/12/17698071.html
-Advertisement-
Play Games

在今天的移動互聯網時代,手機已經成為了人們不可或缺的重要工具,而手機的聯網狀態也是我們經常需要關註的一個問題。我們需要保證手機網路處於正常的連接狀態,但是有時候,由於種種原因,手機的網路可能會斷開,這時我們需要及時發現,併進行相應的處理措施。而利用Api介面實現手機網路連接斷開的監聽,便是一種較為高 ...


十六、基於TCP協議的網路通信

創建客戶端

【1】調用Dial函數:(net包下)

image-20230911152838914

【2】代碼:

package main
import(
        "fmt"
        "net" //所需的網路編程全部都在net包下
)
func main(){
        //列印:
        fmt.Println("客服端啟動。。")
        //調用Dial函數:參數需要指定tcp協議,需要指定伺服器端的IP+PORT
        conn,err := net.Dial("tcp","127.0.0.1:8888")
        if err != nil {//連接失敗
                fmt.Println("客戶端連接失敗:err:",err)
                return
        }
        fmt.Println("連接成功,conn:",conn)
}

創建服務端

【1】進行監聽:(Listen函數在net包下)

image-20230911152923493

【2】代碼:

package main
import(
        "fmt"
        "net" //所需的網路編程全部都在net包下
)
func main(){
        //列印:
        fmt.Println("伺服器端啟動了。。")
        //進行監聽:需要指定伺服器端TCP協議,伺服器端的IP+PORT
        listen,err := net.Listen("tcp","127.0.0.1:8888")
        if err != nil{//監聽失敗
                fmt.Println("監聽失敗,err:",err)
                return
        }
        //監聽成功以後:
        //迴圈等待客戶端的鏈接:
        for{
                conn,err2 := listen.Accept()
                if err2 != nil {//客戶端的等待失敗
                        fmt.Println("客戶端的等待失敗,err2:",err2)
                }else{
                        //連接成功:
                        fmt.Printf("等待鏈接成功,con=%v ,接收到的客戶端信息:%v \n",conn,conn.RemoteAddr().String())
                }
        }
}

運行時註意:需要先啟動伺服器端,然後啟動客戶端進行訪問:

image-20230911152941882

處理終端數據

【1】客戶端發送數據:

package main
import(
        "fmt"
        "net" //所需的網路編程全部都在net包下
        "bufio"
        "os"
)
func main(){
        //列印:
        fmt.Println("客服端啟動。。")
        //調用Dial函數:參數需要指定tcp協議,需要指定伺服器端的IP+PORT
        conn,err := net.Dial("tcp","127.0.0.1:8888")
        if err != nil {//連接失敗
                fmt.Println("客戶端連接失敗:err:",err)
                return
        }
        fmt.Println("連接成功,conn:",conn)
        //通過客戶端發送單行數據,然後退出:
        reader := bufio.NewReader(os.Stdin)//os.Stdin代表終端標準輸入
        //從終端讀取一行用戶輸入的信息:
        str,err := reader.ReadString('\n')
        if err != nil {
                fmt.Println("終端輸入失敗,err:",err)
        }
        //將str數據發送給伺服器:
        n,err := conn.Write([]byte(str))
        if err != nil{
                fmt.Println("連接失敗,err:",err)
        }
        fmt.Printf("終端數據通過客戶端發送成功,一共發送了%d位元組的數據,並退出",n)
}

【2】伺服器端接收數據:

package main
import(
        "fmt"
        "net" //所需的網路編程全部都在net包下
)
func process(conn net.Conn){
        //連接用完一定要關閉:
        defer conn.Close()
        for{
                //創建一個切片,準備:將讀取的數據放入切片:
                buf := make([]byte,1024)
                //從conn連接中讀取數據:
                n,err := conn.Read(buf)
                if err != nil{
                        return
                }
                //將讀取內容在伺服器端輸出:
                fmt.Println(string(buf[0:n]))
        }
}
func main(){
        //列印:
        fmt.Println("伺服器端啟動了。。")
        //進行監聽:需要指定伺服器端TCP協議,伺服器端的IP+PORT
        listen,err := net.Listen("tcp","127.0.0.1:8888")
        if err != nil{//監聽失敗
                fmt.Println("監聽失敗,err:",err)
                return
        }
        //監聽成功以後:
        //迴圈等待客戶端的鏈接:
        for{
                conn,err2 := listen.Accept()
                if err2 != nil {//客戶端的等待失敗
                        fmt.Println("客戶端的等待失敗,err2:",err2)
                }else{
                        //連接成功:
                        fmt.Printf("等待鏈接成功,con=%v ,接收到的客戶端信息:%v \n",conn,conn.RemoteAddr().String())
                }
                //準備一個協程,協程處理客戶端服務請求:
                go process(conn)//不同的客戶端的請求,連接conn不一樣的
        }
}

【3】處理結果:

image-20230911153049172

十七、反射

反射的引入

【1】反射可以做什麼?

  1. 反射可以在運行時動態獲取變數的各種信息,比如變數的類型,類別等信息
  2. 如果是結構體變數,還可以獲取到結構體本身的信息(包括結構體的欄位、方法)
  3. 通過反射,可以修改變數的值,可以調用關聯的方法。
  4. 使用反射,需要import ("reflect")
    【2】反射相關的函數
  5. reflect.TypeOf(變數名),獲取變數的類型,返回reflect.Type類型
  6. reflect.ValueOf(變數名),獲取變數的值,返回reflect.Value類型(reflect.Value是一個結構體類型),通過reflect.Value,可以獲取到關於該變數的很多信息。

image-20230912223247803

基本數據類型的反射

【1】反射相關的函數

  1. reflect.TypeOf(變數名),獲取變數的類型,返回reflect.Type類型
  2. reflect.ValueOf(變數名),獲取變數的值,返回reflect.Value類型(reflect.Value是一個結構體類型),通過reflect.Value,可以獲取到關於該變數的很多信息。
    【2】代碼:

image-20230912223316684

package main
import(
        "fmt"
        "reflect"
)
//利用一個函數,函數的參數定義為空介面:
func testReflect(i interface{}){//空介面沒有任何方法,所以可以理解為所有類型都實現了空介面,也可以理解為我們可以把任何一個變數賦給空介面。
        //1.調用TypeOf函數,返回reflect.Type類型數據:
        reType := reflect.TypeOf(i)
        fmt.Println("reType:",reType)
        fmt.Printf("reType的具體類型是:%T",reType)
        //2.調用ValueOf函數,返回reflect.Value類型數據:
        reValue :=reflect.ValueOf(i)
        fmt.Println("reValue:",reValue)
        fmt.Printf("reValue的具體類型是:%T",reValue)
        //num1 := 100
        //如果真想獲取reValue的數值,要調用Int()方法:返回v持有的有符號整數
        num2 := 80 + reValue.Int()
        fmt.Println(num2)
        //reValue轉成空介面:
        i2 := reValue.Interface()
        //類型斷言:
        n := i2.(int)
        n2 := n + 30
        fmt.Println(n2)
}
func main(){
        //對基本數據類型進行反射:
        //定義一個基本數據類型:
        var num int = 100
        testReflect(num)
}

結構體類型的反射

【1】反射相關的函數

  1. reflect.TypeOf(變數名),獲取變數的類型,返回reflect.Type類型
  2. reflect.ValueOf(變數名),獲取變數的值,返回reflect.Value類型(reflect.Value是一個結構體類型),通過reflect.Value,可以獲取到關於該變數的很多信息。
    【2】代碼:
package main
import(
        "fmt"
        "reflect"
)
//利用一個函數,函數的參數定義為空介面:
func testReflect(i interface{}){//空介面沒有任何方法,所以可以理解為所有類型都實現了空介面,也可以理解為我們可以把任何一個變數賦給空介面。
        //1.調用TypeOf函數,返回reflect.Type類型數據:
        reType := reflect.TypeOf(i)
        fmt.Println("reType:",reType)
        fmt.Printf("reType的具體類型是:%T",reType)
        //2.調用ValueOf函數,返回reflect.Value類型數據:
        reValue :=reflect.ValueOf(i)
        fmt.Println("reValue:",reValue)
        fmt.Printf("reValue的具體類型是:%T",reValue)
        //reValue轉成空介面:
        i2 := reValue.Interface()
        //類型斷言:
        n,flag := i2.(Student)
        if flag == true {//斷言成功
                fmt.Printf("學生的名字是:%v,學生的年齡是:%v",n.Name,n.Age)
        }
        
}
//定義學生結構體:
type Student struct{
        Name string
        Age int
}
func main(){
        //對結構體類型進行反射:
        //定義結構體具體的實例:
        stu := Student{
                Name : "麗麗",
                Age : 18,	
        }
        testReflect(stu)
}

獲取變數的類別

【1】獲取變數的類別:兩種方式:
(1)reflect.Type.Kind()
(2)reflect.Value.Kind()
【2】Kind的值是常量值:

image-20230912223535251

【3】代碼:

package main
import(
        "fmt"
        "reflect"
)
//利用一個函數,函數的參數定義為空介面:
func testReflect(i interface{}){//空介面沒有任何方法,所以可以理解為所有類型都實現了空介面,也可以理解為我們可以把任何一個變數賦給空介面。
        //1.調用TypeOf函數,返回reflect.Type類型數據:
        reType := reflect.TypeOf(i)
        //2.調用ValueOf函數,返回reflect.Value類型數據:
        reValue :=reflect.ValueOf(i)
        //獲取變數的類別:
        //(1)reType.Kind()
        k1 := reType.Kind()
        fmt.Println(k1)
        //(2)reValue.Kind()
        k2 := reValue.Kind()
        fmt.Println(k2)
        //獲取變數的類型:
        //reValue轉成空介面:
        i2 := reValue.Interface()
        //類型斷言:
        n,flag := i2.(Student)
        if flag == true {//斷言成功
                fmt.Printf("結構體的類型是:%T",n)
        }
}
//定義學生結構體:
type Student struct{
        Name string
        Age int
}
func main(){
        //對結構體類型進行反射:
        //定義結構體具體的實例:
        stu := Student{
                Name : "麗麗",
                Age : 18,	
        }
        testReflect(stu)
}

【4】Type和 Kind 的區別
Type是類型, Kind是類別,Type和Kind 可能是相同的,也可能是不同的.
比如:var num int = 10 num的Type是int , Kind也是int
比如:var stu Studentstu的 Type是 pkg1.Student , Kind是struct

通過反射修改變數

【1】修改基本數據類型的值:

package main
import(
        "fmt"
        "reflect"
)
//利用一個函數,函數的參數定義為空介面:
func testReflect(i interface{}){//空介面沒有任何方法,所以可以理解為所有類型都實現了空介面,也可以理解為我們可以把任何一個變數賦給空介面。
        reValue :=reflect.ValueOf(i)
        //通過SetInt()來改變值:
        reValue.Elem().SetInt(40)
        
}
func main(){
        //對基本數據類型進行反射:
        //定義一個基本數據類型:
        var num int = 100
        testReflect(&num) //傳入指針地址
        fmt.Println(num)
}

image-20230912223655856

操作結構體的屬性和方法

【1】代碼:(熟知API)

package main
import(
        "fmt"
        "reflect"
)
//定義一個結構體:
type Student struct{
        Name string
        Age int
}
//給結構體綁定方法:
func (s Student) CPrint(){
        fmt.Println("調用了Print()方法")
        fmt.Println("學生的名字是:",s.Name)
}
func (s Student) AGetSum(n1,n2 int) int{
        fmt.Println("調用了AGetSum方法")
        return n1 + n2
}
func (s Student) BSet(name string,age int){
        s.Name = name
        s.Age = age
}
//定義函數操作結構體進行反射操作:
func TestStudentStruct(a interface{}){
        //a轉成reflect.Value類型:
        val := reflect.ValueOf(a)
        fmt.Println(val)
        //通過reflect.Value類型操作結構體內部的欄位:
        n1 := val.NumField()
        fmt.Println(n1)
        //遍歷-獲取具體的欄位:
        for i := 0; i < n1;i++{
                fmt.Printf("第%d個欄位的值是:%v",i,val.Field(i))
        }
        fmt.Println()
        //通過reflect.Value類型操作結構體內部的方法:
        n2 := val.NumMethod()
        fmt.Println(n2)
        //調用CPrint()方法:
        //調用方法,方法的首字母必須大寫才能有對應的反射的訪問許可權
        //方法的順序按照ASCII的順序排列的,a,b,c,,,,,,索引:0,1,2,,,,,
        val.Method(2).Call(nil)
        //調用AGetSum方法:
        //定義Value的切片:
        var params []reflect.Value
        params = append(params,reflect.ValueOf(10))
        params = append(params,reflect.ValueOf(20))
        result := val.Method(0).Call(params)
        fmt.Println("AGetSum方法的返回值為:",result[0].Int())
}
func main(){
        //定義結構體具體的實例:
        s := Student{
                Name : "麗麗",
                Age : 18,
        }
        //調用TestStudentStruct:
        TestStudentStruct(s)
}

修改結構的變數

【1】代碼:

package main
import(
        "fmt"
        "reflect"
)
//定義一個結構體:
type Student struct{
        Name string
        Age int
}
//給結構體綁定方法:
func (s Student) CPrint(){
        fmt.Println("調用了Print()方法")
        fmt.Println("學生的名字是:",s.Name)
}
func (s Student) AGetSum(n1,n2 int) int{
        fmt.Println("調用了AGetSum方法")
        return n1 + n2
}
func (s Student) BSet(name string,age int){
        s.Name = name
        s.Age = age
}
//定義函數操作結構體進行反射操作:
func TestStudentStruct(a interface{}){
        //a轉成reflect.Value類型:
        val := reflect.ValueOf(a)
        fmt.Println(val)
        n := val.Elem().NumField()
        fmt.Println(n)
        //修改欄位的值:
        val.Elem().Field(0).SetString("張三")
}
func main(){
        //定義結構體具體的實例:
        s := Student{
                Name : "麗麗",
                Age : 18,
        }
        //調用TestStudentStruct:
        TestStudentStruct(&s)
        fmt.Println(s)
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 引言 Apple MDM (Mobile Device Management) 字面理解就是一種管理移動設備的方式,覆蓋 iOS 5 及更高版本的 iPhone/iPod touch/iPad、Mac OS X 10.7 及更高版本的 Mac、TVOS 9 及更高版本的 Apple TV,標題中的 ...
  • Vue2安裝JSX支持 有時候,我們使用渲染函數(render function)來抽象組件,而渲染函數使用Vue的h函數來編寫Dom元素相對template語法差別較大,體驗不佳,這個時候就派 JSX 上場了。然而在Vue3中預設是帶了JSX支持的,而在 Vue2 中使用 JSX,需要安裝並使用 ...
  • 作為一名全棧工程師,在日常的工作中,可能更側重於後端開發,如:C#,Java,SQL ,Python等,對前端的知識則不太精通。在一些比較完善的公司或者項目中,一般會搭配前端工程師,UI工程師等,來彌補後端開發的一些前端經驗技能上的不足。但並非所有的項目都會有專職前端工程師,在一些小型項目或者初創公... ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 如何避免寫出屎山,優雅的封裝組件,在面試官面前大大加分,從這篇文章開始! 保持單向數據流 大家都知道vue是單項數據流的,子組件不能直接修改父組件傳過來的props,但是在我們封裝組件使用v-model時,不小心就會打破單行數據流的規則, ...
  • 存儲相關 Vuex 和本地存儲(如localStorage)以及 cookie 存儲(如 document.cookie)之間有一些關係,但它們是不同的概念,用於不同的目的。 Vuex: Vuex 是 Vue.js 的官方狀態管理庫,用於在 Vue.js 應用程式中管理應用程式的全局狀態。 Vuex ...
  • React18 Hooks+Arco-Design+Zustand仿微信客戶端聊天ReactWebchat。 react18-webchat基於react18+vite4.x+arco-design+zustand等技術開發的一款仿製微信網頁版聊天實戰項目。實現發送帶有emoj消息文本、圖片/視頻預 ...
  • ##一、定義 **使用原型實例指定待創建對象的類型,並且通過複製這個原型來創建新的對象。原型模式是一種創建型模式。** ##二、描述 **包含以下三個角色:** ![](https://img2023.cnblogs.com/blog/1780813/202305/1780813-202305271 ...
  • JWT官網 https://jwt.io/ 選擇第一個 composer require firebase/php-jwt use Firebase\JWT\ExpiredException;use Firebase\JWT\JWT;use Firebase\JWT\Key;use Firebase ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...