《Go語言從入門到精通》用Go語言進行網絡服務的開發(fā)_第1頁
《Go語言從入門到精通》用Go語言進行網絡服務的開發(fā)_第2頁
《Go語言從入門到精通》用Go語言進行網絡服務的開發(fā)_第3頁
《Go語言從入門到精通》用Go語言進行網絡服務的開發(fā)_第4頁
《Go語言從入門到精通》用Go語言進行網絡服務的開發(fā)_第5頁
已閱讀5頁,還剩41頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

用Go語言進行網絡服務的開發(fā)Go語言從入門到精通了解如何使用Go語言進行Socket通訊掌握WEB服務器和API的開發(fā)方法01SOCKET02HTTP03SERVERtarget目標掌握Go語言訪問網絡服務的方法目錄導航13.1C/S架構與B/S架構的概念ContentsC/S架構與B/S架構的概念

Socket是有Web服務之前最常用的網絡通信協(xié)議之一,當時常被用于開發(fā)“客戶端/服務器”(Client-Server,簡稱C/S架構)模式的應用系統(tǒng)

Web服務器加瀏覽器的模式一般被稱為B/S架構(即Browser/Server結構)廣義上,B/S架構也是C/S架構中的一種目錄導航13.2基于Socket通訊的客戶端/服務器模式ContentsSocket通訊基于Socket的客戶端/服務器模式指的是服務器和客戶端之間使用Socket協(xié)議進行通信的客戶端/服務器模式

服務器端與客戶端TCP和UDP協(xié)議

長連接和短連接目錄導航13.3基于TCP協(xié)議的Socket客戶端/服務器系統(tǒng)Contents基于TCP的Socket通訊注意,“服務器端”這里指的也是軟件范疇的概念,并非真的物理服務器電腦目錄導航13.4典型的Socket服務器例子Contents//

在本機的8818端口監(jiān)聽TCP協(xié)議的連接listenerT,

errT

:=

net.Listen("tcp",

":8818")if

errT

!=

nil

{

fmt.Printf("監(jiān)聽端口時發(fā)生錯誤:%v\n",

errT.Error())

return}

//

循環(huán)監(jiān)聽,接受連接并對每個連接新建一個goroutine處理for

{

connectionT,

errT

:=

listenerT.Accept()

if

errT

!=

nil

{

fmt.Printf("接受連接時發(fā)生錯誤:%v\n",

errT.Error())

//

此時連接無效,直接繼續(xù)循環(huán)而不啟動goroutine

continue

}

//

新建goroutine來處理連接

go

connectionHandler(connectionT)}負責初始化服務和監(jiān)聽連接的主線程func

connectionHandler(connectionA

net.Conn)

{

defer

connectionA.Close()//

確保連接最終會被關閉

messageCountT

:=

0

for

{//

從連接讀取字符串,每次接收一行(以“\n”換行符為分界)

messageT,

errT

:=

bufio.NewReader(connectionA).ReadString('\n')

if

errT

!=

nil

{

fmt.Printf("從連接讀取數(shù)據(jù)時發(fā)生錯誤(連接將被關閉):%v\n",

errT.Error())

return

}

messageT

=

strings.TrimSpace(messageT)//

去除收到字符串的首尾空白

switch

messageT

case

"exit":

//

收到“exit”則關閉連接,本goroutine將終止

fmt.Fprintf(connectionA,

"連接將被關閉,共收到%v條消息\n",

messageCountT)

return

default:

//

默認是做加上當前系統(tǒng)時間的簡單回復

//

對收到的消息進行計數(shù)

messageCountT++

responseT

:=

fmt.Sprintf("[%v]

已收到%v\n",

time.Now(),

messageT)

connectionA.Write([]byte(responseT))

}

}}負責處理每個連接上的請求的子線程目錄導航13.5典型的Socket客戶端例子ContentsconnectionT,

errT

:=

net.Dial("tcp",

":8818")if

errT

!=

nil

{}defer

connectionT.Close()var

inputT

string

//

inputT用于放置命令行輸入的字符串

for

{

fmt.Scanln(&inputT)

fmt.Fprintf(connectionT,

"%v\n",

strings.TrimSpace(inputT))

responseT,

errT

:=

bufio.NewReader(connectionT).ReadString('\n')

if

errT

!=

nil

{

//

如果服務器已關閉連接,將會受到io.EOF的錯誤,此時應退出goroutine

if

errT

==

io.EOF

{

fmt.Printf("服務器已關閉連接:%v\n",

errT.Error())

return

}

fmt.Printf("從服務器接受響應時發(fā)生錯誤:%v\n",

errT.Error())

break

}

responseT

=

strings.TrimSpace(responseT)

fmt.Printf("服務器響應:%v\n",

responseT)}基于TCP的Socket客戶端簡要示例目錄導航13.6典型UDP服務器的例子ContentslistenerT,

