Peer to Peer UDP Sockets in Golang - go

I have a distributed application which sends messages among a number of peers. I've been switching over from TCP to UDP. I've seen that UDP can send and receive using a single socket so I've attempted to implement the application with each server containing a single socket.
I've set up a little piece of code to test this out but it returns EHOSTUNREACH (65) when attempting to invoke WriteToUDP on UDPC
Id // assumed to be a unique for the server
PeerAddrList // assumed to be a slice of all server locations (addr:port strings)
N // assumed to be the number of servers
laddr, _ := net.ResolveUDPAddr("udp", PeerAddrList[Id])
UDPC, er := net.ListenUDP("udp", laddr)
if er != nil {
panic(er)
}
for i := 0; i < N; i++ {
if i == int(Id) {
continue
}
i := i
go func() {
var b [4]byte
bs := b[:4]
binary.LittleEndian.PutUint32(bs, uint32(Id))
radddr, _ := net.ResolveUDPAddr("udp", PeerAddrList[i])
if _, er := UDPC.WriteToUDP(bs, radddr); er != nil {
panic(er)
}
}()
}
for i := 0; i < N; i++ {
if i == int(Id) {
continue
}
var b [4]byte
bs := b[:4]
_, raddr, e := UDPC.ReadFromUDP(bs)
if e != nil {
panic(e)
}
// check if laddr == id
id := int32(binary.LittleEndian.Uint32(bs))
log.Printf("Got id %d from %s", id, raddr.String())
}
Any advice on why this behaviour is different from what I expected, or how to fix it, would be greatly appreciated.

I discovered that the reason why the problem existed is that I was testing on my loopback address but didn't specify the address in PeerAddrList, only ":PORT". When giving addresses as "127.0.0.1:PORT" SendTo on the UDP socket worked

Related

Go's garbage collector is deleting ZeroMQ sockets when in use

I am developing a distributed system uisng ZeroMQ and Go. It's like a distributed ledger so you can get the contects and append. I have automated clients making GET and ADD requests. The program runs fine for a couple of seconds but then crashes with the error "panic: socket operation on non-socket".
I tried turning off the garbage collector using debug.SetGCPercent(-1) but im sure this solution is not entirely correct.
This is the server initialization code
package server
import (
"backend/config"
"backend/gset"
"backend/tools"
zmq "github.com/pebbe/zmq4"
)
type Server struct {
Zctx *zmq.Context
Peers map[string]*zmq.Socket
Receive_socket zmq.Socket
Id string
Gset map[string]string
Port string
My_init map[string]bool
My_echo map[string]bool
My_vote map[string]bool
Peers_echo map[string]bool
Peers_vote map[string]bool
}
func CreateServer(node config.Node, peers []config.Node, zctx *zmq.Context) *Server {
id := node.Host + node.Port
port := node.Port
server_sockets := make(map[string]*zmq.Socket)
my_gset := gset.Create()
my_init := make(map[string]bool)
my_echo := make(map[string]bool)
my_vote := make(map[string]bool)
peers_echo := make(map[string]bool)
peers_vote := make(map[string]bool)
receive_socket, _ := zctx.NewSocket(zmq.ROUTER)
receive_socket.Bind("tcp://*:" + node.Port)
tools.Log(id, "Bound tcp://*:"+node.Port)
// Connect my dealer sockets to all other servers' router
for i := 0; i < len(peers); i++ {
s, _ := zctx.NewSocket(zmq.DEALER)
s.SetIdentity(id)
s.Connect("tcp://localhost:" + peers[i].Port)
// append socket to socket list
server_sockets["tcp://localhost:"+peers[i].Port] = s
}
return &Server{
Peers: server_sockets,
Receive_socket: *receive_socket,
Id: id,
Port: port,
Gset: my_gset,
My_init: my_init,
My_echo: my_echo,
My_vote: my_vote,
Peers_echo: peers_echo,
Peers_vote: peers_vote,
}
}
And this is the function that contols the server
func Normal_listener_task(s *server.Server) {
for {
message, err := s.Receive_socket.RecvMessage(0)
if err != nil {
fmt.Println(zmq.AsErrno(err))
panic(err)
}
messaging.HandleMessage(s, message)
}
}
The entire code is in my github here
If anyone knows why this is happening you will save my thesis. Thank you
The problem was that I was declaring the receive_socket with Receive_socket zmq.Socket when it should have been *Receive_socket zmq.Socket. The pointer was just a copy, therefore being considered trash by the GC.

