UDPClient.go

package ipc

import (
	"bytes"
	"encoding/gob"
	"log"
	"net"
	"time"
)

type UDPClient struct {
	UDPBase
	conn *net.UDPConn
	addr *net.UDPAddr
}

func NewUDPClient(addr string, port int) *UDPClient {
	client := &UDPClient{
		UDPBase: UDPBase{
			addr: addr,
			port: port,
			mtu:  32000,
			timeout: 100 * time.Millisecond,
		},
	}
	client.create(addr, port)
	return client
}

func (u *UDPClient) create(addr string, port int) {
	u.addr, _ = net.ResolveUDPAddr("udp", net.JoinHostPort(addr, string(port)))
	u.conn, _ = net.DialUDP("udp", nil, u.addr)
	u.conn.SetReadDeadline(time.Now().Add(u.timeout))
}

func (u *UDPClient) reconnect() {
	if u.conn != nil {
		log.Println("Reconnecting UDP client..")
		u.conn.Close()
		u.create(u.addr.IP.String(), u.addr.Port)
		time.Sleep(u.timeout)
	}
}

func (u *UDPClient) send(command string, data []byte, retry int, sleep time.Duration) ([]byte, error) {
	_, err := u.conn.Write(data)
	if err != nil {
		return nil, err
	}

	buffer := make([]byte, u.mtu)
	for i := 0; i < retry; i++ {
		u.conn.SetReadDeadline(time.Now().Add(u.timeout))
		n, _, err := u.conn.ReadFromUDP(buffer)
		if err == nil && buffer[0] == command[0] {
			return buffer[1:n], nil
		}
		time.Sleep(sleep)
	}
	return nil, err
}

func (u *UDPClient) Once(command string, data interface{}) (interface{}, error) {
	var buf bytes.Buffer
	enc := gob.NewEncoder(&buf)
	err := enc.Encode(data)
	if err != nil {
		return nil, err
	}

	serialized := append([]byte(command), buf.Bytes()...)
	result, err := u.send(command, serialized, 3, 100*time.Microsecond)
	if err != nil {
		return nil, err
	}

	var res interface{}
	dec := gob.NewDecoder(bytes.NewReader(result))
	err = dec.Decode(&res)
	return res, err
}

func (u *UDPClient) Rewind(command string, data interface{}) (interface{}, error) {
	var buf bytes.Buffer
	enc := gob.NewEncoder(&buf)
	err := enc.Encode(data)
	if err != nil {
		return nil, err
	}

	serialized := append([]byte(command), buf.Bytes()...)
	var result []byte
	var res interface{}

	for {
		result, err = u.send(command, serialized, 20, 100*time.Microsecond)
		if err == nil {
			break
		}
		u.reconnect()
		time.Sleep(u.timeout * 2)
	}

	dec := gob.NewDecoder(bytes.NewReader(result))
	err = dec.Decode(&res)
	return res, err
}

์ด ์ฝ”๋“œ๋Š” UDP ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ์„œ๋ฒ„์™€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๊ธฐ ์œ„ํ•œ UDPClient ๊ตฌ์กฐ์ฒด์™€ ๊ทธ ๋ฉ”์„œ๋“œ๋“ค์„ ์ •์˜ํ•œ Go ํŒจํ‚ค์ง€์ž…๋‹ˆ๋‹ค. ๋น„์ „๊ณต์ž๋„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐ ๋ถ€๋ถ„์„ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐœ์š”

UDPClient๋Š” UDP๋ฅผ ํ†ตํ•ด ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

UDPClient ๊ตฌ์กฐ์ฒด

  • UDPBase: UDP ํ†ต์‹ ์— ํ•„์š”ํ•œ ๊ธฐ๋ณธ ์„ค์ •์„ ํฌํ•จํ•˜๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ์ƒ์†๋ฐ›์Šต๋‹ˆ๋‹ค.

  • conn: UDP ์—ฐ๊ฒฐ์„ ๊ด€๋ฆฌํ•˜๋Š” ํฌ์ธํ„ฐ์ž…๋‹ˆ๋‹ค.

  • addr: ํ†ต์‹ ํ•  ์„œ๋ฒ„์˜ ์ฃผ์†Œ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