errT

:=

net.ListenPacket("udp",

":8819")if

errT

!=

nil

{

t.Printfln("監(jiān)聽端口時發(fā)生錯誤:%v\n",

errT.Error())

return}

//

保證UDP監(jiān)聽器會被關閉defer

listenerT.Close()

//

聲明用于接收客戶端信息的緩沖區(qū)bufT

:=

make([]byte,

4096)

//

用于收到消息的計數(shù)messageCountT

:=

0基于UDP的Socket服務端示例–監(jiān)聽與初始化for

{

countT,

addressT,

errT

:=

listenerT.ReadFrom(bufT)

if

errT

!=

nil

{

t.Printfln("接收數(shù)據(jù)時發(fā)生錯誤:%v",

errT.Error())

continue

}

messageT

:=

strings.TrimSpace(string(bufT[:countT]))

switch

messageT

{

case

"exit":

//

收到“exit”則關閉連接,程序將終止

listenerT.WriteTo([]byte(fmt.Sprintf("連接將被關閉,共收到%v條消息\n",

messageCountT)),

addressT)

return

default:

//

默認是做加上當前系統(tǒng)時間的簡單回復

messageCountT++

t.Printfln("收到:%v",

messageT)

responseT

:=

fmt.Sprintf("[%v]

已收到%v\n",

time.Now(),

messageT)

listenerT.WriteTo([]byte(responseT),

addressT)

}}基于UDP的Socket服務端示例–循環(huán)監(jiān)聽并處理目錄導航13.7典型UDP客戶端的例子ContentsconnectionT,

errT

:=

net.Dial("udp",

`localhost:8819`)if

errT

!=

nil

{

t.Printfln("建立UDP連接時發(fā)生錯誤:%v",

errT)

return}defer

connectionT.Close()

_,

errT

=

connectionT.Write([]byte(os.Args[1]))if

errT

!=

nil

{

t.Printfln("發(fā)送數(shù)據(jù)時發(fā)生錯誤:%v",

errT)

return}

bufT

:=

make([]byte,

4096)

countT,

errT

:=

connectionT.Read(bufT)if

errT

!=

nil

{

t.Printfln("讀取服務器響應時發(fā)生錯誤:%v",

errT)

return}

t.Printfln("服務器響應:%v",

string(bufT[:countT]))基于UDP的Socket客戶端示例目錄導航13.8用Go語言搭建簡單的WEB服務器Contentsfunc

httpHandler(responseA

http.ResponseWriter,

requestA

*http.Request)

{

responseA.WriteHeader(http.StatusOK)

responseA.Write([]byte("Hello!"))}

func

main()

{

http.HandleFunc("/",

httpHandler)

errT

:=

http.ListenAndServe(":8838",

nil)

if

errT

!=

nil

{

fmt.Printf("打開HTTP監(jiān)聽端口時發(fā)生錯誤:%v\n",

errT.Error())

}

}最簡單的WEB服務器比Socket還簡單的WEB服務器搭建最簡單的WEB服務器——運行效果目錄導航13.9搭建簡單的文件服務器Contents

http.Handle("/",

http.FileServer(http.Dir(`c:\test`)))

errT

:=

http.ListenAndServe(":8838",

nil)

if

errT

!=

nil

{

fmt.Printf("打開HTTP監(jiān)聽端口時發(fā)生錯誤:%v\n",

errT.Error())

}幾行代碼實現(xiàn)目錄文件分享的WEB服務器文件服務器效果目錄導航13.10搭建靜態(tài)文件型的Web網站服務器Contents靜態(tài)WEB服務器

前端:HTML+CSS+JavaScript

后端:Go語言

動態(tài)變化由前端的JavaScript負責實現(xiàn)http.HandleFunc("/w/",

serveStaticDir)

err

:=

http.ListenAndServe(":8080",

nil)if

err

!=

nil

{

t.Printfln("打開HTTP監(jiān)聽端口時發(fā)生錯誤:%v",

err.Error())}

主服務線程func

serveStaticDir(w

http.ResponseWriter,

r

*http.Request)

