• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

Go 网络编程笔记

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

前言: 本文是学习<<go语言程序设计>> -- 清华大学出版社(王鹏 编著) 的2014年1月第一版 做的一些笔记 , 如有侵权, 请告知笔者, 将在24小时内删除, 转载请注明出处!

1. 标准库中提供net包, 支持基于网络层(IP),传输层(TCP/UDP) 以及应用层(如HTTP,FTP,SMTP) 的网络通信. 

2. IP 地址和域名解析

  - IP地址类型:  type IP[] byte 

    - 常用函数

      -  func ParseIP(s string) IP  验证IP的合法性, 返回IP地址对象或 nil.

      -  func (ip IP) String() string  将IPv4转换成点分十进制格式的字符串, IPv6转换成冒号分隔的简写字符串.

package main

import (
    "fmt"
    "net"
)

func main() {
    addr := "192.168.0.1"
    ip := net.ParseIP(addr)
    if ip == nil {
        fmt.Println("IP Invalid!")
    } else {
        fmt.Println("IP is: ", ip.String())
    }
}
View Code

  - IPMask地址类型:  type IPMask [] byte (只有IPv4才有默认的子网掩码)

    - 常用函数

      -  func IPv4Mask(a,b,c,d byte) IPMask  通过32位的IPv4地址生成子网掩码地址并返回.

      -  func (ip IP) DefaultMask() IPMask  返回IPv4的默认子网掩码,  否则返回 nil

      -  func (m IPMask) Size() (ones,bits int)  通过子网掩码对象返回掩码位数(ones) 和掩码总长度(bits). 如果是非标准的子网掩码, 将返回0,0.

      -  func (ip IP) Mask(mask IPMask) IP  返回IP地址与子网掩码相与的结果, 即网络地址. 

package main

import (
    "fmt"
    "net"
)

func main() {
    ip := net.ParseIP("192.168.0.1")
    if ip == nil {
        fmt.Println("Invalid IP!")
    }
    mask := ip.DefaultMask()
    fmt.Println("Subnet mask is:", mask)
    network := ip.Mask(mask)
    fmt.Println("Network address is:", network)
    ones, bits := mask.Size()
    fmt.Println("Mask ones:", ones, " Total Mask Len is:", bits)
}
View Code

  - IPAddr 结构体类型

    - 定义:  type IPAddr struct { IP IP} , 许多函数和方法都会返回一个指向这个结构体的指针.

    - IPAddr主要作用是用于域名解析服务(DNS)

    - 常用函数

      -  func ResolveIPAddr(net, addr string)(*IPAddr,error)   net 表示网络类型(ip,ip4,ip6), addr为IP地址或者域名.

    - 域名解析

package main

import (
    "fmt"
    "net"
    "os"
)

func main() {
    addr := "www.baidu.com"
    ip, err := net.ResolveIPAddr("ip", addr)
    if err != nil {
        fmt.Println("Resolvation error:#", err.Error())
        os.Exit(1)
    }
    fmt.Println("Resolved address is:", ip.String())
}
View Code

3. 主机信息查询

  - 大多数网络中的主机都有多个IP地址, 所以用主机名来获取一个主机的IP地址有事不好用. 一台主机也可能有别名.

  - 常用函数

    -  func LookupHost(host string) (addrs []string, err error)  返回主机地址列表或错误.

package main

import (
    "fmt"
    "net"
)

func main() {
    name := "www.baidu.com"
    addrs, err := net.LookupHost(name)
    if err != nil {
        fmt.Println("LookupHost Error:#", err.Error())
    } else {
        for _, s := range addrs {
            fmt.Println(s)
        }
    }
}
View Code

    -  func LookupCNAME(name string) (cname string, err error)  查询主机正式名.

4. 服务信息查询

  - 查询 SRV记录

  - 服务端口查询

 

