Я пытаюсь создать промежуточный уровень между пользователем и tcp с функциями Send
и Receive
. В настоящее время я пытаюсь интегрировать контекст, чтобы Send
и Receive
уважали контекст. Однако я не знаю, как заставить их уважать отмену контекста. До сих пор я получал следующее.
// c.underlying is a net.Conn
func (c *tcpConn) Receive(ctx context.Context) ([]byte, error) {
if deadline, ok := ctx.Deadline(); ok {
// Set the read deadline on the underlying connection according to the
// given context. This read deadline applies to the whole function, so
// we only set it once here. On the next read-call, it will be set
// again, or will be reset in the else block, to not keep an old
// deadline.
c.underlying.SetReadDeadline(deadline)
} else {
c.underlying.SetReadDeadline(time.Time{}) // remove the read deadline
}
// perform reads with
// c.underlying.Read(myBuffer)
return frameData, nil
}
Однако, насколько я понимаю этот код, это учитывает только context.WithTimeout
или context.WithDeadline
, а не context.WithCancel
. Если возможно, я хотел бы каким-то образом передать это в соединение или фактически прервать процесс чтения.
Как я могу это сделать?
Примечание: если возможно, я бы хотел избежать другого функция, которая читает в другой горутине и отправляет результат обратно в канал, потому что тогда, когда я вызываю cancel
, и я читаю 2 ГБ по сети, это фактически не отменяет чтение, и ресурсы все еще используются. Однако, если это невозможно по-другому, я хотел бы знать, есть ли лучший способ сделать это, чем функция с двумя каналами, один для результата []byte
, а другой для error
.
РЕДАКТИРОВАТЬ: Со следующим кодом я могу соблюдать отмену, но это не прерывает чтение.
// apply deadline ...
result := make(chan interface{})
defer close(result)
go c.receiveAsync(result)
select {
case res := <-result:
if err, ok := res.(error); ok {
return nil, err
}
return res.([]byte), nil
case <-ctx.Done():
return nil, ErrTimeout
}
}
func (c *tcpConn) receiveAsync(result chan interface{}) {
// perform the reads and push either an error or the
// read bytes to the result channel