Go1.9组播发送消息小实例

//如果实现线上使用请使用标准库封装的 net.ListenMulticastUDP函数.
package main

import (
    "flag"
    "fmt"
    "net"
    "syscall"
)

var (
    ttl        int
    daemon     bool
    port       = 12389
    multiaddr  = [4]byte{224, 0, 1, 1}
    inaddr_any = [4]byte{0, 0, 0, 0}
)

func init() {
    multi := flag.String("m", "224.0.1.1", "-m 224.0.1.1 specify multicast address")
    flag.IntVar(&port, "p", 12389, "-p 12389 specify multi address listen port")
    flag.IntVar(&ttl, "t", 8, "-t 8 specify ttl value")
    flag.BoolVar(&daemon, "d", false, "-d is a recv client")
    flag.Parse()
    ip := net.ParseIP(*multi)
    if ip != nil {
        copy(multiaddr[:], ip[12:16])
        if CheckMultiCast(multiaddr) {
            return
        }
    }
    fmt.Println("Isvalid multi address")
    syscall.Exit(1)
}

func main() {
    socketMC, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0)
    if err != nil {
        fmt.Printf("Create socket fd error:%s\n", err.Error())
        return
    }
    defer syscall.Close(socketMC)
    if err = SetTTL(socketMC, ttl); err != nil {
        fmt.Printf("Set ttl error:%s\n", err.Error())
        return
    }

    if daemon {
        err = UDPMulticast(socketMC)
        if err == nil {
            RecvMsg(socketMC)
        } else {
            fmt.Printf("Join multicast error:%s\n", err.Error())
        }
    } else {
        SendMsg(socketMC)
    }
}

func SendMsg(socketMC int) {
    var (
        msg   = []byte("Hello world")
        raddr = &syscall.SockaddrInet4{Port: port, Addr: multiaddr}
    )

    if err := syscall.Sendto(socketMC, msg, 0, raddr); err != nil {
        fmt.Printf("Send msg error:%s\n", err.Error())
    }
}

func RecvMsg(socketMC int) {
    var buf = make([]byte, 256)
    for {
        n, p, e := syscall.Recvfrom(socketMC, buf, 0)
        if e != nil {
            break
        }
        fmt.Printf("Recv:%s\n", string(buf[:n]))
        raddr, ok := p.(syscall.SockaddrInet4)
        if ok {
            fmt.Printf("Remote addr:%d.%d.%d.%d:%d\n", raddr.Addr[0], raddr.Addr[1], raddr.Addr[2], raddr.Addr[3], raddr.Port)
        } else {
            fmt.Printf("Remote info:%v\n", p)
        }
    }
    ExitMultiCast(socketMC)
}

//加入组播域
func UDPMulticast(socketMC int) error {
    err := syscall.Bind(socketMC, &syscall.SockaddrInet4{Port: port, Addr: inaddr_any})
    if err == nil {
        var mreq = &syscall.IPMreq{Multiaddr: multiaddr, Interface: inaddr_any}
        err = syscall.SetsockoptIPMreq(socketMC, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq)
    }
    return err
}

//退出组播域
func ExitMultiCast(socketMC int) {
    var mreq = &syscall.IPMreq{Multiaddr: multiaddr, Interface: inaddr_any}
    syscall.SetsockoptIPMreq(socketMC, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq)
}

//设置路由的TTL值
func SetTTL(fd, ttl int) error {
    return syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, ttl)
}

//检查是否是有效的组播地址范围
func CheckMultiCast(addr [4]byte) bool {
    if addr[0] > 239 || addr[0] < 224 {
        return false
    }
    if addr[2] == 0 {
        return addr[3] <= 18
    }
    return true
}

猜你喜欢

转载自blog.csdn.net/fyxichen/article/details/77430086