V
V
vpdhjjk2018-11-13 18:29:38
go
vpdhjjk, 2018-11-13 18:29:38

How to implement messaging between two users in Golang?

I saw many examples using websocket, where messages were sent to a general chat, or "rooms" were created. How to create a messaging between two users by id or nickname, for example? What packages do you recommend to use?

Answer the question

In order to leave comments, you need to log in

3 answer(s)
Y
yayashitoya, 2018-11-13
@yayashitoya

WebSocket is a way to bypass browser restrictions on http.
When you have both programs in pure Go, there is no need to use WebSocket crutches.
Use directly https://golang.org/pkg/net/
"By ID or nickname" - this is generally from another opera.
If the ID / nickname can be freely changed - then what's the difference what to use? Do you really need a package to transfer from one computer to another with a simple string?
If the ID/nickname is strictly limited, then you need a certain server that both of your clients trust, and which performs authentication.

A
Andrew, 2018-11-13
@mhthnz

Create the Clients structure. it contains fields nickname, connect.

type Client struct {
       ID        int                  // Идентификатор юзера
       Nickname   string             // Никнейм клиента
       Conn 	 *websocket.Conn    // Сокет клиента
}

After the client is authorized on your socket server, add it to the clients global array, and actually catch message packets, for example, in json:
Then you loop through the clients array and if the client’s nickname matches the to field from json, then send him a message.
PS The most superficial description, without deepening into user/session/authentication/working with json channels

A
Alexander, 2018-11-16
@alex__brin

Let's imagine a situation. We have some very simple protocol, and we will transfer everything using JSON
. He gave as an example server.go and client.go
server.go contains approximately what should be in a regular
client.go server just to demonstrate the connection ( although you can also connect via telnet)
I hope it turned out not too complicated and quite understandable
. If you still have questions or need help, you can write to personal messages on VKontakte, a link in the profile, which will be more efficient (or here in the comments) :)

server.go
package main

import (
  "io"
  "strings"
  "encoding/json"
  "bufio"
  "time"
  "log"
  "net"
)

// Это наш сервер
type Server struct {
  Addr string
  IdleTimeout time.Duration
  MaxReadBytes int64
}
func (s Server) ListenAndServe() error {
  if s.Addr == "" {
    s.Addr = ":3000"
  }

  log.Printf("starting server on %v\n", s.Addr)

  listener, err := net.Listen("tcp", s.Addr)
  if err != nil {
    return err
  }
  defer listener.Close()

  for {
    conn, err := listener.Accept()
    if err != nil {
      log.Printf("error accption connection %v", err)
      continue
    }

    connection := &Conn{
      Conn: conn,
      IdleTimeout: s.IdleTimeout,
      MaxReadBytes: s.MaxReadBytes,
    }
    connection.SetDeadline(time.Now().Add(connection.IdleTimeout))

    log.Printf("accepted connection from %v", conn.RemoteAddr())

    connection.Write([]byte("Content-Type: appliaction/json\n  action:\n    ping - ping\n    scream - upper the text\n  body - content\n"))
    go handle(connection) // запускаем обработчик в новой горутине, чтобы быть готовым принять еще одно соединение 
  }
}

type Conn struct {
  net.Conn
  IdleTimeout time.Duration // Ожидание, когда сервер что-нибудь скажет или прочитает
  MaxReadBytes int64 // максимальный объем передаваемых данных, чтобы клиент вдруг не захотел передать нам гигабайты данных
}
func (c *Conn) Write(p []byte) (int, error) {
  c.updateDeadline()
  return c.Conn.Write(p)
}
func (c *Conn) Read(b []byte) (int, error) {
  c.updateDeadline()
  r := io.LimitReader(c.Conn, c.MaxReadBytes)
  return r.Read(b)
}
func (c *Conn) updateDeadline() {
  c.Conn.SetDeadline(time.Now().Add(c.IdleTimeout))
}

// Это будет наш запрос
type Request struct {
  Action string `json:"action"` // наше действие
  Body   string `json:"body"` // и само тело запроса
}

func handle(conn *Conn) {
  defer func() { // Функция выполнится после return этой функции
    log.Printf("closing connection from %v", conn.RemoteAddr())
    conn.Close()
  }()

  r := bufio.NewReader(conn.Conn)
  w := bufio.NewWriter(conn.Conn)
  scaner := bufio.NewScanner(r)
  for {
    if !scaner.Scan() { // если произошло что-то неладное
      if err := scaner.Err(); err != nil {
        log.Printf("%v(%v)", err, conn.RemoteAddr())
        return // то выйдем из функции (и, благодаря defer, закроем соединение)
      }
    }

    req := Request{}
    scanned := scaner.Text() // читаем текст из сети
    log.Println(scanned)
    err := json.Unmarshal([]byte(scanned), &req) // парсим json в нашу структуру
    if err != nil {
      log.Printf("error parsing json: ", err)
    }

    log.Println("New request. Action:", req.Action, "|", "Message:", req.Body)

    response := ""

    switch req.Action {
    case "ping": // будем отвечать pong
      response = "pong"

    case "scream": // кричать
      response = strings.ToUpper(req.Body)

    case "bye": // и прощаться
      response = "Bye!"

    default: // иначе будем ругаться, что не знаем такого действия
      response = "Unknown Action"
    }

    w.WriteString(response + "\n")
    w.Flush()

    if req.Action == "bye" { // если клиент попрощался, то закрываем соединение
      return
    }
  }
}

func main() {
  srv := Server{":3030", time.Minute, 1024}
  srv.ListenAndServe()
}
client.go
package main

import (
  "encoding/json"
  "os"
  "fmt"
  "net"
)

type Request struct {
  Action string `json:"action"`
  Body   string `json:"body"`
}

func main() {
  conn, err := net.Dial("tcp", "localhost:3030") // Подключаемся к порту
  checkErr(err)
  defer conn.Close()

  hello := make([]byte, 1024)
  conn.Read(hello)
  fmt.Println(string(hello))

  req := Request{}
  for {
    fmt.Print("Action: ")
    fmt.Fscan(os.Stdin, &req.Action)
    fmt.Print("Body: ")
    fmt.Fscan(os.Stdin, &req.Body)

    jsonData, err := json.Marshal(req)
    if err != nil {
      fmt.Println(err)
      continue
    }
    jsonData = append(jsonData, byte('\n'))
    fmt.Println(string(jsonData))
    i, err := conn.Write(jsonData)
    if err != nil {
      panic(err)
    }
    fmt.Println("write", i, "bytes")

    response := make([]byte, 1024)
    i, err = conn.Read(response)
    if err != nil {
      panic(err)
    }
    fmt.Println("read", i, "bytes")
    fmt.Println(string(response))
  }

}

func checkErr(err error) {
  if err != nil {
    panic(err)
  }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question