go語言中的if語句和其他語言中的類似,都是根據(jù)給定的條件表達(dá)式運(yùn)算結(jié)果來,判斷執(zhí)行流程。
我們提供的服務(wù)有:成都做網(wǎng)站、成都網(wǎng)站建設(shè)、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、西塞山ssl等。為上千余家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的西塞山網(wǎng)站制作公司
注意:在go語言中 布爾表達(dá)式不用使用括號(hào)。
根據(jù)布爾值flag判斷
程序運(yùn)行結(jié)果
初始變量可以聲明在布爾表達(dá)式里面,注意它的作用域
程序運(yùn)行結(jié)果
注意:不能使用0或非0表示真假
go語言if語句使用提示:
go語言中的if else語句可以根據(jù)給定條件二選一。
比較兩個(gè)數(shù)的大小
運(yùn)行結(jié)果
判斷一個(gè)數(shù)是奇數(shù)還是偶數(shù)
運(yùn)行結(jié)果
判斷一個(gè)人是否成年
運(yùn)行結(jié)果
特殊寫法,在if前面添加執(zhí)行語句
運(yùn)行結(jié)果
go語言if語句使用提示:
go語言if語句可以進(jìn)行多重嵌套使用,進(jìn)行多重判斷。
根據(jù)分?jǐn)?shù)判斷等級(jí)
運(yùn)行結(jié)果
同樣也可以寫成這樣
運(yùn)行結(jié)果
輸入星期幾的第一個(gè)字母來判斷一下是星期幾,如果第一個(gè)字母一樣,則繼續(xù)判斷第二個(gè)字母
運(yùn)行結(jié)果
go語言if語句可以嵌套多級(jí)進(jìn)行判斷。
判斷三個(gè)數(shù)的大小
運(yùn)行結(jié)果
判斷男生還是女生,還有是否成年
運(yùn)行結(jié)果
1、goroutine:在go語言中,每一個(gè)并發(fā)的執(zhí)行單元叫做goroutine,如果一個(gè)程序中包含多個(gè)goroutine,對(duì)兩個(gè)函數(shù)的調(diào)用則可能發(fā)生在同一時(shí)刻
2、main goroutine:當(dāng)一個(gè)程序啟動(dòng)時(shí),其主函數(shù)即在一個(gè)單獨(dú)的goroutine中運(yùn)行,我們叫他為main gorountine
3、go goroutine:新的goroutine會(huì)用go語句來創(chuàng)建,go+函數(shù)名,go語句會(huì)使其語句中的函數(shù)在一新創(chuàng)建的goroutine中運(yùn)行,而go語句本身會(huì)迅速地完成
4、goroutine的退出:主函數(shù)返回時(shí),所有的goroutine都會(huì)被直接打斷,程序退出,除了從主函數(shù)退出或者終止程序之外,沒有其他方法能夠讓一個(gè)goroutine來打斷另一個(gè)的執(zhí)行,但是可以通過另一種方式來實(shí)現(xiàn)這個(gè)目的,通過goroutine之間的通信來讓一個(gè)goroutine請(qǐng)求其他的goroutine,并讓請(qǐng)求的goroutine自行結(jié)束執(zhí)行
三次握手:
1. 主動(dòng)發(fā)起連接請(qǐng)求端(客戶端),發(fā)送 SYN 標(biāo)志位,攜帶數(shù)據(jù)包、包號(hào)
2. 被動(dòng)接收連接請(qǐng)求端(服務(wù)器),接收 SYN,回復(fù) ACK,攜帶應(yīng)答序列號(hào)。同時(shí),發(fā)送SYN標(biāo)志位,攜帶數(shù)據(jù)包、包號(hào)
3. 主動(dòng)發(fā)起連接請(qǐng)求端(客戶端),接收SYN 標(biāo)志位,回復(fù) ACK。
被動(dòng)端(服務(wù)器)接收 ACK —— 標(biāo)志著 三次握手建立完成( Accept()/Dial() 返回 )
四次揮手:
1. 主動(dòng)請(qǐng)求斷開連接端(客戶端), 發(fā)送 FIN標(biāo)志,攜帶數(shù)據(jù)包
2. 被動(dòng)接受斷開連接端(服務(wù)器), 發(fā)送 ACK標(biāo)志,攜帶應(yīng)答序列號(hào)。 —— 半關(guān)閉完成。
3. 被動(dòng)接受斷開連接端(服務(wù)器), 發(fā)送 FIN標(biāo)志,攜帶數(shù)據(jù)包
4. 主動(dòng)請(qǐng)求斷開連接端(客戶端), 發(fā)送 最后一個(gè) ACK標(biāo)志,攜帶應(yīng)答序列號(hào)?!?發(fā)送完成,客戶端不會(huì)直接退出,等 2MSL時(shí)長(zhǎng)。
等 2MSL待目的:確保服務(wù)器 收到最后一個(gè)ACK
滑動(dòng)窗口:
通知對(duì)端本地存儲(chǔ)數(shù)據(jù)的 緩沖區(qū)容量?!?write 函數(shù)在對(duì)端 緩沖區(qū)滿時(shí),有可能阻塞。
TCP狀態(tài)轉(zhuǎn)換:
1. 主動(dòng)發(fā)起連接請(qǐng)求端:
CLOSED —— 發(fā)送SYN —— SYN_SENT(了解) —— 接收ACK、SYN,回發(fā) ACK —— ESTABLISHED (數(shù)據(jù)通信)
2. 主動(dòng)關(guān)閉連接請(qǐng)求端:
ESTABLISHED —— 發(fā)送FIN —— FIN_WAIT_1 —— 接收ACK —— FIN_WAIT_2 (半關(guān)閉、主動(dòng)端)
—— 接收FIN、回復(fù)ACK —— TIME_WAIT (主動(dòng)端) —— 等 2MSL 時(shí)長(zhǎng) —— CLOSED
3. 被動(dòng)建立連接請(qǐng)求端:
CLOSED —— LISTEN —— 接收SYN、發(fā)送ACK、SYN —— SYN_RCVD —— 接收 ACK —— ESTABLISHED (數(shù)據(jù)通信)
4. 被動(dòng)斷開連接請(qǐng)求端:
ESTABLISHED —— 接收 FIN、發(fā)送 ACK —— CLOSE_WAIT —— 發(fā)送 FIN —— LAST_ACK —— 接收ACK —— CLOSED
windows下查看TCP狀態(tài)轉(zhuǎn)換:
netstat -an | findstr? 端口號(hào)
Linux下查看TCP狀態(tài)轉(zhuǎn)換:
netstat -an | grep? 端口號(hào)
TCP和UDP對(duì)比:?
TCP: 面向連接的可靠的數(shù)據(jù)包傳遞。 針對(duì)不穩(wěn)定的 網(wǎng)絡(luò)層,完全彌補(bǔ)。ACK
UDP:無連接不可靠的報(bào)文傳輸。 針對(duì)不穩(wěn)定的 網(wǎng)絡(luò)層,完全不彌補(bǔ)。還原網(wǎng)絡(luò)真實(shí)狀態(tài)。
優(yōu)點(diǎn)???????????????????????????????????????????????????????????? 缺點(diǎn)
TCP: 可靠、順序、穩(wěn)定 ???????????????????????????????????? 系統(tǒng)資源消耗大,程序?qū)崿F(xiàn)繁復(fù)、速度慢
UDP:系統(tǒng)資源消耗小,程序?qū)崿F(xiàn)簡(jiǎn)單、速度快 ???????????????????????? 不可靠、無序、不穩(wěn)定
使用場(chǎng)景:
TCP:大文件、可靠數(shù)據(jù)傳輸。 對(duì)數(shù)據(jù)的 穩(wěn)定性、準(zhǔn)確性、一致性要求較高的場(chǎng)合。
UDP:應(yīng)用于對(duì)數(shù)據(jù)時(shí)效性要求較高的場(chǎng)合。 網(wǎng)絡(luò)直播、電話會(huì)議、視頻直播、網(wǎng)絡(luò)游戲。
UDP-CS-Server實(shí)現(xiàn)流程:
1.? 創(chuàng)建 udp地址結(jié)構(gòu) ResolveUDPAddr(“協(xié)議”, “IP:port”) —— udpAddr 本質(zhì) struct{IP、port}
2.? 創(chuàng)建用于 數(shù)據(jù)通信的 socket ListenUDP(“協(xié)議”, udpAddr ) —— udpConn (socket)
3.? 從客戶端讀取數(shù)據(jù),獲取對(duì)端的地址 udpConn.ReadFromUDP() —— 返回:n,clientAddr, err
4.? 發(fā)送數(shù)據(jù)包給 客戶端 udpConn.WriteToUDP("數(shù)據(jù)", clientAddr)
UDP-CS-Client實(shí)現(xiàn)流程:
1.? 創(chuàng)建用于通信的 socket。 net.Dial("udp", "服務(wù)器IP:port") —— udpConn (socket)
2.? 以后流程參見 TCP客戶端實(shí)現(xiàn)源碼。
UDPserver默認(rèn)就支持并發(fā)!
------------------------------------
命令行參數(shù): 在main函數(shù)啟動(dòng)時(shí),向整個(gè)程序傳參。 【重點(diǎn)】
語法: go run xxx.go ? argv1 argv2? argv3? argv4 。。。
xxx.exe:? 第 0 個(gè)參數(shù)。
argv1 :第 1 個(gè)參數(shù)。
argv2 :第 2 個(gè)參數(shù)。
argv3 :第 3 個(gè)參數(shù)。
argv4 :第 4 個(gè)參數(shù)。
使用: list := os.Args? 提取所有命令行參數(shù)。
獲取文件屬性函數(shù):
os.stat(文件訪問絕對(duì)路徑) —— fileInfo 接口
fileInfo 包含 兩個(gè)接口。
Name() 獲取文件名。 不帶訪問路徑
Size() 獲取文件大小。
網(wǎng)絡(luò)文件傳輸 —— 發(fā)送端(客戶端)
1.? 獲取命令行參數(shù),得到文件名(帶路徑)filePath list := os.Args
2.? 使用 os.stat() 獲取 文件名(不帶路徑)fileName
3.? 創(chuàng)建 用于數(shù)據(jù)傳輸?shù)?socket? net.Dial("tcp", “服務(wù)器IP+port”) —— conn
4.? 發(fā)送文件名(不帶路徑)? 給接收端, conn.write()
5.? 讀取 接收端回發(fā)“ok”,判斷無誤。封裝函數(shù) sendFile(filePath, conn) 發(fā)送文件內(nèi)容
6.? 實(shí)現(xiàn) sendFile(filePath,? conn)
1) 只讀打開文件 os.Open(filePath)
for {
2) 從文件中讀數(shù)據(jù)? f.Read(buf)
3) 將讀到的數(shù)據(jù)寫到socket中? conn.write(buf[:n])
4)判斷讀取文件的 結(jié)尾。 io.EOF. 跳出循環(huán)
}
網(wǎng)絡(luò)文件傳輸 —— 接收端(服務(wù)器)
1. 創(chuàng)建用于監(jiān)聽的 socket net.Listen() —— listener
2. 借助listener 創(chuàng)建用于 通信的 socket listener.Accpet()? —— conn
3. 讀取 conn.read() 發(fā)送端的 文件名, 保存至本地。
4. 回發(fā) “ok”應(yīng)答 發(fā)送端。
5. 封裝函數(shù),接收文件內(nèi)容 recvFile(文件路徑)
1) f = os.Create(帶有路徑的文件名)
for {
2)從 socket中讀取發(fā)送端發(fā)送的 文件內(nèi)容 。 conn.read(buf)
3)? 將讀到的數(shù)據(jù) 保存至本地文件 f.Write(buf[:n])
4)? 判斷 讀取conn 結(jié)束, 代表文件傳輸完成。 n == 0? break
}
為什么需要context
在go服務(wù)器中,對(duì)于每個(gè)請(qǐng)求的request都是在單獨(dú)的goroutine中進(jìn)行的,處理一個(gè)request也可能設(shè)計(jì)多個(gè)goroutine之間的交互, 使用context可以使開發(fā)者方便的在這些goroutine里傳遞request相關(guān)的數(shù)據(jù)、取消goroutine的signal或截止日期
在并發(fā)程序中,由于超時(shí)、取消操作或者一些異常情況,往往需要進(jìn)行搶占操作或者中斷后續(xù)操作。熟悉channel的朋友應(yīng)該都見過使用done channel來處理此類問題。比如以下這個(gè)例子:
上述例子中定義了一個(gè)buffer為0的channel done, 子協(xié)程運(yùn)行著定時(shí)任務(wù)。如果主協(xié)程需要在某個(gè)時(shí)刻發(fā)送消息通知子協(xié)程中斷任務(wù)退出,那么就可以讓子協(xié)程監(jiān)聽這個(gè)done channel,一旦主協(xié)程關(guān)閉done channel,那么子協(xié)程就可以推出了,這樣就實(shí)現(xiàn)了主協(xié)程通知子協(xié)程的需求。這很好,但是這也是有限的。
如果我們可以在簡(jiǎn)單的通知上附加傳遞額外的信息來控制取消:為什么取消,或者有一個(gè)它必須要完成的最終期限,更或者有多個(gè)取消選項(xiàng),我們需要根據(jù)額外的信息來判斷選擇執(zhí)行哪個(gè)取消選項(xiàng)。
考慮下面這種情況:假如主協(xié)程中有多個(gè)任務(wù)1, 2, …m,主協(xié)程對(duì)這些任務(wù)有超時(shí)控制;而其中任務(wù)1又有多個(gè)子任務(wù)1, 2, …n,任務(wù)1對(duì)這些子任務(wù)也有自己的超時(shí)控制,那么這些子任務(wù)既要感知主協(xié)程的取消信號(hào),也需要感知任務(wù)1的取消信號(hào)。
如果還是使用done channel的用法,我們需要定義兩個(gè)done channel,子任務(wù)們需要同時(shí)監(jiān)聽這兩個(gè)done channel。嗯,這樣其實(shí)好像也還行哈。但是如果層級(jí)更深,如果這些子任務(wù)還有子任務(wù),那么使用done channel的方式將會(huì)變得非常繁瑣且混亂。
我們需要一種優(yōu)雅的方案來實(shí)現(xiàn)這樣一種機(jī)制:
上層任務(wù)取消后,所有的下層任務(wù)都會(huì)被取消;中間某一層的任務(wù)取消后,只會(huì)將當(dāng)前任務(wù)的下層任務(wù)取消,而不會(huì)影響上層的任務(wù)以及同級(jí)任務(wù)。
這個(gè)時(shí)候context就派上用場(chǎng)了。我們首先看看context的結(jié)構(gòu)設(shè)計(jì)和實(shí)現(xiàn)原理。
context接口
先看Context接口結(jié)構(gòu),看起來非常簡(jiǎn)單。
}
Context接口包含四個(gè)方法:
Deadline返回綁定當(dāng)前context的任務(wù)被取消的截止時(shí)間;如果沒有設(shè)定期限,將返回ok == false。
Done 當(dāng)綁定當(dāng)前context的任務(wù)被取消時(shí),將返回一個(gè)關(guān)閉的channel;如果當(dāng)前context不會(huì)被取消,將返回nil。
Err 如果Done返回的channel沒有關(guān)閉,將返回nil;如果Done返回的channel已經(jīng)關(guān)閉,將返回非空的值表示任務(wù)結(jié)束的原因。如果是context被取消,Err將返回Canceled;如果是context超時(shí),Err將返回DeadlineExceeded。
Value 返回context存儲(chǔ)的鍵值對(duì)中當(dāng)前key對(duì)應(yīng)的值,如果沒有對(duì)應(yīng)的key,則返回nil。
可以看到Done方法返回的channel正是用來傳遞結(jié)束信號(hào)以搶占并中斷當(dāng)前任務(wù);Deadline方法指示一段時(shí)間后當(dāng)前goroutine是否會(huì)被取消;以及一個(gè)Err方法,來解釋goroutine被取消的原因;而Value則用于獲取特定于當(dāng)前任務(wù)樹的額外信息。而context所包含的額外信息鍵值對(duì)是如何存儲(chǔ)的呢?其實(shí)可以想象一顆樹,樹的每個(gè)節(jié)點(diǎn)可能攜帶一組鍵值對(duì),如果當(dāng)前節(jié)點(diǎn)上無法找到key所對(duì)應(yīng)的值,就會(huì)向上去父節(jié)點(diǎn)里找,直到根節(jié)點(diǎn)。
emptyCtx
emptyCtx是一個(gè)int類型的變量,但實(shí)現(xiàn)了context的接口。emptyCtx沒有超時(shí)時(shí)間,不能取消,也不能存儲(chǔ)任何額外信息,所以emptyCtx用來作為context樹的根節(jié)點(diǎn)。
Background和TODO只是用于不同場(chǎng)景下: Background通常被用于主函數(shù)、初始化以及測(cè)試中,作為一個(gè)頂層的context,也就是說一般我們創(chuàng)建的context都是基于Background;而TODO是在不確定使用什么context的時(shí)候才會(huì)使用。
用法 :