How can I keep reading using net Conn Read method

I'm creating a simple chat server as a personal project to learn net package and some concurrency in go. My 1st idea is to make the server print whatever is send using nc command echo -n "hello" | nc -w1 -4 localhost 2016 -p 61865. However after the 1st read my code ignores the subsequent messages.
func (s *Server) messageReader(conn net.Conn) {
defer conn.Close()
buffer := make([]byte, 1024)
for {
//read buff
blen, err := conn.Read(buffer)
if err != nil {
log.Fatal(err)
}
message := string(buffer[:blen])
if message == "/quit" {
fmt.Println("quit command received. Bye.")
return
}
if blen > 0 {
fmt.Println(message)
buffer = buffer[:0]
}
}
}
// Run Start up the server. Manages join and leave chat
func (s *Server) Run() {
// Listen on port TCP 2016
listener, err := net.Listen("tcp", ":2016")
if err != nil {
log.Fatal(err)
}
defer listener.Close()
for {
//wait for connection
conn, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
go s.messageReader(conn)
}
}
If I send a new message from a new client it prints without problems but if I send another one it does nothing. What am I missing do I need to reset the Conn or close it and spawn a new one?
After printing your message, you slice buffer down to zero length. You can't read any data into a zero-length slice. There's no reason to re-slice your read buffer at all.
You also need to handle the read bytes before checking for errors, as io.EOF can be returned on a successful read.
You shouldn't use log.Fatal in the server's read loop, as that calls os.Exit
A working messageReader body might look like:
defer conn.Close()
buffer := make([]byte, 1024)
for {
n, err := conn.Read(buffer)
message := string(buffer[:n])
if message == "/quit" {
fmt.Println("quit command received. Bye.")
return
}
if n > 0 {
fmt.Println(message)
}
if err != nil {
log.Println(err)
return
}
}
You should note though that because you're not using any sort of framing protocol here, you can't guarantee that each conn.Read returns a complete or single message. You need to have some sort of higher-level protocol to delimit messages in your stream.

Go: Server should block until a message from the client is received

I'm building some server/client application in Go (the language is new to me). I searched a lot and read a whole bunch of different examples but there is still one thing I can't find. Lets say I have a single server client up and running. The client will send some kind of a message to the server and vice versa. Encoding and decoding is done by the package gob.
This example is not my application, it is only a quick example:
package main
import (
"bytes"
"encoding/gob"
"fmt"
"log"
)
type Message struct {
Sender string
Receiver string
Command uint8
Value int64
}
func (message *Message) Set(sender string, receiver string, command uint8, value int64) *Message {
message.Sender = sender
message.Receiver = receiver
message.Command = command
message.Value = value
return message
}
func main() {
var network bytes.Buffer // Stand-in for a network connection
enc := gob.NewEncoder(&network) // Will write to network.
dec := gob.NewDecoder(&network) // Will read from network.
message := new(Message).Set("first", "second", 10, -1)
err := enc.Encode(*message) // send message
if err != nil {
log.Fatal("encode error:", err)
}
var m Message
err = dec.Decode(&m) // receice message
if err != nil {
log.Fatal("decode error:", err)
}
fmt.Printf("%q %q %d %d\n", m.Sender, m.Receiver, m.Command, m.Value)
}
This works fine, but I want the server to block until a new message is received so I can put the receiving process inside a infinite for loop inside a goroutine.
Something like that:
for {
// The server blocks HERE until a message from the client is received
fmt.Println("Received message:")
// Decode the new message
var m Message
err = dec.Decode(&m) // receice message
if err != nil {
log.Fatal("decode error:", err)
}
fmt.Printf("%q %q %d %d\n", m.Sender, m.Receiver, m.Command, m.Value)
}
The gob decoder blocks until it has read a full message or there's an error. The read loop in the question works as is.
working example on the playground
add a length header to the raw tcp stream.
that means, send a 4-bytes-length-header information to server before send the real load. and in server side read 4 bytes, allocate buffer, full read total message, and finally decode.
assume you have a tcp connection conn, in server side we could have:
func getInt(v []byte) int {
var r uint
r = 0
r |= uint(v[0]) << 24
r |= uint(v[1]) << 16
r |= uint(v[2]) << 8
r |= uint(v[3]) << 0
return int(r)
}
buf := make([]byte, 4)
_, err := io.ReadFull(conn, buf)
if err != nil {
return
}
length := getInt(buf)
buf = make([]byte, length)
_, err = io.ReadFull(conn, buf)
if err != nil {
return
}
//do gob decode from `buf` here
you may know client side refer the the server side source I think.

