Kiến thức

1. Architecture

《Network Programming With Go》不是很深入。

Eight fallacies of distributed computing

  • The network is reliable.
  • Latency is zero.
  • Bandwidth is infinite.
  • The network is secure.
  • Topology doesn’t change.
  • There is one administrator.
  • Transport cost is zero.
  • The network is homogeneous.

IP address type

type IP []byte type IPMask []byte type IPAddr {IP IP}

socket

// resolve IP package main import ( “fmt” “net” “os” ) func main() { name := “www.baidu.com” addr, err := net.ResolveIPAddr(“ip”, name) if err != nil { fmt.Println(“Resolution error”, err.Error()) os.Exit(1) } fmt.Println(“addr ip is “, addr.String()) } // host lookup package main import ( “fmt” “net” ) func main() { addrs, err := net.LookupHost(“www.baidu.com”) if err != nil { fmt.Println(err) } for _, s := range addrs { fmt.Println(s) } }

TCPAddr 包含 IP 和 Port:

type TCPAddr struct{ IP IP Port int }

使用 ResolveTCPAddr 创建一个 TCPAddr

func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error)

TCP Sockets:

func (c *TCPConn) Write(b []byte) (n int, err os.Error) func (c *TCPConn) Read(b []byte) (n int, err os.Error)

客户端用 DialTCP 建立一个连接:

func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error)

尝试使用 tcp 发送一个 http 请求示例:

package main import ( “fmt” “io/ioutil” “log” “net” ) func checkError(err error) { if err != nil { log.Fatal(err) } } func main() { // 使用 tcp 发送 http 请求示例 (只是为了测试几个函数,用 dial 最方便) // get addr addr, err := net.ResolveIPAddr(“ip”, “www.baidu.com”) fmt.Println(addr) checkError(err) // create tcpAddr tcpAddr, err := net.ResolveTCPAddr(“tcp4”, fmt.Sprintf(“%s:%d”, addr, 80)) checkError(err) // dialtcp conn, err := net.DialTCP(“tcp”, nil, tcpAddr) checkError(err) _, err = conn.Write([]byte(“HEAD / HTTP/1.0rnrn”)) checkError(err) res, err := ioutil.ReadAll(conn) // 读取直到 error 或者 EOF checkError(err) fmt.Println(string(res)) }

编写一个时间回显tcp服务器,tcp server 主要涉及两个函数:

func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) func (l *TCPListener) Accept() (c Conn, err os.Error) // DaytimeServer // telnet localhost 1200 package main import ( “fmt” “net” “os” “time” ) func main() { service := “:1200” tcpAddr, err := net.ResolveTCPAddr(“tcp4”, service) checkError(err) listener, err := net.ListenTCP(“tcp”, tcpAddr) checkError(err) for { conn, err := listener.Accept() if err != nil { continue } daytime := time.Now().String() conn.Write([]byte(daytime)) conn.Close() } } func checkErr(err error) { if err != nil { fmt.Fprintf(os.Stderr, “Fatal error: %s”, err.Error()) os.Exit(1) } }

Chuyên gia chia sẻ  Search code, repositories, users, issues, pull requests...

编写一个简单的tcp回显服务器:

// SimpleEchoServer package main import ( “fmt” “net” “os” ) func main() { service := “:1201” tcpAddr, err := net.ResolveTCPAddr(“tcp4”, service) checkError(err) listener, err := net.ListenTCP(“tcp”, tcpAddr) checkError(err) for { conn, err := listener.Accept() if err != nil { continue } handleClient(conn) conn.Close() // close the client } } func handleClient(conn net.Conn) { var buf [512]byte for { n, err := conn.Read(buf[0:]) if err != nil { return } fmt.Println(string(buf[0:])) _, err2 := conn.Write(buf[0:n]) if err2 != nil { return } } } func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, “Fatal error: %s”, err.Error()) os.Exit(1) } }

可以很容易修改成并发的,使用 goroutine

