在今天的移動互聯網時代,手機已經成為了人們不可或缺的重要工具,而手機的聯網狀態也是我們經常需要關註的一個問題。我們需要保證手機網路處於正常的連接狀態,但是有時候,由於種種原因,手機的網路可能會斷開,這時我們需要及時發現,併進行相應的處理措施。而利用Api介面實現手機網路連接斷開的監聽,便是一種較為高 ...
十六、基於TCP協議的網路通信
創建客戶端
【1】調用Dial函數:(net包下)
【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包下)
【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())
}
}
}
運行時註意:需要先啟動伺服器端,然後啟動客戶端進行訪問:
處理終端數據
【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】處理結果:
十七、反射
反射的引入
【1】反射可以做什麼?
- 反射可以在運行時動態獲取變數的各種信息,比如變數的類型,類別等信息
- 如果是結構體變數,還可以獲取到結構體本身的信息(包括結構體的欄位、方法)
- 通過反射,可以修改變數的值,可以調用關聯的方法。
- 使用反射,需要import ("reflect")
【2】反射相關的函數 - reflect.TypeOf(變數名),獲取變數的類型,返回reflect.Type類型
- reflect.ValueOf(變數名),獲取變數的值,返回reflect.Value類型(reflect.Value是一個結構體類型),通過reflect.Value,可以獲取到關於該變數的很多信息。
基本數據類型的反射
【1】反射相關的函數
- reflect.TypeOf(變數名),獲取變數的類型,返回reflect.Type類型
- 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)
//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】反射相關的函數
- reflect.TypeOf(變數名),獲取變數的類型,返回reflect.Type類型
- 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的值是常量值:
【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)
}
操作結構體的屬性和方法
【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)
}