Answer the question
In order to leave comments, you need to log in
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
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.
Create the Clients structure. it contains fields nickname, connect.
type Client struct {
ID int // Идентификатор юзера
Nickname string // Никнейм клиента
Conn *websocket.Conn // Сокет клиента
}
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) :)
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()
}
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 questionAsk a Question
731 491 924 answers to any question