GO语言和网络编程有关的包都在net包下,通过net包及其子包,可以实现各种协议编程、Socket编程、http编程、rpc编程等。
Go语言中 Dial() 函数用于创建网络连接,函数原型如下:
func Dial(network, address string) (Conn, error) {
var d Dialer
return d.Dial(network, address)
}
参数说明如下:
:
的形式跟在地址或域名的后面即可。如果连接成功,该函数返回连接对象,否则返回 error。实际上,Dial() 函数是对 DialTCP()、DialUDP()、DialIP()、DialUnix() 函数的封装:
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err error)
func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err error)
func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err error)
func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err error)
在成功建立连接后,我们就可以进行数据的发送和接收,发送数据时使用连接对象 conn 的 Write() 方法,接收数据时使用 Read() 方法。
net包下个Listen函数会监听一个地址,返回一个监听器对象。
func Listen(network, address string) (Listener, error) {
var lc ListenConfig
return lc.Listen(context.Background(), network, address)
}
通过net包下的Dial和Listen函数来实现一个Socket编程。
服务器端:
通过Listen函数监听端口,接收来自客户端的请求。
监听器的Accept()方法是阻塞的,接收不到消息就会一直等待。
使用for循坏持续监听,并发处理接收的请求。
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
listener, _ := net.Listen("tcp", ":8888")
fmt.Println("开始监听...")
for{
conn, err := listener.Accept()//接收客户端发来的请求
if err!=nil{
fmt.Fprintln(os.Stdout,"错误:",err)
}
go handler(conn)//并发处理
}
defer listener.Close()//关闭监听器
}
func handler(conn net.Conn) {
//处理器
defer conn.Close()
conn.Write([]byte("已经收到..."))//响应客户端的数据
reader := bufio.NewReader(conn)
s, _ := reader.ReadString('\n')
fmt.Fprintln(os.Stdout,s)//将客户端发送的数据输出
}
客户端:
package main
import (
"fmt"
"net"
)
func main() {
conn, _ := net.Dial("tcp", "127.0.0.1:8888")//建立Tcp连接
defer conn.Close()//关闭连接
conn.Write([]byte("hello world"))//发出数据
bytes := make([]byte, 100)
n, _ := conn.Read(bytes)//读取数据
fmt.Println(string(bytes[0:n]))
}
http包提供了HTTP客户端和服务端的实现。
Get、Head、Post和PostForm函数发出HTTP/ HTTPS请求。
测试:
使用Get方法向测试网站发送一个请求。
package main
import (
"io"
"net/http"
"os"
)
func main() {
//使用Get请求获得一个
resp, _ := http.Get("http://jsonplaceholder.typicode.com/users")
l:=resp.Body//响应体
io.Copy(os.Stdout, l)//将响应体数据输出
//Fprint系函数按照默认格式输出、在此不适用
request := resp.Request//获取请求
fmt.Println("Header ",request.Header)
fmt.Println("Body ",request.Body)
fmt.Println("Method ",request.Method)
defer l.Close()
}
http包中还提供了web服务。
使用非常简单,只需要两步就可以启动一个简单的服务器:
1、设置一个入口处理器
使用http.HandleFunc()或者http.Handle()函数设置入口。
2、监听端口并启动服务
http.ListenAndServe()用于监听并启动服务。
package main
import (
"fmt"
"net/http"
)
func main() {
//处理器设置,第一个为入口url,第二个为处理器函数名
http.HandleFunc("/hello",hand)
//监听地址,第二个参数为Handler,nil代表不使用Handler
http.ListenAndServe(":8888",nil)
}
//处理器函数,必须接受w http.ResponseWriter, r *http.Request作为参数
func hand(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w,"Hello Web
")//将数据发送给响应写入
}
此时运行服务,访问浏览器 localhost:8888/hello
,出现以下内容:
Hello Web
go标准库中自带了模板引擎。
所谓模板引擎就是某些文本可以重复使用,只有部分数据需要变更,能够将需要变更的部分数据用特定的语法代替,用于被实际数据注入的一种机制。
如下:{ {data}}中的data可以从外界注入,外界注入什么数据就会输出hello 什么。
<body>
<h1>hello {
{data}}h1>
body>
template包(html/template)实现了数据驱动的模板,用于生成可对抗代码注入的安全HTML输出。
go中的模本语法如下:
{
{
.}}
使用{
{
}}圈住数据,.代表注入的数据。
如果注入的是结构体或者map,通过字段名字和key表示.
{
{
.Name}}拿到注入结构体的Name字段,如果字段不可见,即字段名小写,此时无法拿到数据
{
{
.k1}}拿到植入map的key为k1的value
测试:
import (
"html/template"
"os"
)
const tpl ="hello world ,hello {
{.}}"//模板字段
func main() {
//给模板起个名字并解析tpl字段
parse, _ := template.New("tpl_1").Parse(tpl)
//开始解析,参数一是将解析后的数据输出、参数二是注入的数据
parse.Execute(os.Stdout,"杰米")
}
//此时控制台:
hello world ,hello 杰米
模板引擎也常用于web中,用于对html的解析。
package main
import (
"fmt"
"html/template"
"net/http"
)
func main() {
http.HandleFunc("/hello",hand)
http.ListenAndServe(":8888",nil)
}
func hand(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w,"Hello Web
")
//从文件中解析
files, err:= template.ParseFiles("you url/hello.html")
if err!=nil{
fmt.Println(err)
}
//写入响应中
files.Execute(w,"jim")
}