Go语言编程第五章网络编程

参考书:Go语言编程

第五章  网络编程

 

1 以前其他的Socket编程步骤

  • 建立Socket:使用socket( )函数
  • 绑定Socket:使用bind( )函数
  • 监听使用listen( )函数,或者连接使用connect( )函数
  • 接受连接:使用accept( )函数
  • 接收使用receive( )函数,或者发送使用send( )函数

2 无论使用什么协议建立什么形式的连接,都只需要调用net.Dial( )函数,函数原型如下

            func  Dial( net , addr  string ) ( Conn , error )

net参数是网络协议的名字,addr参数是IP地址或域名,而端口号以“:”的形式跟随在地址或域名的后面

 

  • TCP链接:conn , err := net.Dial("tcp" , "192.168.0.10:2100")
  • UDP链接:conn , err := net.Dial("udp" , "192.168.0.12:975")
  • ICMP链接(使用协议名称):conn , err := net.Dial("ip4:icmp" , "www.baidu.com")
  • ICMP链接(使用协议编号):conn , err := net.Dial("ip4:1" , "10.0.0.3")

3 Dial( )函数支持如下几种网络协议:tcp,tcp4(仅限IPv4),tcp6(仅限IPv6),udp,udp4(仅限IPv4),udp6(仅限IPv6),ip,ip4(仅限IPv4),ip6(仅限IPv6)。

4 其实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) (*IPConn , error)
  • func DialUnix(net string , laddr , raddr *UnixAddr) (c *UnixConn , err error)

5 例子

tcpAddr,err := net.ResolveTCPAddr("tcp4",service)   // 解析地址和端口号
conn2,err := net.DialTCP("tcp",nil,tcpAddr)         // 建立链接

6 net还包含了一系列的工具函数,如下

  • 验证IP地址有效性: func net.ParseIP( )
  • 创建子网掩码:func IPv4Mask(a , b , c , d byte) IPMask
  • 获取默认子网掩码: func (ip IP) DefaultMask( ) IPMask
  • 根据域名查找IP:

           func   ResolveIPAddr(net , addr string)  (*IPAddr , error)

           func   LookupHost(name string)  (cname string , addrs  []string , err error)

7 Go语言提供了net/http包,涵盖了HTTP客户端和服务端的具体实现。如下几个基本方法

  • func (c *Client) Get(url string) (r *Response , err error)
  • func (c *Client) Post(url string , bodyType string , body io.Reader) (r *Response , err error)
  • func (c *Client) PostForm(url string , data url.Values) (r *Response , err error)
  • func (c *Client) Head(url string) (r *Response , err error)
  • func (c *Client) Do(req *Request) (resp *Response , err error)

8 要请求一个资源,只需要调用http.Get( ),如下

            resp , err :=  http.Get("http://example.com/")

            if err != nil {

                    // 处理异常

                    return

            }

            defer resp.Body.close( )

9 要以POST的方式发送数据,只需调用http.Post( )并依次传递三个参数即可(请求的目标URL将要POST数据的资源类型MIMEType以[]byte形式的数据比特流)

            resp , err :=  http.Post("http://example.com/upload" , "image/jpeg" , &imageDataBuf)

10 HTTP中的Head请求方式表明只请求目标URL的头部信息,即HTTP Header而不返回HTTP Body。用http.Head( )方法即可,只需要传入目标URL即可

            resp , err :=  http.Head("http://example.com/")

11 如果我们发起的HTTP请求需要更多的定制信息,如设定一些自定义的Http Header字段,如

  • 设定自定义的“User-Agent”,而不是默认的“Go http package”
  • 传递Cookie

