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
原文地址:https://www.cnblogs.com/lxlhelloworld/p/14286067.html