Go微服務(wù)網(wǎng)關(guān)的實現(xiàn)_第1頁
Go微服務(wù)網(wǎng)關(guān)的實現(xiàn)_第2頁
Go微服務(wù)網(wǎng)關(guān)的實現(xiàn)_第3頁
Go微服務(wù)網(wǎng)關(guān)的實現(xiàn)_第4頁
Go微服務(wù)網(wǎng)關(guān)的實現(xiàn)_第5頁
已閱讀5頁,還剩16頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第Go微服務(wù)網(wǎng)關(guān)的實現(xiàn)目錄Go微服務(wù)網(wǎng)關(guān)網(wǎng)絡(luò)基礎(chǔ)大綱OSI七層網(wǎng)絡(luò)協(xié)議三次握手與四次揮手為啥會出現(xiàn)大量的close_waitTCP為啥需要擁塞控制TCP擁塞控制為啥會出現(xiàn)粘包,拆包,如何處理產(chǎn)生tcp粘包和拆包的原因如何解決拆包粘包如何獲取完整應(yīng)用數(shù)據(jù)報文基于golang實現(xiàn)TCP,UDP,Http服務(wù)端與客戶端

Go微服務(wù)網(wǎng)關(guān)

從核心原理理解網(wǎng)關(guān)的本質(zhì)

網(wǎng)關(guān)具備的基本功能:

支持多種協(xié)議代理:tcp/http/websocket/grpc支持多種負載均衡策略:輪詢,權(quán)重輪詢,hash一致性輪詢支持下游的服務(wù)發(fā)現(xiàn):主動探測/自動服務(wù)發(fā)現(xiàn)支持橫向擴展:加機器就能解決高并發(fā)

借助網(wǎng)關(guān)處理高可用,高并發(fā)

限流:請求QPS限制熔斷:錯誤率達閾值則服務(wù)熔斷降級:確保核心業(yè)務(wù)可用權(quán)限認證:請求攔截

網(wǎng)絡(luò)基礎(chǔ)大綱

OSI七層網(wǎng)絡(luò)協(xié)議

經(jīng)典協(xié)議與數(shù)據(jù)包

http協(xié)議

GET/HTTP/1.1

Host:

User-Agent:curl/7.55.1