{

staticFileHandler

:=

http.StripPrefix("/w/",

http.FileServer(http.Dir(`c:\test\w`)))

urlPathT

:=

r.URL.Path

filePathT

:=

filepath.Join(`c:\test`,

path.Clean(urlPathT))

info,

err

:=

os.Lstat(filePathT)

if

err

==

nil

{

if

!info.IsDir()

{

staticFileHandler.ServeHTTP(w,

r)

}

else

{

if

t.FileExists(filepath.Join(filePathT,

"index.html"))

{

staticFileHandler.ServeHTTP(w,

r)

}

else

{

http.NotFound(w,

r)

}

}

}

else

{

http.NotFound(w,

r)

}

}HTTP請求處理函數(shù)對于目錄做特殊處理:尋找是否有index.html目錄導航13.11混合不同方式的Web服務器Contentshttp.HandleFunc("/w/",

staticDirHandler)http.Handle("/sub1/",

http.StripPrefix("/sub1/",

http.FileServer(http.Dir(`c:\test\sub1`))))

http.HandleFunc("/",

welcomeHandler)對不同“路徑”的請求分別處理目錄導航13.12搭建提供網絡接口服務的API服務器ContentsWEBAPI服務器

WEBAPI服務器一般以JSON格式的數(shù)據(jù)返回,并不直接返回可顯示的網頁等

客戶端一般使用AJAX請求來訪問WEBAPI

服務端要能夠處理客戶端傳遞的參數(shù),一般會以GET或POST等方式傳遞

存在跨域訪問問題,因此服務器要支持JSONPfunc

japiHandler(w

http.ResponseWriter,

r

*http.Request)

{

reqT

:=

r.FormValue("req")

returnObjectT

:=

make(map[string]string)

switch

reqT

{

case

"":

returnObjectT["Status"]

=

"fail"

returnObjectT["Value"]

=

fmt.Sprintf("請求不能為空")

case

"getTime":

returnObjectT["Status"]

=

"success"

returnObjectT["Value"]

=

fmt.Sprintf("%v",

time.Now())

}

bufT,

_

:=

json.Marshal(returnObjectT)

w.Header().Set("Access-Control-Allow-Origin",

"*")

w.Header().Set("Content-Type",

"text/json;charset=utf-8")

w.WriteHeader(http.StatusOK)

w.Write(bufT)}核心代碼WEBAPI請求的服務器響應示例目錄導航13.13Web服務器的路由管理Contents通過?+&傳遞參數(shù)或者組合路徑控制處理邏輯目錄導航13.14動態(tài)網頁的生成Contents動態(tài)網頁技術“動態(tài)網頁”技術,指的是Web服務器接收到請求后動態(tài)生成網頁內容,填寫網頁中的HTML代碼,而不是直接將文件系統(tǒng)中存在的靜態(tài)網頁文件直接推送給用戶動態(tài)網頁技術典型的代表有ASP、ASP.NET、JSP、PHP等

動態(tài)網頁安全性較好,并具有良好的可拓展性func

dynamicHandler(w

http.ResponseWriter,

r

*http.Request)

{

urlPathT

:=

strings.TrimPrefix(r.RequestURI,

"/dynamic/")

var

htmlTextT

string

switch

urlPathT

{

case

"index.html",

"",

"next/test.html":

tmplFilePathT

:=

filepath.Join(`c:\test\tmpl`,

"indextmpl.html")

templateT,

errT

:=

template.ParseFiles(tmplFilePathT)

if

errT

!=

nil

{

w.WriteHeader(http.StatusInternalServerError)

return

}

dataT

:=

map[string]interface{}{

"RemoteAddr":

r.RemoteAddr,

"RandomStrings":

[]string{t.GenerateRandomString(5,

8,

true,

true,

true,

false,

false,

false),

t.GenerateRandomString(5,

8,

true,

true,

true,

false,

false,

false),

t.GenerateRandomString(5,

8,

true,

true,

true,

false,

false,

false)},

}

var

sb

strings.Builder

templateT.ExecuteTemplate(&sb,

"indextmpl.html",

dataT)

htmlTextT

=

sb.String()

default:

http.NotFound(w,

r)

return

}

w.Header().Set("Content-Type",

"text/html;charset=utf-8")

w.WriteHeader(http.StatusOK)

w.Write([]byte(htmlTextT))}核心代碼目錄導航13.15提供HTTPS方式訪問ContentserrT

:=

http.ListenAndServeTLS(":443",

`c:\test\test.crt`,

`c:\test\test.key`,

nil)if

errT

!=

nil

{

t.Printfln("打開HTTPS監(jiān)聽端口時發(fā)生錯誤:%v",

errT.Error())}準備SSL證書后啟動HTTPS端口服務HTTPS的默認端口是443目錄導航13.16第三方的WEB開發(fā)包ContentsWEB服務有關的優(yōu)秀第三方包

Beego

Gin……routerT

:=

gin.Default()

routerT.GET("/generatePassword/:len",

func(c

*gin.Context)

{

lenStrT

:=

c.Param("len")

var

lenT

int

_,

errT

:=

fmt.Sscanf(le

溫馨提示

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

評論

0/150

提交評論