NewUDPClient ํ•จ์ˆ˜

์ด ํ•จ์ˆ˜๋Š” UDPClient์˜ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์„ค์ •์„ ํ†ตํ•ด UDP ํด๋ผ์ด์–ธํŠธ๋ฅผ ์„ค์ •ํ•œ ํ›„, create ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์—ฐ๊ฒฐ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

create ๋ฉ”์„œ๋“œ

์ด ๋ฉ”์„œ๋“œ๋Š” ์ฃผ์–ด์ง„ ์ฃผ์†Œ์™€ ํฌํŠธ๋กœ UDP ์—ฐ๊ฒฐ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ResolveUDPAddr๋กœ ์ฃผ์†Œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ , DialUDP๋กœ ์—ฐ๊ฒฐ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ดํ›„ ์ฝ๊ธฐ ํƒ€์ž„์•„์›ƒ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

reconnect ๋ฉ”์„œ๋“œ

์ด ๋ฉ”์„œ๋“œ๋Š” ์—ฐ๊ฒฐ์„ ์žฌ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด ์—ฐ๊ฒฐ์„ ๋‹ซ๊ณ , create ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ƒˆ๋กœ์šด ์—ฐ๊ฒฐ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

send ๋ฉ”์„œ๋“œ

์ด ๋ฉ”์„œ๋“œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๊ณ , ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ ๋ฐ์ดํ„ฐ์™€ ๋ช…๋ น์–ด๋ฅผ ๋ณด๋‚ด๊ณ , ์ตœ๋Œ€ retry ํšŸ์ˆ˜๋งŒํผ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. ์‘๋‹ต์„ ์„ฑ๊ณต์ ์œผ๋กœ ๋ฐ›์œผ๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

Once ๋ฉ”์„œ๋“œ

์ด ๋ฉ”์„œ๋“œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„๋กœ ํ•œ ๋ฒˆ๋งŒ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ ๋ฐ์ดํ„ฐ๋ฅผ ์ง๋ ฌํ™”ํ•˜์—ฌ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๊ณ , ์‘๋‹ต์„ ๋””์ฝ”๋”ฉํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

Rewind ๋ฉ”์„œ๋“œ

์ด ๋ฉ”์„œ๋“œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„๋กœ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ณด๋‚ด๊ณ , ์‘๋‹ต์„ ๋ฐ›์„ ๋•Œ๊นŒ์ง€ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. ์žฌ์‹œ๋„ ์ค‘์— ์—ฐ๊ฒฐ์ด ๋Š์–ด์ง€๋ฉด ๋‹ค์‹œ ์—ฐ๊ฒฐ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์ข…์ ์œผ๋กœ ์‘๋‹ต์„ ๋””์ฝ”๋”ฉํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์š”์•ฝ

  • UDPClient ๊ตฌ์กฐ์ฒด: UDP๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

  • NewUDPClient ํ•จ์ˆ˜: ์ƒˆ๋กœ์šด UDP ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

  • create ๋ฉ”์„œ๋“œ: ์ฃผ์–ด์ง„ ์ฃผ์†Œ์™€ ํฌํŠธ๋กœ UDP ์—ฐ๊ฒฐ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  • reconnect ๋ฉ”์„œ๋“œ: ์—ฐ๊ฒฐ์„ ์žฌ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  • send ๋ฉ”์„œ๋“œ: ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.

  • Once ๋ฉ”์„œ๋“œ: ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ๋งŒ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.

  • Rewind ๋ฉ”์„œ๋“œ: ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์„ ๋•Œ๊นŒ์ง€ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ UDP ํด๋ผ์ด์–ธํŠธ๋ฅผ ์„ค์ •ํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ๊ณผ์ •์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Last updated