ListenUDP, a one way street?

When I run this code an incoming UDP packet gets read in, however no packet gets sent back out. Why is this? (I verified this fact with wireshark). I want to be able to communicate two ways over a UDP connection, how do I achieve this with golang?
//Node 1
func main() {
addr := net.UDPAddr{
Port: 7000,
IP: net.ParseIP("127.0.0.1"),
}
conn, err := net.ListenUDP("udp", &addr)
defer conn.Close()
if err != nil {
panic(err)
}
for {
b := make([]byte, 10)
conn.Read(b)
fmt.Println(string(b[:]))
conn.Write([]byte("sending back"))
}
}
func main() {
sock, _ := net.Dial("udp", "127.0.0.1:7000")
buf := make([]byte, 10)
sock.Write([]byte("first send"))
sock.Read(buf)
fmt.Println(string(buf[:]))
}
Remember, UDP is connection-less. When you call conn.Write, your listener doesn't know where to send the packet. In your server code, you should be using UDPConn.ReadFromUDP and UDPConn.WriteToUDP to obtain and specify the client address, as mentioned in the documentation:
The returned connection's ReadFrom and WriteTo methods can be used to receive and send UDP packets with per-packet addressing.
Your modified Node 1 loop could then look something like the following:
for {
b := make([]byte, 10)
n, clientAddr, _ := conn.ReadFromUDP(b) // TODO: error check
fmt.Println(string(b[:n]))
conn.WriteToUDP([]byte("sending back"), clientAddr)
}

How to access other client connections from a Go WebSocket handler?

Note: I'm more interested in understanding general Go concepts/patterns, rather than solving this contrived example.
The Go (golang) WebSocket package provides a trivial echo server example, which condenses down to something like this:
func EchoServer(ws *websocket.Conn) { io.Copy(ws, ws); }
func main() {
http.Handle("/echo", websocket.Handler(EchoServer));
http.ListenAndServe(":12345", nil);
}
The server handles simultaneous connections, and I'm trying to upgrade it to a basic chat server by echoing the input to all connected clients.
How would I go about providing the EchoServer handler access to each of the open connections?
A quick little almost-functional example to give you an idea
var c = make(chan *websocket.Conn, 5) //5 is an arbitrary buffer size
var c2 = make(chan []byte, 5)
func EchoServer(ws *websocket.Conn) {
buff := make([]byte, 256)
c <- ws
for size, e := ws.Read(buff); e == nil; size, e = ws.Read(buff) {
c2 <- buff[0:size]
}
ws.Close()
}
func main() {
go func() {
var somekindofstorage
for {
select {
case newC := <-c:
somekindofstorage.Add(newC)
case msg := <-c2:
for _, v := range somekindofstorage {
if _, e := v.Write(msg); e != nil { //assuming the client disconnected on write errors
somekindofstorage.Remove(v)
}
}
}
}
}()
http.Handle("/echo", websocket.Handler(EchoServer));
http.ListenAndServe(":12345", nil);
}
This starts a goroutine that listens on two channels, one for new connections to add and one for messages to send to all active connection. somekindofstorage could be a map or a vector.
Edit:
Alternatively, you could just store all connections in a global map and write to each from EchoServer. But maps aren't designed to be accessed concurrently.

Resources