Шаблон обратного вызова для обработки ответа сокета


Я в процессе обучения идти и иду через PHP, JS и Nodejs фоне.

Я создал пакет, который представляет собой клиент, который подключается к сокет-сервера и обрабатывает данные, полученные от сервера. Я использую шаблон обратного вызова, и я интересно, если это не одобряется в обществе идут. Здесь представлены актуальные фрагменты кода:

// SocketClient allows handles the socket connection to a server
type SocketClient struct {
    Host string
    Path string
    conn *websocket.Conn
}

// SocketResponse function callback for data from socket
type SocketResponse func(res []byte, err error)

// Connect create the connection with the host
func (sc SocketClient) Connect(cb SocketResponse) {
    interrupt := make(chan os.Signal, 1)
    signal.Notify(interrupt, os.Interrupt)

    u := url.URL{Scheme: "wss", Host: sc.Host, Path: sc.Path}

    var err error
    sc.conn, _, err = websocket.DefaultDialer.Dial(u.String(), nil)

    if err != nil {
        cb(nil, err)
    }

    defer sc.conn.Close()

    done := make(chan struct{})

    // anonymous function call
    go func() {
        defer sc.conn.Close()
        defer close(done)
        for {
            _, message, err := sc.conn.ReadMessage()
            if err != nil {
                cb(nil, err)
            }
            cb(message, nil)
        }
    }()

    // ...
}

А потом в другой файл, я на самом деле инициализировать SocketClient и соединении...

sc.Connect(func(res []byte, err error) {
    // handle the response
})


587
4
задан 27 января 2018 в 10:01 Источник Поделиться
Комментарии
1 ответ


Я использую шаблон обратного вызова, и я интересно, если это не одобряется в обществе идут.

"обратный звонок узор" не стоит неодобрением (они используются в "функции первого класса", например: https://blog.golang.org/first-class-functions-in-go-and-new-go https://dave.cheney.net/2016/11/13/do-not-fear-first-class-functions)

Однако что касается вашего кода, я не думаю, что он выглядит как идиоматические код.


Не просто проверять ошибки, обработаны

sc.conn, _, err = websocket.DefaultDialer.Dial(u.String(), nil)

if err != nil {
cb(nil, err)
}

Вы проходите err для вашего обратного вызова, но вы потом дальше внутри Connect функция: если вы не смогли набрать, почему вы продолжаете?


Никогда не начинайте горутина не зная, как это остановить

go func() {
defer sc.conn.Close()
defer close(done)
for {
_, message, err := sc.conn.ReadMessage()
if err != nil {
cb(nil, err)
}
cb(message, nil)
}
}()

Внутренний for цикл никогда не остановится (так будет ваш горутина).


Одна возможность состояла бы в том, чтобы изменить его, как это:

// SocketResponse function callback for data from socket
type SocketResponse func(res []byte)

// Connect create the connection with the host
func (sc SocketClient) Connect(cb SocketResponse) error {
u := url.URL{Scheme: "wss", Host: sc.Host, Path: sc.Path}

var err error
sc.conn, _, err = websocket.DefaultDialer.Dial(u.String(), nil)

if err != nil {
return err
}

defer sc.conn.Close()
for {
_, message, err := sc.conn.ReadMessage()
if err != nil {
return err
}
cb(message)
}
}

Некоторые свойства этого кода :


  • на ошибки диск, он останавливается

  • он читает все сообщения до одной ошибки

  • он блокирует (но go sc.Connect() легко писать)

Некоторые возможные ситуации:


  • продолжать даже в случае ошибки, можно вернуть канал ошибок (и послать всех ошибок)

  • также использовать канал, чтобы сообщить о полученных сообщениях

  • для контроля, когда Connect способ следует прекратить, вы могли бы использовать context или разделить ваш метод на 3 части: Connect, ReadMessage & Close

3
ответ дан 2 февраля 2018 в 09:02 Источник Поделиться