// SimpleEchoServer package main import ( “fmt” “net” “os” ) func main() { service := “:1201” tcpAddr, err := net.ResolveTCPAddr(“tcp4”, service) checkError(err) listener, err := net.ListenTCP(“tcp”, tcpAddr) checkError(err) for { conn, err := listener.Accept() if err != nil { continue } go handleClient(conn) // NOTE: use goroutine } } func handleClient(conn net.Conn) { defer conn.Close() // NOTE: close connection on exit var buf [512]byte for { n, err := conn.Read(buf[0:]) if err != nil { return } fmt.Println(string(buf[0:])) _, err2 := conn.Write(buf[0:n]) if err2 != nil { return } } } func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, “Fatal error: %s”, err.Error()) os.Exit(1) } }

Controlling TCP connections

// Timeout func (c *TCPConn) SetTimeout(nsec int64) os.Error // Staying alive, a client wish to stay connected to a server even if it has nothing to send func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error

UDP Datagrams

func ResolveUDPAddr(net, addr string) (*UDPAddr, os.Error) func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error) func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err os.Error) func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error)

UDP client server demo:

// UDPDaytimeClient package main import ( “fmt” “net” “os” ) func main() { service := “localhost:1200” udpAddr, err := net.ResolveUDPAddr(“udp4”, service) conn, err := net.DialUDP(“udp”, nil, udpAddr) checkError(err) _, err = conn.Write([]byte(“anything”)) checkError(err) var buf [512]byte n, err := conn.Read(buf[0:]) checkError(err) fmt.Println(string(buf[0:n])) } func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, “Fatal error: %s”, err.Error()) os.Exit(1) } } // udpserver.go package main import ( “fmt” “net” “os” “time” ) func main() { service := “:1200” updAddr, err := net.ResolveUDPAddr(“udp4”, service) checkError(err) conn, err := net.ListenUDP(“udp”, updAddr) checkError(err) for { handleClient(conn) } } func handleClient(conn *net.UDPConn) { var buf [512]byte _, addr, err := conn.ReadFromUDP(buf[0:]) if err != nil { return } daytime := time.Now().String() conn.WriteToUDP([]byte(daytime), addr) } func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, “Fatal error: %s”, err.Error()) os.Exit(1) } }

Chuyên gia chia sẻ  Hỏi đáp: Pulse trong máy đo huyết áp là gì?

The types Conn, PacketConn and Listener

func Dial(net, laddr, raddr string) (c Conn, err os.Error)

改写之前 tcp 发送 http 请求的例子

