《Go语言从入门到精通》用Go语言进行网络服务的开发_第1页
《Go语言从入门到精通》用Go语言进行网络服务的开发_第2页
《Go语言从入门到精通》用Go语言进行网络服务的开发_第3页
《Go语言从入门到精通》用Go语言进行网络服务的开发_第4页
《Go语言从入门到精通》用Go语言进行网络服务的开发_第5页
已阅读5页,还剩41页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

用Go语言进行网络服务的开发Go语言从入门到精通了解如何使用Go语言进行Socket通讯掌握WEB服务器和API的开发方法01SOCKET02HTTP03SERVERtarget目标掌握Go语言访问网络服务的方法目录导航13.1C/S架构与B/S架构的概念ContentsC/S架构与B/S架构的概念

Socket是有Web服务之前最常用的网络通信协议之一,当时常被用于开发“客户端/服务器”(Client-Server,简称C/S架构)模式的应用系统

Web服务器加浏览器的模式一般被称为B/S架构(即Browser/Server结构)广义上,B/S架构也是C/S架构中的一种目录导航13.2基于Socket通讯的客户端/服务器模式ContentsSocket通讯基于Socket的客户端/服务器模式指的是服务器和客户端之间使用Socket协议进行通信的客户端/服务器模式

服务器端与客户端TCP和UDP协议

长连接和短连接目录导航13.3基于TCP协议的Socket客户端/服务器系统Contents基于TCP的Socket通讯注意,“服务器端”这里指的也是软件范畴的概念,并非真的物理服务器电脑目录导航13.4典型的Socket服务器例子Contents//

在本机的8818端口监听TCP协议的连接listenerT,

errT

:=

net.Listen("tcp",

":8818")if

errT

!=

nil

{

fmt.Printf("监听端口时发生错误:%v\n",

errT.Error())

return}

//

循环监听,接受连接并对每个连接新建一个goroutine处理for

{

connectionT,

errT

:=

listenerT.Accept()

if

errT

!=

nil

{

fmt.Printf("接受连接时发生错误:%v\n",

errT.Error())

//

此时连接无效,直接继续循环而不启动goroutine

continue

}

//

新建goroutine来处理连接

go

connectionHandler(connectionT)}负责初始化服务和监听连接的主线程func

connectionHandler(connectionA

net.Conn)

{

defer

connectionA.Close()//

确保连接最终会被关闭

messageCountT

:=

0

for

{//

从连接读取字符串,每次接收一行(以“\n”换行符为分界)

messageT,

errT

:=

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

if

errT

!=

nil

{

fmt.Printf("从连接读取数据时发生错误(连接将被关闭):%v\n",

errT.Error())

return

}

messageT

=

strings.TrimSpace(messageT)//

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

switch

messageT

case

"exit":

//

收到“exit”则关闭连接,本goroutine将终止

fmt.Fprintf(connectionA,

"连接将被关闭,共收到%v条消息\n",

messageCountT)

return

default:

//

默认是做加上当前系统时间的简单回复

//

对收到的消息进行计数

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("从服务器接受响应时发生错误:%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("监听端口时发生错误:%v\n",

errT.Error())

return}

//

保证UDP监听器会被关闭defer

listenerT.Close()

//

声明用于接收客户端信息的缓冲区bufT

:=

make([]byte,

4096)

//

用于收到消息的计数messageCountT

:=

0基于UDP的Socket服务端示例–监听与初始化for

{

countT,

addressT,

errT

:=

listenerT.ReadFrom(bufT)

if

errT

!=

nil

{

t.Printfln("接收数据时发生错误:%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:

//

默认是做加上当前系统时间的简单回复

messageCountT++

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

messageT)

responseT

:=

fmt.Sprintf("[%v]

已收到%v\n",

time.Now(),

messageT)

listenerT.WriteTo([]byte(responseT),

addressT)

}}基于UDP的Socket服务端示例–循环监听并处理目录导航13.7典型UDP客户端的例子ContentsconnectionT,

errT

:=

net.Dial("udp",

`localhost:8819`)if

errT

!=

nil

{

t.Printfln("建立UDP连接时发生错误:%v",

errT)

return}defer

connectionT.Close()

_,

errT

=

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

errT

!=

nil

{

t.Printfln("发送数据时发生错误:%v",

errT)

return}

bufT

:=

make([]byte,

4096)

countT,

errT

:=

connectionT.Read(bufT)if

errT

!=

nil

{

t.Printfln("读取服务器响应时发生错误:%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监听端口时发生错误:%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监听端口时发生错误:%v\n",

errT.Error())

}几行代码实现目录文件分享的WEB服务器文件服务器效果目录导航13.10搭建静态文件型的Web网站服务器Contents静态WEB服务器

前端:HTML+CSS+JavaScript

后端:Go语言

动态变化由前端的JavaScript负责实现http.HandleFunc("/w/",

serveStaticDir)

err

:=

http.ListenAndServe(":8080",

nil)if

err

!=

nil

{

t.Printfln("打开HTTP监听端口时发生错误:%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请求处理函数对于目录做特殊处理:寻找是否有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格式的数据返回,并不直接返回可显示的网页等

客户端一般使用AJAX请求来访问WEBAPI

服务端要能够处理客户端传递的参数,一般会以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通过?+&传递参数或者组合路径控制处理逻辑目录导航13.14动态网页的生成Contents动态网页技术“动态网页”技术,指的是Web服务器接收到请求后动态生成网页内容,填写网页中的HTML代码,而不是直接将文件系统中存在的静态网页文件直接推送给用户动态网页技术典型的代表有ASP、ASP.NET、JSP、PHP等

动态网页安全性较好,并具有良好的可拓展性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监听端口时发生错误:%v",

errT.Error())}准备SSL证书后启动HTTPS端口服务HTTPS的默认端口是443目录导航13.16第三方的WEB开发包ContentsWEB服务有关的优秀第三方包

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. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论