Go语言的Socket编程

作者: 帅气的昵称都有人用了 | 来源:发表于2019-04-11 17:10 被阅读5次

    我们在日常开发当中,几乎所有网络编程都是Socket编程,因为大部分底层网络的编程都离不开Socket编程。


    什么是Socket

    其实Socket起源于UNIX,网络的Socket数据传输是一种特殊的I/OSocket也是一种文件描述符。
    同文件的基本操作一样,Socket也有一个类似的函数--Socket(),该函数返回的是一个整型的Socket描述符,之后再进行类似于连接建立、数据传输等操作就都可以通过这个Socket来实现了。
    我们知道,在计算机网络当中,存在着TCPUDP两种协议,因此Socket也相应的对应着两种类型:流式SocketSOCK_STREAM,和数据报式Socket(SOCK_DGRAM),其中流式Socket是一种面向连接的Socket,针对的是面向连接的TCP服务应用,数据报式Socket是一种无连接的Socket,针对的是面向无连接的UDP服务应用。
    那么在建立一个Socket连接时,除了我们知道它是应用了哪种协议后,还有两个内容是需要确定的,就是IP地址和端口

    Go语言所支持的IP类型

    Go语言针对网络编程定义了net包,里面有很多关于网络编程的类型,函数和方法。其中IP的定义如下:

    type IP []byte
    

    虽然在net包中有很多的函数用于操作IP,但我们在这里只介绍几个比较常用的。
    先来看第一个:ParseIP(s string),这个函数会把一个IPv4IPv6的地址转化为IP类型:

    package main
    
    import (
        "fmt"
        "net"
        "os"
    )
    
    func main() {
        if len(os.Args) != 2 {
            fmt.Fprintf(os.Stderr, "Useage: %s IP Address\n", os.Args[0])
            os.Exit(1)
        }
        ipAddress := os.Args[1]
        addr := net.ParseIP(ipAddress)
        if addr == nil {
            fmt.Println("Invalid IP Address!")
        } else {
            fmt.Println("The IP Address is: ", addr.String())
        }
        os.Exit(0)
    }
    

    只要我们在执行时给定一个标准的IP地址,就会给出相应的IP格式


    Dial()函数

    在Go语言中,通常使用Dial()函数来连接服务器,Listen()进行监听,Accept()接收连接。
    Go语言标准库对传统的Socket编程过程进行了抽象和封装,无论期望使用什么协议建立什么形式的连接,都只需要调用net.Dial()即可。
    Dial()函数的原型如下:

    func Dial(net, addr string) (Conn, error)
    

    net参数是网络协议的名字,addr参数是IP地址或者域名,而端口号以:的形式跟随在地址或域名的后面,端口号可选。
    几种常见协议的调用方式:
    TCP

    conn, err := net.Dial("tcp", "192.168.0.10:8888")
    

    UDP

    conn, err := net.Dial("udp", "192.168.0.10:8888")
    

    ICMP

    /** 使用协议名称 */
    conn, err := net.Dial("ip4:icmp", "www.baidu.com")
    /** 使用协议编号 */
    conn, err := net.Dial("ip4:1", "10.0.0.1")
    

    在连接建立成功之后,就可以进行数据的发送与接收了,其中发送使用的是Write()函数,接收使用的是Read()函数。

    package main
    
    import (
        "bytes"
        "fmt"
        "io"
        "net"
        "os"
    )
    
    func main() {
        if len(os.Args) != 2 {
            fmt.Println("Usage: ", os.Args[0], "hostname")
            os.Exit(1)
        }
        service := os.Args[1]
        conn, err := net.Dial("ip4:icmp", service)
        checkError(err)
        var msg [512]byte
        // ICMP报文
        msg[0] = 8  // echo
        msg[1] = 0  // code 0
        msg[2] = 0  // checksum
        msg[3] = 0  // checksum
        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("Get response...")
        if msg[5] == 13 {
            fmt.Println("Identifier match.")
        }
        if msg[7] == 37 {
            fmt.Println("Sequence match.")
        }
        os.Exit(0)
    }
    func checkError(err error) {
        if err != nil {
            fmt.Fprintf(os.Stderr, "Error: %s", err.Error())
            os.Exit(1)
        }
    }
    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)
        var answer uint16 = uint16(^sum)
        return answer
    }
    func readFully(conn net.Conn) ([]byte, error) {
        defer conn.Close()
        result := bytes.NewBuffer(nil)
        var buf [512]byte
        for {
            _, err := conn.Read(buf[0:])
            result.Write(buf[0:])
            if err != nil {
                if err == io.EOF {
                    break
                }
                return nil, err
            }
        }
        return result.Bytes(), nil
    }
    

    运行程序后,如果取得响应,就会返回相应的结果,如下:

    Get response...
    Identifier match.
    Sequence match.
    

    相关文章

      网友评论

        本文标题:Go语言的Socket编程

        本文链接:https://www.haomeiwen.com/subject/rbmgiqtx.html