1. 程式人生 > 其它 >golang 的net包的網路程式設計 TCP | HTTP | RPC

golang 的net包的網路程式設計 TCP | HTTP | RPC

目錄
golang net包

1.TCP網路程式設計

server.go

package main

import (
	"fmt"
	"log"
	"net"
	"os"
	"time"
)

func main()  {
	// 建立socket監聽
	lis, err := net.Listen("tcp", "localhost:1024")
	log.Println("server up at " + lis.Addr().String())
	defer lis.Close()
	log.Println("Waiting for clients...")

	// 處理錯誤
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
	}

	// 處理客戶端連線
	for {
		conn, err := lis.Accept()
		if err != nil {
			continue
		}

		log.Printf("client addr: %s, tcp connect success", conn.RemoteAddr())
		go handle(conn)
	}
}

func handle(conn net.Conn)  {
	buffer := make([]byte, 2048)
	// 迴圈讀取客戶請求
	for {
		n, err := conn.Read(buffer)
		if err != nil {
			log.Printf("%s connection error: %s", conn.RemoteAddr(), err)
			return
		}
		log.Printf("From %s receive data string: %s\n", conn.RemoteAddr(), string(buffer[:n]))
		// 收到的返回資訊
		strTmp := fmt.Sprintf("server got msg \"%s\" at %s", string(buffer[:n]), time.Now().String())
		conn.Write([]byte(strTmp))
	}
}

client.go

package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"os"
)

func main()  {
	addr := "127.0.0.1:1024"
	conn, err := net.Dial("tcp", addr)
	defer conn.Close()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
		os.Exit(1)
	}

	log.Printf("connection server: %s success", addr)
	sendLoop(conn)
}

func send(conn net.Conn)  {
	words := "hello server!"
	conn.Write([]byte(words))
	log.Println("send over")

	// receive from server
	buffer := make([]byte, 2048)

	n, err := conn.Read(buffer)
	if err != nil {
		log.Printf("%s waiting server back msg error: %s", conn.RemoteAddr(), err)
		return
	}
	log.Printf("%s receive server back msg: %s", conn.RemoteAddr(), string(buffer[:n]))
}

func sendLoop(conn net.Conn)  {
	for {
		input, _ := bufio.NewReader(os.Stdin).ReadString('\n')
		_, err := conn.Write([]byte(input))
		if err != nil {
			log.Println(err)
		}
		log.Println("send over")

		// receive from server
		buffer := make([]byte, 2048)

		n, err := conn.Read(buffer)
		if err != nil {
			log.Printf("%s waiting server back msg error: %s", conn.RemoteAddr(), err)
			return
		}
		log.Printf("%s receive server back msg: %s", conn.RemoteAddr(), string(buffer[:n]))
	}

}

2.HTTP網路程式設計

2.1 HTTP

server.go

package main

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

func main()  {
	// register callback func
	http.HandleFunc("/index", indexHandle)
	log.Println("HTTP server up at", "http://localhost:8080")
	// bind ip and start recv req
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal("ListenAndServe:", err)
	}
}

func indexHandle(w http.ResponseWriter, r *http.Request)  {
	fmt.Println("method = ", r.Method) 	//請求方法
	fmt.Println("URL = ", r.URL)		// 瀏覽器傳送請求檔案路徑
	fmt.Println("header = ", r.Header)	// 請求頭
	fmt.Println("body = ", r.Body)		// 請求包體
	fmt.Println(r.RemoteAddr, "連線成功")  	//客戶端網路地址

	w.Write([]byte("Hello from http server"))
	//fmt.Fprint(w, "Hello from http server")
}

client.go

package main

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

func main()  {
	resp, err := http.Get("http://localhost:8080/index")
	if err != nil {
		log.Println("Get err:", err)
		return
	}
	defer resp.Body.Close()

	// parse resp data
	// 獲取伺服器端讀到的資料---header
	fmt.Println("Status = ", resp.Status)           // 狀態
	fmt.Println("StatusCode = ", resp.StatusCode)   // 狀態碼
	fmt.Println("Header = ", resp.Header)           // 響應頭部
	fmt.Println("Body = ", resp.Body)               // 響應包體
	// resp body
	content, err := ioutil.ReadAll(resp.Body)
	log.Println("response body:", string(content))
}

2.2 HTTPS

server.go

package main

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