package main import ( “fmt” “io/ioutil” “log” “net” ) func checkError(err error) { if err != nil { log.Fatal(err) } } func main() { conn, err := net.Dial(“tcp”, “www.baidu.com:80”) checkError(err) _, err = conn.Write([]byte(“HEAD / HTTP/1.0rnrn”)) checkError(err) res, err := ioutil.ReadAll(conn) // 读取直到 error 或者 EOF checkError(err) fmt.Println(string(res)) }

同样的 listen 也可以简化

func Listen(net, laddr string) (l Listener, err os.Error) func (l Listener) Accept() (c Conn, err os.Error)

Raw sockets and the type IPConn

IP 协议基础上自定义。按照 ping 发送格式模仿写一个 ping

  • The first byte is 8, standing for the echo message
  • The second byte is zero
  • The third and fourth bytes are a checksum on the entire message
  • The fifth and sixth bytes are an arbitrary identifier
  • The seventh and eight bytes are an arbitrary sequence number
  • The rest of the packet is user data

// Ping,使用 root 运行 package main import ( “fmt” “net” “os” ) func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, “Fatal error: %s”, err.Error()) os.Exit(1) } } func main() { if len(os.Args) != 2 { fmt.Println(“Usage: “, os.Args[0], “host”) os.Exit(1) } addr, err := net.ResolveIPAddr(“ip”, os.Args[1]) if err != nil { fmt.Println(“Resolution error”, err.Error()) os.Exit(1) } fmt.Println(addr) conn, err := net.DialIP(“ip4:icmp”, addr, addr) checkError(err) var msg [512]byte msg[0] = 8 //echo msg[1] = 0 //code 0 msg[2] = 0 //checksum, fix later msg[3] = 0 //checksum, fix later msg[4] = 0 //identifier[0] msg[5] = 13 //identifier[1] msg[6] = 0 // sequence[0] msg[7] = 37 //sequence[1] len := 8 check := checkSum(msg[0:len]) msg[2] = byte(check >> 8) msg[3] = byte(check & 255) _, err = conn.Write(msg[0:len]) checkError(err) _, err = conn.Read(msg[0:]) checkError(err) fmt.Println(“Got response”) if msg[5] == 13 { fmt.Println(“identifier matches”) } if msg[7] == 37 { fmt.Println(“Sequence matches”) } } func checkSum(msg []byte) uint16 { sum := 0 for n := 1; n < len(msg)-1; n += 2 { sum += int(msg[n])*256 + int(msg[n+1]) } sum = (sum >> 16) + (sum & 0xffff) sum += (sum >> 16) answer := uint16(^sum) return answer }

  • ASN.1
  • JSON
  • gob
  • base64
  • version control
  • message format
  • data format: byte encoded or character encoded
  • state
Chuyên gia chia sẻ  Cẩm nang đầu tư F0

Go use utf8 encoded characters in its strings. Each character is of type rune(alias for int32) as a Unicode character can be 1,2 or 4 bytes in UTF8 encoding. A string is an array of rune.

Data integrity (数据完整性)

// MD5 Has package main import ( “crypto/md5” “fmt” ) func main() { hash := md5.New() bytes := []byte(“hellon”) hash.Write(bytes) hashValue := hash.Sum(nil) hashSize := hash.Size() // print out in ASCII from as four hexadcimal numbers for n := 0; n < hashSize; n += 4 { var val uint32 val = uint32(hashValue[n])<<24 + uint32(hashValue[n+1])<<16 + uint32(hashValue[n+2])<<8 + uint32(hashValue[n+3]) fmt.Printf(“%x “, val) } }

Symmetric key encryption

  • Blowfish
  • DES

Public key encryption

  • crypto/rsa

X.509 certificates

A public key infrastructure(PKI) is a framework for a collections of public keys, along with additional information such as owner name and location.

TLS

  • crypto/tls

package main import ( “fmt” “net/http” “os” ) func main() { url := “http://127.0.0.1:8000” response, err := http.Get(url) if err != nil { fmt.Println(err.Error()) os.Exit(2) } if response.Status != “200 OK” { fmt.Println(response.Status) os.Exit(2) } // b, _ := httputil.DumpResponse(response, false) // fmt.Print(string(b)) var buf [512]byte reader := response.Body for { n, err := reader.Read(buf[0:]) if err != nil { fmt.Println(err) os.Exit(0) } fmt.Print(string(buf[0:n])) } }

Proxy handling:

proxyURL, err := url.Parse(proxyString) // http://proxy-host:port transport := &http.Transport{Proxy: http.ProxyURL(proxyURL)} client := &http.Client{Transport: transport} // func ProxyFromEnvironment(req *Request) (*url.URL, error)

Servers

  • File server

package main import “net/http” func main() { fileServer := http.FileServer(http.Dir(“/home/httpd/html”)) err := http.ListenAndServe(“:8000”, fileServer) checkError(err) }

  • Handler function

func Handle(pattern string, handler Handler) func HandleFunc(pattern string, handler func(*Conn, *Request))

  • html/template, text/template
  • pipelines: {{. | html}}
  • template.FuncMap{“emailExpand”: EmailExpand}
  • variables in templates are prefixed by ‘$’
  • conditional

Đánh giá bài viết post

Phạm Văn Sỹ

Tôi là Phạm Văn Sỹ chuyên gia uy tín trong lĩnh vực kinh tế và kinh doanh là sinh viên của trường Đại học Ngoại Thương. Với kiến thức sâu rộng sau 12 năm ở bên ngoài thương trường thị trường tôi mong muốn chia sẻ các kiến thức chuyên sâu hữu ích dành cho mọi người.

Related Articles

Check Also
Close
Back to top button