Accept:*/*

Websocket握手協(xié)議

三次握手與四次揮手

三次握手的最主要的目的是保證連接是全雙工的,可靠更多的是通過重傳機制來保證的

因為連接是全雙工的,雙方必須都收到對方的FIN包及確認才可關(guān)閉

TCP報文格式:

其中比較重要的字段有:

(1)序號(sequencenumber):Seq序號,占32位,用來標識從TCP源端向目的端發(fā)送的字節(jié)流,發(fā)起方發(fā)送數(shù)據(jù)時對此進行標記。

(2)確認號(acknowledgementnumber):Ack序號,占32位,只有ACK標志位為1時,確認序號字段才有效,Ack=Seq+1。

(3)標志位(Flags):共6個,即URG、ACK、PSH、RST、SYN、FIN等。具體含義如下:

URG:緊急指針(urgentpointer)有效。ACK:確認序號有效。PSH:接收方應(yīng)該盡快將這個報文交給應(yīng)用層。RST:重置連接。SYN:發(fā)起一個新連接。FIN:釋放一個連接。

需要注意的是:

不要將確認序號Ack與標志位中的ACK搞混了。確認方Ack=發(fā)起方Seq+1,兩端配對。

三次握手連接:

(1)首先客戶端向服務(wù)器端發(fā)送一段TCP報文,其中:

標記位為`SYN,表示請求建立新連接序號為Seq=X(X一般為1);隨后客戶端進入SYN-SENT階段。

(2)服務(wù)器端接收到來自客戶端的TCP報文之后,結(jié)束LISTEN階段。并返回一段TCP報文,其中:

標志位為SYN和ACK,表示確認客戶端的報文Seq序號有效,服務(wù)器能正常接收客戶端發(fā)送的數(shù)據(jù),并同意創(chuàng)建新連接(即告訴客戶端,服務(wù)器收到了你的數(shù)據(jù));序號為Seq=y;確認號為Ack=x+1,表示收到客戶端的序號Seq并將其值加1作為自己確認號Ack的值;隨后服務(wù)器端進入SYN-RCVD階段。

(3)客戶端接收到來自服務(wù)器端的確認收到數(shù)據(jù)的TCP報文之后,明確了從客戶端到服務(wù)器的數(shù)據(jù)傳輸是正常的,結(jié)束SYN-SENT階段。并返回最后一段TCP報文。其中:

標志位為ACK,表示確認收到服務(wù)器端同意連接的信號(即告訴服務(wù)器,我知道你收到我發(fā)的數(shù)據(jù)了);序號為Seq=x+1,表示收到服務(wù)器端的確認號Ack,并將其值作為自己的序號值;確認號為Ack=y+1,表示收到服務(wù)器端序號Seq,并將其值加1作為自己的確認號Ack的值;隨后客戶端進入ESTABLISHED階段。

服務(wù)器收到來自客戶端的確認收到服務(wù)器數(shù)據(jù)的TCP報文之后,明確了從服務(wù)器到客戶端的數(shù)據(jù)傳輸是正常的。結(jié)束SYN-SENT階段,進入ESTABLISHED階段。

在客戶端與服務(wù)器端傳輸?shù)腡CP報文中,雙方的確認號Ack和序號Seq的值,都是在彼此Ack和Seq值的基礎(chǔ)上進行計算的,這樣做保證了TCP報文傳輸?shù)倪B貫性。一旦出現(xiàn)某一方發(fā)出的TCP報文丟失,便無法繼續(xù)握手,以此確保了三次握手的順利完成。

四次揮手:

(1)首先客戶端想要釋放連接,向服務(wù)器端發(fā)送一段TCP報文,其中:

標記位為FIN,表示請求釋放連接;序號為Seq=U;隨后客戶端進入FIN-WAIT-1階段,即半關(guān)閉階段。并且停止在客戶端到服務(wù)器端方向上發(fā)送數(shù)據(jù),但是客戶端仍然能接收從服務(wù)器端傳輸過來的數(shù)據(jù)。注意:這里不發(fā)送的是正常連接時傳輸?shù)臄?shù)據(jù)(非確認報文),而不是一切數(shù)據(jù),所以客戶端仍然能發(fā)送ACK確認報文。

(2)服務(wù)器端接收到從客戶端發(fā)出的TCP報文之后,確認了客戶端想要釋放連接,隨后服務(wù)器端結(jié)束ESTABLISHED階段,進入CLOSE-WAIT階段(半關(guān)閉狀態(tài))并返回一段TCP報文,其中:

標記位為ACK,表示接收到客戶端發(fā)送的釋放連接的請求;序號為Seq=V;確認號為Ack=U+1,表示是在收到客戶端報文的基礎(chǔ)上,將其序號Seq值加1作為本段報文確認號Ack的值;隨后服務(wù)器端開始準備釋放服務(wù)器端到客戶端方向上的連接。客戶端收到從服務(wù)器端發(fā)出的TCP報文之后,確認了服務(wù)器收到了客戶端發(fā)出的釋放連接請求,隨后客戶端結(jié)束FIN-WAIT-1階段,進入FIN-WAIT-2階段

前兩次揮手既讓服務(wù)器端知道了客戶端想要釋放連接,也讓客戶端知道了服務(wù)器端了解了自己想要釋放連接的請求。于是,可以確認關(guān)閉客戶端到服務(wù)器端方向上的連接了

(3)服務(wù)器端自從發(fā)出ACK確認報文之后,經(jīng)過CLOSED-WAIT階段,做好了釋放服務(wù)器端到客戶端方向上的連接準備,再次向客戶端發(fā)出一段TCP報文,其中:

標記位為FIN,ACK,表示已經(jīng)準備好釋放連接了。注意:這里的ACK并不是確認收到服務(wù)器端報文的確認報文。序號為Seq=W;確認號為Ack=U+1;表示是在收到客戶端報文的基礎(chǔ)上,將其序號Seq值加1作為本段報文確認號Ack的值。

隨后服務(wù)器端結(jié)束CLOSE-WAIT階段,進入LAST-ACK階段。并且停止在服務(wù)器端到客戶端的方向上發(fā)送數(shù)據(jù),但是服務(wù)器端仍然能夠接收從客戶端傳輸過來的數(shù)據(jù)。

(4)客戶端收到從服務(wù)器端發(fā)出的TCP報文,確認了服務(wù)器端已做好釋放連接的準備,結(jié)束FIN-WAIT-2階段,進入TIME-WAIT階段,并向服務(wù)器端發(fā)送一段報文,其中:

標記位為ACK,表示接收到服務(wù)器準備好釋放連接的信號。序號為Seq=U+1;表示是在收到了服務(wù)器端報文的基礎(chǔ)上,將其確認號Ack值作為本段報文序號的值。確認號為Ack=W+1;表示是在收到了服務(wù)器端報文的基礎(chǔ)上,將其序號Seq值作為本段報文確認號的值。隨后客戶端開始在TIME-WAIT階段等待2MSL

為什么要客戶端要等待2MSL呢?見后文。

服務(wù)器端收到從客戶端發(fā)出的TCP報文之后結(jié)束LAST-ACK階段,進入CLOSED階段。由此正式確認關(guān)閉服務(wù)器端到客戶端方向上的連接。

客戶端等待完2MSL之后,結(jié)束TIME-WAIT階段,進入CLOSED階段,由此完成四次揮手。

后兩次揮手既讓客戶端知道了服務(wù)器端準備好釋放連接了,也讓服務(wù)器端知道了客戶端了解了自己準備好釋放連接了。于是,可以確認關(guān)閉服務(wù)器端到客戶端方向上的連接了,由此完成四次揮手。

與三次揮手一樣,在客戶端與服務(wù)器端傳輸?shù)腡CP報文中,雙方的確認號Ack和序號Seq的值,都是在彼此Ack和Seq值的基礎(chǔ)上進行計算的,這樣做保證了TCP報文傳輸?shù)倪B貫性,一旦出現(xiàn)某一方發(fā)出的TCP報文丟失,便無法繼續(xù)揮手,以此確保了四次揮手的順利完成。

為什么客戶端在TIME-WAIT階段要等2MSL

為的是確認服務(wù)器端是否收到客戶端發(fā)出的ACK確認報文保證TCP協(xié)議的全雙共連接能夠可靠關(guān)閉保證這次連接的重復(fù)數(shù)據(jù)段從網(wǎng)絡(luò)中消失

當客戶端發(fā)出最后的ACK確認報文時,并不能確定服務(wù)器端能夠收到該段報文。所以客戶端在發(fā)送完ACK確認報文之后,會設(shè)置一個時長為2MSL的計時器。MSL指的是(最大的生命周期)MaximumSegmentLifetime:(30秒1分鐘)一段TCP報文在傳輸過程中的最大生命周期。2MSL即是服務(wù)器端發(fā)出為FIN報文和客戶端發(fā)出的ACK確認報文所能保持有效的最大時長。

服務(wù)器端在1MSL內(nèi)沒有收到客戶端發(fā)出的ACK確認報文,就會再次向客戶端發(fā)出FIN報文;

如果客戶端在2MSL內(nèi),再次收到了來自服務(wù)器端的FIN報文,說明服務(wù)器端由于各種原因沒有接收到客戶端發(fā)出的ACK確認報文??蛻舳嗽俅蜗蚍?wù)器端發(fā)出ACK確認報文,計時器重置,重新開始2MSL的計時;否則客戶端在2MSL內(nèi)沒有再次收到來自服務(wù)器端的FIN報文,說明服務(wù)器端正常接收了ACK確認報文,客戶端可以進入CLOSED階段,完成四次揮手。

所以,客戶端要經(jīng)歷時長為2SML的TIME-WAIT階段;這也是為什么客戶端比服務(wù)器端晚進入CLOSED階段的原因

為啥會出現(xiàn)大量的close_wait

首先close_wait一般出現(xiàn)在被動關(guān)閉方并發(fā)請求太多導(dǎo)致被動關(guān)閉方未及時釋放端口資源導(dǎo)致

funcmain(){

//1、監(jiān)聽端口

listener,err:=net.Listen("tcp",":9090")

iferr!=nil{

fmt.Printf("listenfail,err:%v\n",err)

return

//2.建立套接字連接

for{

conn,err:=listener.Accept()

iferr!=nil{

fmt.Printf("acceptfail,err:%v\n",err)

continue

//3.創(chuàng)建處理協(xié)程

gofunc(connnet.Conn){

deferconn.Close()//思考題:這里不填寫會有啥問題?

//服務(wù)端就有一個close,wait狀態(tài),客戶端就有一個finally狀態(tài)

for{

varbuf[128]byte

n,err:=conn.Read(buf[:])

iferr!=nil{

fmt.Printf("readfromconnectfailed,err:%v\n",err)

break

str:=string(buf[:n])

fmt.Printf("receivefromclient,data:%v\n",str)

}(conn)

TCP為啥需要流量控制

由于通訊雙方,網(wǎng)速不同。通訊方任一方發(fā)送過快都會導(dǎo)致對方的消息處理不過來,所以就需要數(shù)據(jù)放到緩沖區(qū)中如果緩沖區(qū)滿了,發(fā)送方還在瘋狂發(fā)送,那接收方只能把數(shù)據(jù)包丟棄,因此我們需要控制發(fā)送速率我們緩沖區(qū)剩余大小稱之為接收窗口,用變量win表示,如果win=0,則發(fā)送方停止發(fā)送

TCP為啥需要擁塞控制

流量控制與擁塞控制是兩個概念,擁塞控制是調(diào)節(jié)網(wǎng)絡(luò)的負載接收方網(wǎng)絡(luò)資源繁忙,因未及時響應(yīng)ACK導(dǎo)致發(fā)送方重傳大量的數(shù)據(jù),這樣將會導(dǎo)致網(wǎng)絡(luò)更加的擁堵?lián)砣刂剖莿討B(tài)調(diào)整win大小,不只是依賴緩沖區(qū)大小去確定窗口大小

TCP擁塞控制

慢開始和擁塞避免快速重傳和快速恢復(fù)

優(yōu)化步驟3到步驟4:因為網(wǎng)絡(luò)擁塞,有24直接降到1,會造成堵塞

為啥會出現(xiàn)粘包,拆包,如何處理

粘包、拆包表現(xiàn)形式

現(xiàn)在假設(shè)客戶端向服務(wù)端連續(xù)發(fā)送了兩個數(shù)據(jù)包,用packet1和packet2來表示,那么服務(wù)端收到的數(shù)據(jù)可以分為三種,現(xiàn)列舉如下:

第一種情況,接收端正常收到兩個數(shù)據(jù)包,即沒有發(fā)生拆包和粘包的現(xiàn)象,此種情況不在本文的討論范圍內(nèi)。

第二種情況,接收端只收到一個數(shù)據(jù)包,由于TCP是不會出現(xiàn)丟包的,所以這一個數(shù)據(jù)包中包含了發(fā)送端發(fā)送的兩個數(shù)據(jù)包的信息,這種現(xiàn)象即為粘包。這種情況由于接收端不知道這兩個數(shù)據(jù)包的界限,所以對于接收端來說很難處理。

第三種情況,這種情況有兩種表現(xiàn)形式,如下圖。接收端收到了兩個數(shù)據(jù)包,但是這兩個數(shù)據(jù)包要么是不完整的,要么就是多出來一塊,這種情況即發(fā)生了拆包和粘包。這兩種情況如果不加特殊處理,對于接收端同樣是不好處理的。

產(chǎn)生tcp粘包和拆包的原因

我們知道tcp是以流動的方式傳輸數(shù)據(jù),傳輸?shù)淖钚挝粸橐粋€報文段(segment)。tcpHeader中有個Options標識位,常見的標識為mss(MaximumSegmentSize)指的是,連接層每次傳輸?shù)臄?shù)據(jù)有個最大限制MTU(MaximumTransmissionUnit),一般是1500比特,超過這個量要分成多個報文段,mss則是這個最大限制減去TCP的header,光是要傳輸?shù)臄?shù)據(jù)的大小,一般為1460比特。換算成字節(jié),也就是180多字節(jié)。

tcp為提高性能,發(fā)送端會將需要發(fā)送的數(shù)據(jù)發(fā)送到緩沖區(qū),等待緩沖區(qū)滿了之后,再將緩沖中的數(shù)據(jù)發(fā)送到接收方。同理,接收方也有緩沖區(qū)這樣的機制,來接收數(shù)據(jù)。

發(fā)生TCP粘包、拆包主要是由于下面一些原因:

應(yīng)用程序?qū)懭氲臄?shù)據(jù)大于套接字緩沖區(qū)大小,這將會發(fā)生拆包。應(yīng)用程序?qū)懭霐?shù)據(jù)小于套接字緩沖區(qū)大小,網(wǎng)卡將應(yīng)用多次寫入的數(shù)據(jù)發(fā)送到網(wǎng)絡(luò)上,這將會發(fā)生粘包。進行mss(最大報文長度)大小的TCP分段,當TCP報文長度-TCP頭部長度mss的時候?qū)l(fā)生拆包。接收方法不及時讀取套接字(socket)緩沖區(qū)數(shù)據(jù),這將發(fā)生粘包。

如何解決拆包粘包

既然知道了tcp是無界的數(shù)據(jù)流,且協(xié)議本身無法避免粘包,拆包的發(fā)生,那我們只能在應(yīng)用層數(shù)據(jù)協(xié)議上,加以控制。通常在制定傳輸數(shù)據(jù)時,可以使用如下方法:

使用帶消息頭的協(xié)議、消息頭存儲消息開始標識及消息長度信息,服務(wù)端獲取消息頭的時候解析出消息長度,然后向后讀取該長度的內(nèi)容。設(shè)置定長消息,服務(wù)端每次讀取既定長度的內(nèi)容作為一條完整消息。設(shè)置消息邊界,服務(wù)端從網(wǎng)絡(luò)流中按消息編輯分離出消息內(nèi)容。

如何獲取完整應(yīng)用數(shù)據(jù)報文

使用帶消息頭的協(xié)議,頭部寫入包長度,然后在讀取包內(nèi)容設(shè)置定長消息,每次讀取定長內(nèi)容,長度不夠時空位補固定字符設(shè)置消息邊界,服務(wù)端從網(wǎng)絡(luò)流中按消息邊界分離出消息內(nèi)容,一般使用\n更為復(fù)雜的協(xié)議:json,protobuf

如何獲取完整的數(shù)據(jù)報文

funcmain(){

//類比接收緩沖區(qū)

bytesBuffer:=bytes.NewBuffer([]byte{})

//發(fā)送

iferr:=Encode(bytesBuffer,"helloworld0!!");err!=nil{

panic(err)

iferr:=Encode(bytesBuffer,"helloworld1!!");err!=nil{

panic(err)

//讀取

for{

ifbt,err:=Decode(bytesBuffer);err==nil{

fmt.Println(string(bt))

continue

break

如何獲取完整的數(shù)據(jù)報文

tcp_server

funcmain(){

//simpletcpserver

//1.監(jiān)聽端口

listener,err:=net.Listen("tcp",":9090")

iferr!=nil{

fmt.Printf("tcpListenfail,err:%v\n",err)

return

//2.接受請求

for{

conn,err:=listener.Accept()

iferr!=nil{

fmt.Printf("tcpAcceptfail,err:%v\n",err)

continue

//3.創(chuàng)建協(xié)程

goprocess(conn)

//4.創(chuàng)建的協(xié)程里面實現(xiàn)解碼的功能

funcprocess(connnet.Conn){

deferconn.Close()

for{

bt,err:=unpack.Decode(conn)

iferr!=nil{

fmt.Printf("readfromconnectfailed,err:%v\n",err)

break

str:=string(bt)

fmt.Printf("receivefromclient,data:%v\n",str)

tcp_client

funcmain(){

//1.連接tcp服務(wù)器

conn,err:=net.Dial("tcp","localhost:9090")

deferconn.Close()

iferr!=nil{

fmt.Printf("connectfailed,err:%v\n",err.Error())

return

//2.實現(xiàn)編碼

unpack.Encode(conn,"helloworld0!!!")

**unpack**:實現(xiàn)編碼(encode)和解碼(docode)功能

constMsg_Header="12345678"

//編碼

funcEncode(bytesBufferio.Writer,contentstring)error{

//msg_header+content_len+content

//8+4+content_len

iferr:=binary.Write(bytesBuffer,binary.BigEndian,[]byte(Msg_Header));err!=nil{

returnerr

clen:=int32(len([]byte(content)))

//binary.BigEndian大端字節(jié)實現(xiàn)的加密,

iferr:=binary.Write(bytesBuffer,binary.BigEndian,clen);err!=nil{

returnerr

iferr:=binary.Write(bytesBuffer,binary.BigEndian,[]byte(content));err!=nil{

returnerr

returnnil

//解碼

funcDecode(bytesBufferio.Reader)(bodyBuf[]byte,errerror){

MagicBuf:=make([]byte,len(Msg_Header))

//先讀取header的大小

if_,err=io.ReadFull(bytesBuffer,MagicBuf);err!=nil{

returnnil,err

//比較得到的header和實際的Msg_Header是否相同

ifstring(MagicBuf)!=Msg_Header{

returnnil,errors.New("msg_headererror")

lengthBuf:=make([]byte,4)

if_,err=io.ReadFull(bytesBuffer,lengthBuf);err!=nil{

returnnil,err

//binary.BigEndian大端字節(jié)實現(xiàn)的解密,得到實際數(shù)據(jù)的長度

length:=binary.BigEndian.Uint32(lengthBuf)

bodyBuf=make([]byte,length)

if_,err=io.ReadFull(bytesBuffer,bodyBuf);err!=nil{

returnnil,err

returnbodyBuf,err

基于golang實現(xiàn)TCP,UDP,Http服務(wù)端與客戶端

golang實現(xiàn)UDP服務(wù)端與客戶端

UDP服務(wù)端:

funcmain(){

//1.監(jiān)聽端口

listen,err:=net.ListenUDP("udp",net.UDPAddr{

IP:net.IPv4(0,0,0,0),

Port:9090,

iferr!=nil{

fmt.Printf("listenudpfailed,err:%v\n",err)

return

//2.循環(huán)讀取消息內(nèi)容

for{

vardata[1024]byte

n,addr,err:=listen.ReadFromUDP(data[:])

iferr!=nil{

fmt.Printf("readfailedfromaddr:%v,err%v\n",addr,err)

break

gofunc(){

//3.回復(fù)數(shù)據(jù)

fmt.Printf("addr:%vdata:%vcount:%v\n",addr,string(data[:n]),n)

_,err=listen.WriteToUDP([]byte("receivedsuccess!"),addr)

iferr!=nil{

fmt.Printf("writefailed,err:%v\n",err)

return

udp客戶端

funcmain(){

//1.連接udp服務(wù)器

conn,err:=net.DialUDP("udp",nil,net.UDPAddr{

IP:net.IPv4(127,0,0,1),

Port:9090,

iferr!=nil{

fmt.Printf("connectfailed,err%v\n",err)

return

fori:=0;i100;i++{

//2.發(fā)送數(shù)據(jù)

_,err:=conn.Write([]byte("hello"+

"server"))

iferr!=nil{

fmt.Printf("senddatafailed,err:%v\n",err)

return

//3.接收數(shù)據(jù)

result:=make([]byte,1024)

n,remoteAddr,err:=conn.ReadFromUDP(result)

iferr!=nil{

fmt.Printf("readdatafailed,err:%v\n",err)

return

fmt.Printf("receivefromaddr:%vdata:%v\n",remoteAddr,string(result[:n]))

golang實現(xiàn)tcp的服務(wù)端和客戶端

tcp服務(wù)端

funcmain(){

//1、監(jiān)聽端口

listener,err:=net.Listen("tcp",":9090")

iferr!=nil{

fmt.Printf("listenfail,err:%v\n",err)

return

//2.建立套接字連接

for{

conn,err:=listener.Accept()

iferr!=nil{

fmt.Printf("acceptfail,err:%v\n",err)

continue

//3.創(chuàng)建處理協(xié)程

goprocess(conn)

funcprocess(connnet.Conn){

deferconn.Close()//思考題:這里不填寫會有啥問題?

for{

varbuf[128]byte

n,err:=conn.Read(buf[:])

iferr!=nil{

fmt.Printf("readfromconnectfailed,err:%v\n",err)

break

str:=string(buf[:n])

fmt.Printf("fromclient,data:%v\n",str)

tcp客戶端

golang實現(xiàn)Http的服務(wù)端和客戶端

http服務(wù)端

var(

Addr=":8000"

//http的服務(wù)器

funcmain(){

//1.創(chuàng)建路由器

mux:=http.NewServeMux()

//2.設(shè)置路由規(guī)則

mux.HandleFunc("/bye",sayBye)

//3.創(chuàng)建服務(wù)器

server:=http.Server{

Addr:Addr,

WriteTimeout:time.Second*3,

Handler:mux,

//4.監(jiān)聽端口并提供服務(wù)

log.Println("startinghttpServerat"+Addr)

log.Fatal(server.ListenAndServe())

funcsayBye(whttp.ResponseWriter,r*http.Request){

time.Sleep(1*time.Second)

w.Write([]byte("byebye,thisishttpserver"))

http客戶端

funcmain(){

//1.創(chuàng)建連接池

transport:=http.Transport{

DialContext:(net.Dialer{

Timeout:3

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論