How to define UDP connection sessions more correctly?

Listening to messages from the udp socket, I would like to somehow determine where packets come from and scatter in sessions to get a more detailed report on the received data, I just did it forehead, looking for the current session and recording in its channel, I would like to know if more elegant methods?
full code function

     for {
        buff := bufPool.Get().([]byte)
        size, addr, err := pc.ReadFromUDP(buff[0:])
        if err != nil {
            done <- err
            return
        }
        switch s, ok := getSession(addr); ok {
        case true:
            s.buffer <- buff[0:size]
            bufPool.Put(buff)
            s.expiration = time.Now().Add(time.Duration(time.Second * 10)).UnixNano()
            atomic.AddInt64(&s.countMessage, 1)
            atomic.AddInt64(&s.len, int64(size))
        case false:
            s := &session{
                id:         rand.Int(),
                conn:       addr,
                expiration: time.Now().UnixNano(),
                buffer:     make(chan []byte, 64),
                run: func(wg *sync.WaitGroup, in chan []byte, ip string) {
                    for b := range in {
                        var m Message
                        err := json.Unmarshal(b, &m)
                        if err != nil {
                            log.Fatal(err)
                            continue
                        }
                        m.Device_ip = ip
                        out <- m
                    }
                },
            }
            wg.Add(1)
            s.buffer <- buff[0:size]
            bufPool.Put(buff)
            atomic.AddInt64(&s.countMessage, 1)
            atomic.AddInt64(&s.len, int64(size))
            go s.run(&wg, s.buffer, s.conn.IP.String())

Hi, Дмитрий,

If you copy the data out of the net.UDPAddr into a “flat” struct (I mean one that doesn’t have slices or pointers in it), you can use it as a map key:

type key struct {
  bits  uint32
  addr  [16]byte
  zone  string
}

func makeKeyFromUDPAddr(u *net.UDPAddr) (k key) {
  k.bits = int32(u.Port | ((copy(k.addr[:], u.IP) & 0x10) << 12))
  k.zone = u.Zone
}

func (k key) port() int {
  return k.bits & 0xffff
}

func (k key) addrLen() int {
  // бит 16 означает IPv6
  shifter := (k.bits & 0x10000) >> 15
  return 4 << shifter
}

func (k key) IP() net.IP {
  return net.IP(k.addr[:k.addrLen()])
}

var sessions = make(map[key]*session)
1 Like

Thanks for the answer, can I get a resource or comment on the bitwise operation in your answer?

Дмитрий, The solution may be more complicated than it has to be. I was trying to pack bits into specific integer sizes to make the solution more cache-efficient, but after re-reading it now, I don’t think you’ll gain anything significant. I instead recommend:

type key struct {
    zone string
    addr [16]byte
    port int16
    ipv6 bool
}

func makeKeyFromUDPAddr(u *net.UDPAddr) key {
    k := key{
        zone: u.Zone,
        port: int16(u.Port),
        ipv6: len(u.IP) == 16,
    }
    copy(k.addr[:], u.IP)
    return k
}

func (k key) IP() net.IP {
    if k.ipv6 {
        return net.IP(k.addr[:16])
    }
    return net.IP(k.addr[:4])
}

var sessions = make(map[key]*session)

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.