go语言网络编程(Socket编程)

Posted 开源你我

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言网络编程(Socket编程)相关的知识,希望对你有一定的参考价值。

一.go语言网络概述


go语言中,网络编程它提供一个net,支持基于IP层、TCP和UDP层及更高层(如HTTP,FTP、SMITP)的网络操作,其中IP层称为RawSocket。



二.Socket编程


在C++或者java这样语言中,socket编程是下面的这么一种方式:

Server端:

    1.创建Socket,使用一个叫做Socket函数

    2.绑定Socket,使用的是bind函数。

    3.监听最大连接数,Listen函数

    4.接受连接,使用accept函数

    5.发送或者接收消息,recv和send类似函数,read和write类似功能的函数

Client端

     1.创建Socket,使用一个叫做Socket函数

     2.可以绑定IP或者端口,如果不绑定,会自动隐式绑定 

     3.连接服务器,用connect函数

     4.接收或者发送消息,recv和send类似函数,read和write类似功能的函数


在go语言中,不是像上面的方式去写Socket编程的代码,go语言的标准库对此过程进行了抽象和封装,无论我们期望使用什么协议建立什么样的连接,都只需要调用net.Dial()就可以。


2.1.Dial函数

函数原型:

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

参数说明:

    net:网络协议的名字

返回值:

    成功返回连接对象

    失败返回错误


TCP的连接示例:

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


UDP的连接示例

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


ICMP的连接示例

conn, err := net.Dial("ipv4:icmp", "127.0.0.1:8888")


目前,Dial函数支持一下几种网络协议:“tcp”, "tcp4", "tcp6";“udp”, "udp4", "udp6";"ip","ip4","ip6"


在成功建立连接后,我们就可以通过网络来收发数据了,使用Write和Read函数


icmp示例:

package main

import (

    "net"

    "os"

    "fmt"

)

func main(){

    conn, err := net.Dial("ip4:icmp",  "www.baidu.com")

    checkError(err)

    var msg [512]byte

    msg[0] = 8

    msg[1] = 0

    msg[2] = 0

    msg[3] = 0

    msg[4] = 0

    msg[5] = 13

    msg[6] = 0

    msg[7] = 37

    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 Matcher")

    }

    if msg[7] == 37 {

        fmt.Println("Sequece Matcher")

    }

    os.Exit(0)

}


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 checkError(err error){

    if err != nil {

        fmt.Println(os.Stderr, "Fatal error : s%", err.Error())

     os.Exit(0)

    }

}


TCP案例

package main


// icmp


import (

    "net"

    "os"

    "fmt"

    "bytes"

    "io"

)


func main(){

    conn, err := net.Dial("tcp",  "www.baidu.com:80")

    checkError(err)


    _, err = conn.Write([]byte("HEAD/HTTP/1.0\r\n\r\n"))

    checkError(err)


     ret, err := readFull(conn) 

    checkError(err)

   

    fmt.Println(string(ret))

    os.Exit(0)

}


func checkError(err error){

    if err != nil {

        fmt.Println(os.Stderr, "Fatal error : s%", err.Error())

     os.Exit(0)

    }

}


func readFull(conn net.Conn) ([]byte, error) {

    defer conn.Close()

    result := bytes.NewBuffer(nil)

    var buf [512]byte


    for {

        n, err := conn.Read(buf[0:])

        result.Write(buf[0:n])

        if err != nil {

            if err == io.EOF {

                break

            }

            return nil, err

        }

    }

    return result.Bytes(), nil

}


效果截图:


2.2.网络通信的其他控制原语

实际上,Dial函数是对DialTCP(),DialUDP(),DialIP()和DialUnix()的封装,当然,我们也可以直接使用这些函数。原型如下:


func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err error)

func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err error)

func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err error)

func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err error)


完整示例代码:


package main


// icmp


import (

    "net"

    "os"

    "fmt"

    "io/ioutil"

)


func main(){

    tcpAddr, err := net.ResolveTCPAddr("tcp4",  "www.zgxnjz.cn:80")

    conn, err := net.DialTCP("tcp", nil, tcpAddr)

    checkError(err)


    _, err = conn.Write([]byte("HEAD/HTTP/1.0\r\n\r\n"))

    checkError(err)


     ret, err := ioutil.ReadAll(conn) 

    checkError(err)

   

    fmt.Println(string(ret))

    os.Exit(0)

}


func checkError(err error){

    if err != nil {

        fmt.Println(os.Stderr, "Fatal error : s%", err.Error())

     os.Exit(0)

    }

}

结果截图:




以上是关于go语言网络编程(Socket编程)的主要内容,如果未能解决你的问题,请参考以下文章

Go 语言网络编程系列— Socket 编程入门:Dial 函数及其使用

Go语言之Socket网络编程

GO语言Socket编程详解

Go语言TCP/UDP Socket编程

Go语言TCP Socket编程

GO语言网络编程