5. Go 网络编程

  - 传统的Socket编程

    -流式套接字步骤:

      - 服务器和客户端分别调用socket()创建套接字

      - 服务器和客户端分别调用bind()函数绑定服务器地址

      - 服务器调用liste()监听, 客户机调用connect()进行连接并向服务器发出连接请求.

      - 服务器调用accept()接受请求并重新创建一个套接字用于和客户机之间通信连接.

      - 调用send() 和recv() 收发数据.

      - 任何一方可调用close()关闭

    - 数据报套接字不需监听和连接步骤, 服务器和客户机只要建立好套接字后就可以相互收发数据.

  - Go中的网络编程.

    - 对传统的Socket编程进行了封装. 无论想用什么形式的连接, 都用  func Dial(net,addr string) (Conn,error)  net是协议名(如tcp,ip), addr为IP地址或域名, 后加 :端口号. 如:  conn, err := net.Dial("tcp","192.168.0.1:5000")  conn, err := net.Dial("ip4:icmp","www.baidu.com") 

    - Dail()支持以下几种协议: tcp,tcp4,tcp6, udp,udp4,udp6,ip,ip4,ip6

    - 成功建立连接之后就可以进行数据收发了.

 

6.TCP

  - TCP工作在传输层, 面向连接, TCP程序设计属于C/S模式.

type TCPAddr struct{
    IP IP
    Port int
}

  -  func ResolveTCPAddr(net,addr string)(*TCPAddr,error)  将网络地址转换成TCPAddr地址结构.   www.google.com:80 

    - net : 网络协议名, 可以是 tcp,tcp4,tcp6

    - addr: IP地址或者域名, 如果是IPv6 必须用 " [ ] " 括起来, 端口号以 ":port" 的形式放在后面

  - 常用方法: 

    -  func (a * TCPAddr) Network() string  返回TCPAddr地址对象的网络协议名, 如"tcp"

    -  func (a * TCPAddr) String() string  将TCPAddr转换成字符串形式.

package main

import (
    "fmt"
    "net"
)

func main() {
    networkType := "tcp4"
    addr := "www.baidu.com:80"
    tcpAddr, err := net.ResolveTCPAddr(networkType, addr)
    if err != nil {
        fmt.Println("ResolveTCPAddr error:", err.Error())
    } else {
        fmt.Println("The Network Type is: ", tcpAddr.Network(), "IP is: ", tcpAddr.String())
    }
}
View Code

  - TCPConn 对象

    - TCP编程中客户机和服务器之间的通信是通过TCPConn对象实现连接的.

    - TCPConn是Conn接口的实现, 绑定了服务器的网络协议和地址信息.

type TCPConn struct{
    // 定义为空结构
}

    - 通过TCPConn连接对象, 可以实现客户机和服务器之间的全双工通信. 可以通过TCPConn的Read()/Write() 收发数据, 这两个方法都会引起阻塞.

      -  func (c * TCPConn) Read(b []byte) (n int, err error) 

      -  func (c * TCPConn) Write(b []byte) (n int, err error) 

  - TCP Server

    - TCP Server先注册一个共有端口号, 然后调用ListenTCP() 在这个端口上创建一个TCPListener监听对象, 并监听连接请求.

    - 启用TCPListener对象的Accept()接收请求, 返回一个协议相关的Conn对象(这里对应的就是TCPConn对象)

    - 如果返回一个新的TCPConn对象 , 服务器就可以像调用该对象的Read()/Write() 方法进行收发数据.

type TCPListener struct{
    // contains filtered or unexported fields.
}
func ListenTCP(net string, laddr * TCPAddr)(*TCPListener, error)
  - net : tcp / tcp4 / tcp6
  - laddr: local server address

    -  func (l * TCPListener) Accept()(c Conn,err error)  返回TCPConn(实现了Conn接口)对象.

    - 通信过程中如果想获取通信地址

      -  func (c * TCPConn) LocalAddr/RemoteAddr() Addr 

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() {
    tcpAddr, err := net.ResolveTCPAddr("tcp", ":5000")
    checkError(err)
    tcpListener, err := net.ListenTCP("tcp", tcpAddr)
    checkError(err)
    for {
        tcpConn, err := tcpListener.Accept()
        if err != nil {
            continue
        }
        handleClient(tcpConn)
        tcpConn.Close()
    }
}

