指定网卡的udp数据包发送
func main() {
macAddr := "xxxxxx"
err := wakeNew("以太网 2",macAddr)
fmt.Println("wakeNew err = ", err)
}
func wakeNew(nic,macAddr string) error {
// var dArr []byte
// 将 MAC 地址转换为 6 字节的数组
macBytes, err := hex.DecodeString(macAddr)
if err != nil {
fmt.Println("DecodeString err = ", err)
return err
}
// 构造 Magic Packet 数据包
var magicPacket bytes.Buffer
for i := 0; i < 6; i++ {
err := magicPacket.WriteByte(0xff)
if err != nil {
fmt.Println("WriteByte err = ", err)
}
}
for i := 0; i < 16; i++ {
_, err = magicPacket.Write(macBytes)
if err != nil {
fmt.Println("magicPacket Write err = ", err)
}
}
//指定了使用哪个网卡将数据包发送出去
sender := net.UDPAddr{}
if len(nic) != 0 {
ip, err := interfaceIPv4ByName(nic)
if err != nil {
fmt.Printf("网卡[%s]错误: %s", nic, err)
return err
}
sender.IP = ip
}
//确定目的地址,这里是广播
addr, err := net.ResolveUDPAddr("udp", "255.255.255.255:9")
if err != nil {
fmt.Println("ResolveUDPAddr err = ", err)
return err
}
// 发送 Magic Packet
conn, err := net.DialUDP("udp", &sender, addr)
if err != nil {
fmt.Println("DialUDP err = ", err)
return err
}
_, err = conn.Write(magicPacket.Bytes())
if err != nil {
fmt.Println("conn.Write err = ", err)
return err
}
return nil
}
多设备的多客户端的UDP通信管理
场景:一个设备有唯一识别码cmdId。该服务要管理接收,标识他们的数据,但是设备IP和端口会变。也就是一个设备会生成多个客户端信息。保证服务端对一个设备只有一个最新的客户端信息。
var UdpConnPool = UDPSNConnMap{}
type UDPSNConnMap struct {
mu sync.Mutex
conns map[string]*UDPConn
Adrr *net.UDPAddr
}
func init() {
UdpConnPool.Init()
}
type UDPConn struct {
conn *net.UDPConn
Adrr *net.UDPAddr
}
func (m *UDPSNConnMap) Init() {
m.conns = make(map[string]*UDPConn)
}
func SocketListen(address string) {
addr, err := net.ResolveUDPAddr("udp", address)
if err != nil {
global.DS_LOG.Error("ResolveUDPAddr==", err)
return
}
conn, err := net.ListenUDP("udp", addr)
if err != nil {
global.DS_LOG.Error("ListenUDP==", err)
return
}
go handleConnection(conn)
select {}
}
func handleConnection(conn *net.UDPConn) {
global.DS_LOG.Info("监听udp")
defer conn.Close()
for {
var data [1500]byte
n, rAddr, err := conn.ReadFromUDP(data[:])
// global.DS_LOG.Infof("clientIP:%#v---clientPort:%#v", rAddr.IP, rAddr.Port)
if err != nil {
global.DS_LOG.Error("UDP 数据读取错误:", err)
continue
}
global.DS_LOG.Infof("客户端:[%s:%d]数据接收【原文】:%#v", rAddr.IP, rAddr.Port, data[:n])
cmdId, content := parseMsg(data[:n])
UdpConnPool.addConnect(cmdId, conn, rAddr)
// 处理变长内容
processFrameContent(*content)
}
}
//添加设备的唯一识别码
func (m *UDPSNConnMap) addConnect(cmdId string, conn *net.UDPConn, addr *net.UDPAddr) bool {
m.mu.Lock()
defer m.mu.Unlock()
// 如果已经存在对应SN的连接,则直接返回
if c, ok := m.conns[cmdId]; ok {
if c.Adrr == addr {
return false
}
}
connItem := UDPConn{
conn: conn,
Adrr: addr,
}
// 将新连接加入映射
m.conns[cmdId] = &connItem
return true
}
func (m *UDPSNConnMap) CloseUDPConnByCmdId(cmdId string) {
m.mu.Lock()
defer m.mu.Unlock()
// 关闭并移除对应SN的连接
if connItem, ok := m.conns[cmdId]; ok {
connItem.conn.Close()
delete(m.conns, cmdId)
}
}
func (m *UDPSNConnMap) Send(cmdId string, resp []byte) error {
m.mu.Lock()
defer m.mu.Unlock()
if connItem, ok := m.conns[cmdId]; ok {
global.DS_LOG.Infof("udp响应cmdId:【%s】", cmdId)
_, err := connItem.conn.WriteToUDP([]byte(resp), connItem.Adrr)
if err != nil {
global.DS_LOG.Info("服务器回复响应错误:", err)
return err
}
// global.DS_LOG.Infof("Send:%#v", resp)
} else {
return errors.New("设备" + cmdId + "不在线")
}
return nil
}
func (m *UDPSNConnMap) getConne(cmdId string) *net.UDPConn {
m.mu.Lock()
defer m.mu.Unlock()
// 如果已经存在对应SN的连接,则直接返回
if conn, ok := m.conns[cmdId]; !ok {
return conn.conn
}
return nil
}