Может ли golang net.Conn получать уведомления при появлении нового сообщения? - PullRequest
0 голосов
/ 26 декабря 2018

Что я пытаюсь реализовать

Я реализую клиент, отправляющий и получающий unixpackets и взаимодействующий с сервером, который уже был реализован в C ++.
Пока клиентможет получить и отправить пакет на сервер успешно.Но я использовал цикл for для продолжения вызова Recv , чтобы узнать, есть ли новое сообщение.

Что я сделал

Я реализовал пакеткласс, чтобы клиент и сервер могли следовать тем же правилам для кодирования и декодирования сообщения.Транспорт - это структура, упаковывающая net.Conn .Клиент состоит из транспорта, получающего и отправляющего пакета.
Я использовал для цикла , чтобы продолжать звонить Recv , чтобы узнать, приходит ли новое сообщение net.conn

type Packet struct {
    Length      uint32
    Data        []byte
    ReadOffset  uint32
    WriteOffset uint32
}

type Transport struct {
    url   string
    conn  net.Conn
}

// connect to url
func (transport *Transport) Dial(url string) error {
    c, err := net.Dial("unixpacket", url)
    if err != nil {
        return err
    }
    transport.url = url
    transport.conn = c
    return nil
}

// sending Packet
func (transport *Transport) Send(p *Packet) bool {
    readBuffer := (p.Data)[p.ReadOffset : p.WriteOffset]
    _, err := transport.conn.Write(readBuffer)
    if err != nil {
        return false
    }
    return true
}

// receiving Packet
func (transport *Transport) Recv(p *Packet) bool {
    writeBuffer := (p.Data)[p.WriteOffset :]
    _, err := transport.conn.Read(writeBuffer)
    if err != nil {
        return false
    }
    return true
}

type Client struct {
    Transport  *Transport
    RecvPacket *Packet
    SendPacket *Packet
}

// keep checking transport
func (c *Client) ReadFromTransport() {
    for {
        time.Sleep(20 * time.Millisecond)
        if c.Transport.Recv(c.RecvPacket) == false {
            continue
        }
    }
}

Вопрос

Есть ли способ, чтобы net.conn получал уведомление при поступлении нового сообщения net.conn вместо использования цикла for?

Ответы [ 2 ]

0 голосов
/ 27 декабря 2018

Есть ли способ, чтобы net.conn получал уведомление при поступлении нового сообщения net.conn вместо использования цикла for?

Нет, не в стандартных пакетах.

Чтение () из net.Conn в цикле - это обычный способ обнаружения прибытия сообщения.Если вам нужно выполнить несколько одновременных задач, вы можете инкапсулировать цикл в запись процедуры в канал и обернуть цикл for, а также выбрать чтение из этого канала.

Вне стандартных пакетов вы можете исследовать событиеIO с такими проектами, как https://github.com/tidwall/evio

0 голосов
/ 26 декабря 2018

net.conn.Read автоматически блокируется, пока данные не будут доступны для соединения.Вам не нужно зацикливаться, чтобы дождаться появления данных.

Наличие простого сокет-сервера (в python3 просто для того, чтобы прояснить языковой барьер)

import socket, os, sys

addr='/tmp/a_unix_socket'

if os.path.exists(addr):
  os.unlink(addr)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)

sock.bind(addr)
sock.listen(1)

while True:
  print("Waiting for connection", file=sys.stderr)
  conn, client_addr = sock.accept()
  data =conn.recv(128)
  print("Recived {}".format(data))
  conn.sendall(b'thank you')
  conn.close()

Я могу сделать клиент golang следующим образом:

package main

import (
  "net"
  "fmt"
)

func main() {
  conn, err := net.Dial("unix", "/tmp/a_unix_socket")
  if err != nil {
    panic(err)
  }
  conn.Write([]byte("here is data"))
  result := make([]byte, 128)
  _, err = conn.Read(result)
  if err != nil {
    panic(err)
  }
  fmt.Println("Response: ", string(result))
  conn.Close()
}

Серверсторона говорит:

$ python3 ./t.py
Waiting for connection
Recived b'here is data'
Waiting for connection

Клиентская сторона говорит:

$ go run t.go
Response:  thank you

net.Conn здесь не настроен тайм-аут чтения, поэтому он готов ждать столько времени, сколько потребуется.

Позвольте мне также упомянуть следующее:

if err != nil {
    return false
}

Это скрывает ошибки за незаметными «ложными» ответами.В случае неустранимой ошибки (скажем, закрытое соединение с сервером) ваш клиент будет бесконечно зацикливаться (перегружая процессор).Если вам нужно выявить ошибки, верните их.Если вы хотите быть ленивым в доказательстве концепции, наберите panic() их, если нужно, но не возвращайте одинаковый результат для всех из них, иначе вы не сможете правильно обрабатывать отдельные случаи ошибок.В вашем случае это своего рода спорный вопрос, поскольку вам все равно не нужен цикл for.

...