func handleClient(conn net.Conn) {
    var buf [512]byte
    for {
        n, err := conn.Read(buf[0:])
        if err != nil {
            return
        }
        rAddr := conn.RemoteAddr()
        fmt.Println("Receive from client:", rAddr.String(), "#", string(buf[0:n]))
        _, err = conn.Write([]byte("Welcome client!"))
        if err != nil {
            return
        }
    }
}
View Code

    - 并发的Server

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() {
    tcpAddr, err := net.ResolveTCPAddr("tcp", ":5000")
    checkError(err)
    tcpListener, err := net.ListenTCP("tcp", tcpAddr)
    checkError(err)
    for {
        tcpConn, err := tcpListener.Accept()
        if err != nil {
            continue
        }
        go handleClient(tcpConn)
    }
}

func handleClient(conn net.Conn) {
    defer conn.Close()
    var buf [512]byte
    for {
        n, err := conn.Read(buf[0:])
        if err != nil {
            return
        }
        rAddr := conn.RemoteAddr()
        fmt.Println("Receive from client:", rAddr.String(), "#", string(buf[0:n]))
        _, err = conn.Write([]byte("Welcome client!"))
        if err != nil {
            return
        }
    }
}
View Code

  - TCP Client

    - 工作流程

      - 获取服务器地址和端口号之后, 调用DialTCP()函数向服务器发出连接请求, 如果请求成功会返回TCPConn对象

      - 调用 TCPConn 对象的 Read()和Write() 方法 , 进行收发消息.

    - 常用方法:

      -  func DialTCP(net string, laddr, raddr * TCPAddr)(* TCPConn, error)  net : tcp/tcp4/tcp6

      -  func (c * TCPConn) Close() error 

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() {
    var buf [512]byte
    tcpAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:5000")
    checkError(err)
    conn, err := net.DialTCP("tcp", nil, tcpAddr)
    checkError(err)
    rAddr := conn.RemoteAddr()
    n, err := conn.Write([]byte("Hello Server!"))
    checkError(err)
    n, err = conn.Read(buf[0:])
    checkError(err)
    fmt.Println("Reply from server: ", rAddr.String(), " #", string(buf[0:n]))
    conn.Close()
}
View Code

 

7. UDP

  - UDPAddr 地址结构体

