• Go网络编程


    网络编程基本介绍

    Golang的主要目标之一就是面向大规模后端服务程序,网络通信整块是服务端 程序必不可少也是至关重要的一部分

    1. 网络编程有两种:

      • TCP socket编程,是网络编程的主流。之所以叫TCP socket编程,是因为底层是基于TCP/IP协议的。比如:QQ聊天
      • b/s结构的HTTP编程,我们使用浏览器去访问服务器时,使用的就是http协议,而http底层依旧是用tcp socket实现的。比如:京东商城
    2. 端口介绍

      • 一个IP地址的端口可以有65535(256 * 256,0 - 65535)
      • 0号是保留端口
      • 1 - 1024 是固定端口:又称有名端口,即被某些程序固定使用,一般程序员不使用
      • 1025 - 65535 是动态端口:程序员可以使用
      • 注意事项
        • 在计算机要尽可能的少开端口
        • 一个端口只能被一个程序监听
        • 如果使用 netstat -an 可以常看本机有哪些端口在监听
        • 如果使用 netstat -anb 来查看监听端口的pid,在结合任务管理器关闭不安全的端口
    3. 案例

    client.go

    import (
    	"bufio"
    	"fmt"
    	"net"
    	"os"
    )
    
    func main() {
    
    	conn, err := net.Dial("tcp", "127.0.0.1:8080")
    	if err != nil {
    		fmt.Println("connect server fail")
    		fmt.Println(err)
    		return
    	}
    
    	defer conn.Close()
    
    	fmt.Printf("connect success %v 
    ", conn)
    
    	reader := bufio.NewReader(os.Stdin)
    
    	for {
    		fmt.Println("input data: ")
    		line, err := reader.ReadString('
    ')
    		if err != nil {
    			fmt.Println("read data fail: ", err)
    			continue
    		}
    		if line == "-1" {
    			fmt.Println("exit client...")
    			break
    		}
    		n, err := conn.Write([]byte(line))
    		if err != nil {
    			fmt.Println("send data fail: ", err)
    			continue
    		}
    		fmt.Printf("send %d byte data
    ", n)
    	}
    }
    
    

    server.go

    import (
    	"fmt"
    	"net"
    )
    
    func handleConnection(conn net.Conn) {
    
    	defer conn.Close() // 函数退出的时候关闭连接
    
    	ip := conn.RemoteAddr().String()
    	for {
    		buf := make([]byte, 1024)
    		n, err := conn.Read(buf)
    		if err != nil {
    			fmt.Printf("clien %v logout
    ", ip)
    			break
    		}
    		fmt.Printf("%v say: %v", ip, string(buf[:n]))
    	}
    
    }
    
    func main() {
    
    	fmt.Println("start server...")
    
    	ln, err := net.Listen("tcp", "127.0.0.1:8080") // IPV4的写法, IPV6的写法:0.0.0.0:8888
    
    	if err != nil {
    		fmt.Printf("server start error: %v", err)
    		return
    	}
    
    	defer ln.Close() // 延时关闭
    
    	for {
    		conn, err := ln.Accept() // 接收一个客户端请求
    		if err != nil {
    			fmt.Println("connect fail ", err)
    			continue
    		}
    		fmt.Printf("accept client ip = %v 
    ", conn.RemoteAddr().String()) // client info
    		go handleConnection(conn)
    	}
    }
    

    Dial函数:

    在网络network上连接地址address,并返回一个Conn接口。可用的网络类型有:
    "tcp"、"tcp4"、"tcp6"、"udp"、"udp4"、"udp6"、"ip"、"ip4"、"ip6"、"unix"、"unixgram"、"unixpacket"对TCP和UDP网络,地址格式是host:port或[host]:port,参见函数JoinHostPort和SplitHostPort。

    HTTP 编程

    HTTP( HyperText Transfer Protocol,超文本传输协议)是互联网上应用最为广泛的一种网络
    协议,定义了客户端和服务端之间请求与响应的传输标准。
    Go语言标准库内建提供了net/http包,涵盖了HTTP客户端和服务端的具体实现。使用
    net/http包,我们可以很方便地编写HTTP客户端或服务端的程序。

    HTTP 客户端

    Go内置的net/http包提供了最简洁的HTTP客户端实现,我们无需借助第三方网络通信库(比如libcurl)就可以直接使用HTTP中用得最多的GET和POST方式请求数据。

    net/http包的Client类型提供了如下几个方法,让我们可以用最简洁的方式实现 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)
    

    HTTP 服务端

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

    该方法有两个参数:第一个参数 addr 即监听地址;第二个参数表示服务端处理程序,通常为空

    1. 处理HTTPS请求
      net/http 包还提供 http.ListenAndServeTLS() 方法,用于处理 HTTPS 连接请求:
    func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error
    

    ListenAndServeTLS() 和 ListenAndServe()的行为一致,区别在于只处理HTTPS请求。此外,服务器上必须存在包含证书和与之匹配的私钥的相关文件,比如certFile对应SSL证书文件存放路径, keyFile对应证书私钥文件路径。如果证书是由证书颁发机构签署的, certFile参数指定的路径必须是存放在服务器上的经由CA认证过的SSL证书。

    RPC 编程

    RPC( Remote Procedure Call,远程过程调用)是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络细节的应用程序通信协议。 RPC协议构建于TCP或UDP,或者是 HTTP之上,允许开发者直接调用另一台计算机上的程序,而开发者无需额外地为这个调用过程编写网络通信相关代码,使得开发包括网络分布式程序在内的应用程序更加容易。

    RPC 采用客户端—服务器( Client/Server)的工作模式。请求程序就是一个客户端( Client),而服务提供程序就是一个服务器( Server)。当执行一个远程过程调用时,客户端程序首先发送一个带有参数的调用信息到服务端,然后等待服务端响应。在服务端,服务进程保持睡眠状态直到客户端的调用信息到达为止。当一个调用信息到达时,服务端获得进程参数,计算出结果,并向客户端发送应答信息,然后等待下一个调用。最后,客户端接收来自服务端的应答信息,获得进程结果,然后调用执行并继续进行

    Go语言中的RPC支持与处理

    net/rpc包允许 RPC 客户端程序通过网络或是其他 I/O 连接调用一个远端对象的公开方法(必须是大写字母开头、可外部调用的)。在 RPC 服务端,可将一个对象注册为可访问的服务,之后该对象的公开方法就能够以远程的方式提供访问。一个 RPC 服务端可以注册多个不同类型的对象,但不允许注册同一类型的多个对象。

    一个对象中只有满足如下这些条件的方法,才能被 RPC 服务端设置为可供远程访问:

    • 必须是在对象外部可公开调用的方法(首字母大写);
    • 必须有两个参数,且参数的类型都必须是包外部可以访问的类型或者是Go内建支持的类型;
    • 第二个参数必须是一个指针;
    • 方法必须返回一个error类型的值。
      以上4个条件,可以简单地用如下一行代码表示:func (t *T) MethodName(argType T1, replyType *T2) error

    在上面这行代码中,类型T、 T1 和 T2 默认会使用 Go 内置的 encoding/gob 包进行编码解码
    该方法( MethodName)的第一个参数表示由 RPC 客户端传入的参数,第二个参数表示要返回给RPC客户端的结果,该方法最后返回一个 error 类型的值

    Go 的 net/rpc 包提供了便利的rpc.Dial()rpc.DialHTTP() 方法来与指定的 RPC 服务端建立连接。

    调用 RPC 客户端的 Call() 方法则进行同步处理,这时候客户端程序按顺序执行,只有接收完 RPC 服务端的处理结果之后才可以继续执行后面的程序。当调用 RPC 客户端的 Go() 方法时,则可以进行异步处理, RPC 客户端程序无需等待服务端的结果即可执行后面的程序,而当接收到 RPC 服务端的处理结果时,再对其进行相应的处理。

    例子

    // rpc_server.go
    package service
    
    import (
    	"errors"
    )
    
    type Args struct {
    	A, B int
    }
    
    type Quotient struct {
    	Quo, Rem int
    }
    
    type Arith int
    
    func (t *Arith) Multiply(args *Args, reply *int) error {
    	*reply = args.A * args.B
    	return nil
    }
    
    func (t *Arith) Divide(args *Args, quo *Quotient) error {
    	if args.B == 0 {
    		return errors.New("divide by zero")
    	}
    	quo.Quo = args.A / args.B
    	quo.Rem = args.A % args.B
    	return nil
    }
    
    // server.go
    package main
    
    import (
    	"log"
    	"net"
    	"net/http"
    	"net/rpc"
    	"rpcdemo/server/service"
    )
    
    func main() {
    	arith := new(service.Arith)
    	rpc.Register(arith)
    	rpc.HandleHTTP()
    	l, e := net.Listen("tcp", "127.0.0.1:8080")
    	if e != nil {
    		log.Fatal("listen error:", e)
    	}
    	
    	go http.Serve(l, nil)
    
    	for {
    
    	}
    }
    
    
    // client.go
    package main
    
    import (
    	"fmt"
    	"log"
    	"net/rpc"
    	"rpcdemo/server/service"
    )
    
    func main() {
    	serverAddress := "127.0.0.1"
    	client, err := rpc.DialHTTP("tcp", serverAddress+":8080")
    	if err != nil {
    		log.Fatal("dialing:", err)
    	}
    
    	args := &service.Args{7, 8}
    	var reply int
    	err = client.Call("Arith.Multiply", args, &reply)
    	if err != nil {
    		log.Fatal("arith error:", err)
    	}
    	fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)
    }
    
    
    

    Gob简介

    Gob 是 Go 的一个序列化数据结构的编码解码工具,在 Go 标准库中内置encoding/gob包以供使用。一个数据结构使用 Gob 进行序列化之后,能够用于网络传输。与 JSON 或 XML 这种基于文本描述的数据交换语言不同, Gob 是二进制编码的数据流,并且 Gob 流是可以自解释的,它在保证高效率的同时,也具备完整的表达能力。

    作为针对 Go 的数据结构进行编码和解码的专用序列化方法,这意味着 Gob 无法跨语言使用。在 Go 的net/rpc包中,传输数据所需要用到的编码解码器,默认就是 Gob。

    JSON 处理

    1. json.Marshal()函数:func Marshal(v interface{}) ([]byte, error)
    2. json.Unmarshal()函数: func Unmarshal(data []byte, v interface{}) error
  • 相关阅读:
    Spring事务管理
    Java GC算法
    内连接,左连接,右连接
    ThreadLocal相关
    @Autowired 与 @Resource的区别
    spring注解
    BZOJ 1040 ZJOI 2008 骑士 树形DP
    HDU 5575 Discover Water Tank 并查集 树形DP
    BZOJ 3571 画框 KM算法 最小乘积最大权匹配
    ZOJ 3256 Tour in the Castle 插头DP 矩阵乘法
  • 原文地址:https://www.cnblogs.com/lxlhelloworld/p/14286067.html
Copyright © 2020-2023  润新知