此时可以使用net/http包的http.Client对象的Do( )方法来实现

            req , err :=  http.NewRequest("GET" , "http://example.com" , nil)

            req.Header.Add("User-Agent" , "Gobook Gustom User-Agent")

            client := &http.Client{  // . . . }

            resp , err := client.Do(req)

12 在Go语言标准库中,http.Client类型有3个公开数据成员:

            Transport   RoundTripper

            CheckRedirect  func(req *Request , via []*Request)   error   // 指定处理重定向的策略,如果HTTP请求响应为30x,HTTP Client会在遵循跳转规则前先调用这个CheckRedirect函数

            Jar  CookieJar

13 http.Transport类型,如下

            type Transport struct {

                    Proxy  func( *Request )  (*url.URL , error)      // 指定代理方法

                    Dial  func(net , addr string)  (c net.Conn , err error)    // 创建TCP连接

                    TLSClientConfig  *tls.Config    // SSL连接专用,指定tls.Client所用的TLS配置信息

                    DisableKeepAlives  bool     // 是否取消长连接,默认为false

                    DisableCompression  bool   // 是否取消压缩,默认是false

                    MaxIdleConnsPerHost  int   //指定与每个请求目标主机间的最大非活跃连接数量

            }

14 http.Transport的其他公开成员函数

  • func (t *Transport) CloseIdleConnections( )  关闭所有非活跃的连接
  • func (t *Transport) RegisterProtocol(scheme string , rt RoundTripper)  注册并启用一个新的传输协议,比如WebSocket的传输协议标准(ws) ,或FTP,File协议等
  • func (t *Transport) RoundTrip(req *Request) (resp *Response , err error)  实现http.RoundTripper接口

15 处理HTTP请求:使用net/http包提供的http.ListenAndServe( )方法,可以在指定的地址进行监听,开启一个HTTP,如下           func  ListenAndServe(addr string , handler Handler)  error

该方法用于指定的TCP网络地址addr进行监听,然后调用服务端处理程序来处理传入的连接请求。该方法有两个参数,第一个是addr即监听地址;第二个是服务端处理程序,通常为空,表示服务端调用http.DefaultServeMux进行处理。具体代码如下

         http.Handle("/foo" , fooHandler)

         http.HandleFunc("/bar" ,  func( w http.ResponseWriter , r *http.Request) {

                // toDo

         })

        log.Fatal( s.ListenAndServe(":8080" , nil) )

16 可以自定义http.Server,代码如下

        s :=  &http.Server {

                Addr : ":8080",

                Handler: myHandler,

                ReadTimeout:  10*time.Second,

                WriteTimeout:  10*time.Second,

                MaxHeaderBytes:  1 << 20,

        }

17 处理HTTPS请求,net/http包还提供http.ListenAndServeTLS( ),用于处理HTTPS连接请求:

        func ListenAndServeTLS(addr string , certFile string , keyFile string , handler Handler)  error

ListenAndServeTLS( )和ListenAndServe( )的行为一致,区别在于只处理HTTPS请求。此外服务器上必须存在包含证书和与之匹配的私钥的相关文件,比如certFile对应SSL证书文件存放路径,keyFile对应证书私钥文件路径。

        

         http.Handle("/foo" , fooHandler)

         http.HandleFunc("/bar" ,  func( w http.ResponseWriter , r *http.Request) {

                // toDo

         })

        log.Fatal( s.ListenAndServe(":8080" , "cert.pem" , "key.pem" , nil) )

18  在Go语言中,net/rpc包实现了RPC协议

19 使用json.Marshal( )函数可以对一组数据进行JSON格式的编码。函数原型如下

            func  Marshal( v interface{ } )  ([]byte , error)

20 使用json.Unmarshal( )函数将JSON格式的文本解码为Go里边预期的数据结构,函数原型如下

            func Unmarshal( data []byte , v interface{ } )   error

补充:json.Unmarshal( )函数会根据一个约定的顺序查找目标结构中的字段,如一个JSON对象有个名为"Foo"的索引,会按如下顺序查找匹配

  • 一个包含Foo标签,即 ` json: "Foo" ` 的字段,如 Name string ` json: "Foo" `;
  • 一个名为Foo的字段
  • 一个除了首字母其他字母不区分大小写名为Foo的字段

这些字段在类型声明中必须都是以大写字母开头,可被导出的字段。

type Book struct {
	Name string `json:"title"`
}
func main(){
	b := []byte(`{"Title":"Go语言编程"}`)
	var gobook Book
	err := json.Unmarshal(b,&gobook)
	if err == nil {
		fmt.Println(gobook.Name)   // Go语言编程
	}
}

21 Go语言允许使用map[string]interface{ }和[]interface{ }类型的值来分别存放未知结构的JSON对象或数组,代码如下  

b := []byte(`{
	"Title":"Go语言编程12",
	"Authors":["Tom","Jim","Kily"],
	"Publisher":"baidu.com",
	"IsPublished": true,
	"Price":9.99,
	"Sales":1000}`)
var r interface{}
json.Unmarshal(b,&r)
fmt.Printf("r: %v\n",r)
gobook,_ := r.(map[string]interface{})
fmt.Printf("gobook: %v\n",gobook)

// 输出
r: map[Authors:[Tom Jim Kily] IsPublished:true Price:9.99 Publisher:baidu.com Sales:1000 Title:Go语言编程12]
gobook: map[Authors:[Tom Jim Kily] IsPublished:true Price:9.99 Publisher:baidu.com Sales:1000 Title:Go语言编程12]

22 例子

import (
   "io"
   "log"
   "net/http"
)

func helloHandler(w http.ResponseWriter,r *http.Request){
   io.WriteString(w,"Hello , world!")
}

func main(){
   http.HandleFunc("/hello",helloHandler)
   err := http.ListenAndServe(":8080",nil)
   if err != nil {
      log.Fatal("ListenAndServe: ",err.Error())
   }
}

23 页面跳转

http.Redirect(w,r,"/view?id="+filename,http.StatusFound)

24 渲染页面,可以使用io.WriteString( )函数,也可以采用html/template包的ParseFiles( )函数

  • 使用io.WriteString( )函数

func uploadHandler(w http.ResponseWriter,r *http.Request){
   if r.Method == "GET" {
      io.WriteString(w,"<html><form method=\"POST\" action=\"upload\" "+
                       " enctype=\"multipart/form-data\">"+
                       "Choose an image to upload: <input name=\"image\" type=\"file\" />"+
                       "<input type=\"submit\" value=\"Upload\" /></form></html>")
       return
   }
}

  • 使用ParseFiles( )函数
t,err := template.ParseFiles("./src/upload.html")
if err != nil {
   http.Error(w,err.Error(),http.StatusInternalServerError)
   return
}
t.Execute(w,nil)

25 template.Must( )可以确保如果模板不能解析成功时一定会触发错误处理流程

t := template.Must(template.ParseFiles("./src/upload.html"))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值