func main()  {
	http.HandleFunc("/index", indexHandle)

	log.Println("HTTPS server up at https://localhost:8443")
	http.ListenAndServeTLS(":8443", "D:\\demo1\\src\\demo\\demo05\\https-server\\server\\server.crt",
		"D:\\demo1\\src\\demo\\demo05\\https-server\\server\\server.key", nil)
}

func indexHandle(w http.ResponseWriter, r *http.Request)  {
	log.Println(r.RemoteAddr, r.URL, r.Proto, r.Header, r.Body)
	fmt.Fprint(w, "Hi, This is an example of https service in golang!")
}

client.go

package main

import (
	"crypto/tls"
	"crypto/x509"
	"io/ioutil"
	"log"
	"net/http"
)

func main()  {
	// create cert pool, which stands for cert set
	pool := x509.NewCertPool()
	caCrtPath := "D:\\demo1\\src\\demo\\demo05\\https-server\\client\\ca.crt"
	// call ca.crt
	caCrt, err := ioutil.ReadFile(caCrtPath)
	if err != nil {
		log.Println("ReadFile err:", err)
		return
	}

	// parse cert
	pool.AppendCertsFromPEM(caCrt)
	tr := &http.Transport{
		// InsecureSkipVerify-如果設定為true, 則不會校驗證書以及證書中的主機名和伺服器主機名是否一致
		TLSClientConfig: &tls.Config{RootCAs: pool, InsecureSkipVerify: true},
	}

	client := &http.Client{Transport: tr}

	resp, err := client.Get("https://localhost:8443/index")
	if err != nil {
		log.Println("Get err:", err)
		return
	}
	defer resp.Body.Close()
	content, err := ioutil.ReadAll(resp.Body)
	log.Println(string(content))
}

3.RPC網路程式設計

3.1 基於TCP的RPC

server.go


client.go


3.2 基於HTTP的RPC

server.go

package main

import (
	"fmt"
	"log"
	"net/http"
	"net/rpc"
)

type Student struct {
	Name   string
	School string
}

type RpcServer struct {}

func (r *RpcServer) Introduce(student Student, words *string) error {
	log.Println("student:", student)
	*words = fmt.Sprintf("Hello everyone, my name is %s, and I am from %s", student.Name, student.School)
	return nil
}

func main()  {
	rpcServer := new(RpcServer)
	// register rpc service
	_ = rpc.Register(rpcServer)
	// service bind to http protocol
	rpc.HandleHTTP()
	log.Println("http rpc service start success addr:8080")
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal(err)
	}
}

client.go

package main

import (
	"log"
	"net/rpc"
)

func main()  {
	type Student struct {
		Name   string
		School string
	}
	// connect rpc server
	client, err := rpc.DialHTTP("tcp", "127.0.0.1:8080")
	if err != nil {
		panic(err)
	}
	defer client.Close()
	// send request
	var reply string
	err = client.Call("RpcServer.Introduce", &Student{Name: "random_w", School: "Secret"}, &reply)
	if err != nil {
		panic(nil)
	}
	log.Println(reply)
}

3.3 基於jsonRpc的RPC

server.go

package main

import (
	"fmt"
	"log"
	"net"
	"net/rpc"
	"net/rpc/jsonrpc"
)

type Student struct {
	Name   string
	School string
}

type RpcServer struct{}

func (r *RpcServer) Introduce(student Student, words *string) error {
	log.Println("student: ", student)
	*words = fmt.Sprintf("Hello everyone, my name is %s, and I am from %s", student.Name, student.School)
	return nil
}

func main()  {
	rpcServer := new(RpcServer)
	// register rpc service
	_ = rpc.Register(rpcServer)
	// json-rpc based on tcp protocol, not http
	tcpLis, err := net.Listen("tcp", "127.0.0.1:8080")
	if err != nil {
		panic(err)
	}

	log.Println("tcp json-rpc service start success addr:8080")
	for {
		// listen request from clients
		conn, err := tcpLis.Accept()
		if err != nil {
			continue
		}
		go jsonrpc.ServeConn(conn)
	}
}

client.go

package main

import (
	"log"
	"net/rpc/jsonrpc"
)

func main()  {
	type Student struct {
		Name string
		School string
	}

	client, err := jsonrpc.Dial("tcp", "127.0.0.1:8080")
	if err != nil {
		panic(err)
	}
	defer client.Close()
	var reply string
	err = client.Call("RpcServer.Introduce", &Student{
		Name: "random_w",
		School: "Secret",
	}, &reply)
	if err != nil {
		panic(err)
	}
	log.Println(reply)
}