type UDPAddr struct{
    IP IP
    Port int
}

  - 和TCP对应 , UDP有 ResolveUDPAddr(), Network() 和String(); 原型和功能都一样.

  - UDPConn对象

    - UDP中C/S通过UDPConn对象连接, UDPConn是Conn接口的实现, 绑定了服务器的网络协议和地址.

    -  type UDPConn struct {//empty } 

  - UDP 不保证通信的可靠性和有序性.

  - UDPConn对象提供了处理UDP数据的方法, 保证可靠

    -  func (c * UDPConn) ReadFromUDP(b []byte) (n int, addr * UDPAddr, err error) 

    -  func (c * UDPConn) WriteToUDP(b []byte, addr * UDPAddr )(int, error) 

  - UDP Server

    - 工作流程

      - Server先注册一个端口号, 然后调用ListenUDP()在这个端口上穿件一个UDPConn连接对象, 并在该对象和客户机上简历不可靠连接.

      - 如果服务器和某个客户机建立了UDPConn 连接, 就可以使用该对象的ReadFromUDP() 和WriteToUDP()方法.

      - 不管上一次通信是否完成或正常, UDP服务器都会依然接受下一次连接请求.

    - 常用方法.

      -  func ListenUDP(net string, laddr * UDPAddr)(* UDPAddr ,error) 

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() {
    udpAddr, err := net.ResolveUDPAddr("udp", ":5001") //使用本地地址
    checkError(err)
    conn, err := net.ListenUDP("udp", udpAddr)
    checkError(err)
    for {
        handleClient(conn)
    }
}

func handleClient(conn *net.UDPConn) {
    var buf [512]byte
    n, addr, err := conn.ReadFromUDP(buf[0:])
    if err != nil {
        return
    }
    fmt.Println("Receive from client:", addr.String(), " #", string(buf[0:n]))
    conn.WriteToUDP([]byte("Welcome Client!"), addr)
}
View Code

  - UDP Client

    - 工作流程

      - 获取服务器的地址和端口号之后 , 可以调用DialUDP() 向服务器发出连接请求, 成功后返回UDPConn对象

      - 客户机可以调用UDPConn对象的 ReadFromUDP() 和 WriteToUDP() 方法, 与服务器进行数据传输

      - 通信结束后, Client调用Close()关闭连接.

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() {
    udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:5001")
    checkError(err)
    conn, err := net.DialUDP("udp", nil, udpAddr)
    checkError(err)
    _, err = conn.Write([]byte("Hello Server!"))
    checkError(err)
    var buf [512]byte
    n, addr, err := conn.ReadFromUDP(buf[0:])
    checkError(err)
    fmt.Println("Reply from server:", addr.String(), " #", string(buf[0:n]))
    conn.Close()
}
View Code

 

8. IP

  - IP 是不可靠无连接的协议, 可以用IP实现自己的网络服务协议. 

  -  type IPAddr struct{ IP IP } 

  - 有对应的 ResolveIPAddr() , Network(), String() 和 IPConn对象

  - IP Server

    - 工作流程

      - IP 工作在网络层, 不需要在一个指定的端口上和客户机通信.

      - IP服务器使用指定的协议簇和协议, 调用ListenIP() 创建一个IPConn连接对象

      - 使用 IPConn的ReadFromIP() 和 WriteToIP() 收发数据

      - 通信结束, 服务器调用Close()关闭IPConn

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() {
    name, err := os.Hostname()
    checkError(err)
    ipAddr, err := net.ResolveIPAddr("ip4", name)
    checkError(err)
    conn, err := net.ListenIP("ip4:ip", ipAddr)
    checkError(err)
    for {
        handleClient(conn)
    }
}

func handleClient(conn *net.IPConn) {
    var buf [512]byte
    n, addr, err := conn.ReadFromIP(buf[0:])
    if err != nil {
        return
    }
    fmt.Println("Receive from client:", addr.String(), " #", string(buf[0:n]))
    conn.WriteToIP([]byte("Welcome Client!"), addr)
}
View Code

  - IP Client

    - 工作流程

      - 获取服务器网址后调用DialIP() 发出连接请求 , 成功返回 IPConn对象

      - 如果成功连接, 使用IPConn的ReadFromIP() 和 WriteToIP() 收发数据

      - 通信结束, Client也可以调用Close() 关闭IPConn

    -  func DialIP(netProto string, laddr , raddr * IPAddr)(*IPConn,error)   netProto : "网络类型 + 协议名" (i.e. ip4:ip  or  ip4:4)

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() {
    lAddr, err := net.ResolveIPAddr("ip4", "127.0.0.1")
    checkError(err)
    name, err := os.Hostname()
    checkError(err)
    rAddr, err := net.ResolveIPAddr("ip4", name)
    checkError(err)
    conn, err := net.DialIP("ip4:ip", lAddr, rAddr)
    checkError(err)
    _, err = conn.WriteToIP([]byte("Hello Server!"), rAddr)
    checkError(err)
    var buf [512]byte
    n, addr, err := conn.ReadFromIP(buf[0:])
    checkError(err)
    fmt.Println("Reply from server:", addr.String(), " #", string(buf[0:n]))
    conn.Close()
}
View Code

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Go的网络编程发布时间:2022-07-10
下一篇:
Go语言系列之网络编程发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap