As I'm finding quite some examples how to write a go server and client, this works locally on one machine.
Now I'm trying to communicate in my local network between two PCs, one running the go server script, one the client.
However, I can't establish a connection because of the error:
Error: listen udp 192.168.11.6:10001: bind: cannot assign requested address
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x401376] // ...
Of course I will post my code (client, where the problem occurs):
package main
import (
"fmt"
"net"
"strconv"
"time"
)
func CheckError(err error) {
if err != nil {
fmt.Println("Error: ", err)
}
}
func main() {
ServerAddr, err := net.ResolveUDPAddr("udp", "192.168.11.6:10001")
CheckError(err)
Conn, err := net.ListenUDP("udp", ServerAddr)
CheckError(err)
defer Conn.Close()
i := 0
for {
msg := strconv.Itoa(i)
i++
buf := []byte(msg)
_, err = Conn.WriteToUDP(buf, ServerAddr)
time.Sleep(time.Second * 1)
}
}
Server:
package main
import (
"fmt"
"net"
"os"
)
/* A Simple function to verify error */
func CheckError(err error) {
if err != nil {
fmt.Println("Error: " , err)
os.Exit(0)
}
}
func main() {
ServerAddr,err := net.ResolveUDPAddr("udp",":10001")
CheckError(err)
ServerConn, err := net.ListenUDP("udp", ServerAddr)
CheckError(err)
defer ServerConn.Close()
buf := make([]byte, 1024)
for {
fmt.Println("Starting...")
n,addr,err := ServerConn.ReadFromUDP(buf)
fmt.Println("Received ",string(buf[0:n]), " from ",addr)
ServerConn.WriteToUDP([]byte("hello there!"), addr)
if err != nil {
fmt.Println("Error: ",err)
}
}
}
The client has the local network IP address 192.168.11.8 and the server 192.168.11.6. They can also ping each other, and I'm opening the port when Windows asks for it.
I'm happy about all suggestions. I struggle with this because I only find localhost server client go examples.
Okay, I figured it out. Weird that I had to allow the app to communicate on public networks? While I am on my home network. When starting the server - I had to enable public networks
I figured out that I do not have to open a socket on the client side, but use DialUDP
Also the server needed the full Ip address in
ServerAddr,err := net.ResolveUDPAddr("udp","192.168.11.6:10001")
Improved Client code: (main func)
ServerAddr, err := net.ResolveUDPAddr("udp", "192.168.11.6:10001")
CheckError(err)
buf := make([]byte, 1024)
Conn, err := net.DialUDP("udp", nil, ServerAddr)
CheckError(err)
defer Conn.Close()
i := 0
for {
msg := strconv.Itoa(i)
i++
fmt.Printf(msg)
n, err := Conn.Write([]byte(msg))
CheckError(err)
fmt.Printf("sent %d bytes", n)
n, addr, err := Conn.ReadFromUDP(buf)
if err == nil {
fmt.Printf("%s %s\n", buf, addr)
} else {
fmt.Printf("some err %v\n", err)
}
time.Sleep(time.Second * 1)
}
Related
I am trying to create a UDP server in Golang to Listen at a port for eg. 1234. I have a client which sends the start/stop message to this server.
On receiving of message "start", the server will start sending random data to this client and on the stop, the server will stop sending to the client.
For this purpose, I am using context to create a goroutine to send the data and cancel it when it gets "stop".
The error I am getting is the program works fine for one client, but if I start the client again the data is not sent again.
Any help would be appreciated?
UDP server Code:
package main
import (
"context"
"fmt"
"math/rand"
"net"
"time"
)
func generateMessageToUDP(ctx context.Context, addr *net.UDPAddr) {
// stop writing to UDP
done := false
fmt.Println("Generating message to UDP client", addr)
conn, err := net.DialUDP("udp", nil, addr)
if err != nil {
fmt.Println("Error: ", err)
}
defer func(conn *net.UDPConn) {
err := conn.Close()
if err != nil {
fmt.Println("Error in closing the UDP Connection: ", err)
}
}(conn)
// write to address using UDP connection
go func() {
for i := 0; !done; i++ {
RandomInt := rand.Intn(100)
fmt.Println("Random Int: ", RandomInt)
_, err = conn.Write([]byte(fmt.Sprintf("%d", RandomInt)))
fmt.Println("Sent ", RandomInt, " to ", addr)
time.Sleep(time.Second * 1)
}
}()
<-ctx.Done()
fmt.Println("Stopping writing to UDP client", addr)
done = true
}
//var addr *net.UDPAddr
//var conn *net.UDPConn
func main() {
fmt.Println("Hi this is a UDP server")
udpServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 5010})
if err != nil {
fmt.Println("Error: ", err)
}
defer func(udpServer *net.UDPConn) {
err := udpServer.Close()
if err != nil {
fmt.Println("Error in closing the UDP Connection: ", err)
}
}(udpServer)
// create a buffer to read data into
buffer := make([]byte, 1024)
ctx, cancel := context.WithCancel(context.Background())
for {
// read the incoming connection into the buffer
n, addr, err := udpServer.ReadFromUDP(buffer)
fmt.Println("Recieved ", string(buffer[0:n]), " from ", addr)
if err != nil {
fmt.Println("Error: ", err)
}
fmt.Println("Received ", string(buffer[0:n]), " from ", addr)
if string(buffer[0:n]) == "stop" {
fmt.Println("Stopped listening")
cancel()
continue
} else if string(buffer[0:n]) == "start" {
// send a response back to the client
_, err = udpServer.WriteToUDP([]byte("Hi, I am a UDP server"), addr)
if err != nil {
fmt.Println("Error: ", err)
}
// start a routine to generate messages to the client
generateMessageToUDP(ctx, addr)
} else {
fmt.Println("Unknown command")
}
}
}
Client Code:
package main
import (
"fmt"
"net"
"time"
)
func main() {
fmt.Println("Hello, I am a client")
// Create a new client
localAddr, err := net.ResolveUDPAddr("udp", ":5011")
client3, err := net.DialUDP("udp", localAddr, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 5010})
if err != nil {
fmt.Println(err)
return
}
defer client3.Close()
_, err = client3.Write([]byte("start"))
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Message sent. Sleeping for 5 seconds")
time.Sleep(time.Second * 5)
fmt.Println("Sending stop message")
_, err = client3.Write([]byte("stop"))
if err != nil {
fmt.Println(err)
}
}
You must take care to what you are doing.
avoid data races (done variable is read/write by two different routines without synchronization mechanism) https://go.dev/doc/articles/race_detector
dont make a new dialer everytime the program start sending messages to a new client. This will open a new local address and use it to send it to the client. The client will receive messages from another address, which it should normally ignore, because it did not initiated any exchange with that remote.
dont mixup client lifetime span with the program context lifetime span. In the code provided a client sending a stop message will trigger the cancel function of the whole program, it will stop all clients. Make a new context for each client, derived from the program context, cancel the related client context upon receiving a stop message.
UDP conns are shared by all clients, they must not be stopped from listening incoming packets because the program is serving a client. IE the call to generateMessageToUDP should be executed into another routine.
Following is a revised version accounting for those comments.
A var peers map[string]peer is added to match a remote address with a context. The type peer is defined as struct {stop func();since time.Time}. Upon receiving a start message, the peer is added to the map with a derived context, pctx, pcancel := context.WithCancel(ctx). The new client is then served in a different routine, go generateMessageToUDP(pctx, udpServer, addr), which is bond to the newly created context and the server socket. Upon receiving a stop message, the program performs a lookup peer, ok := peers[addr.String()], it then cancels the associated peer context peer.stop(); delete(peers, addr.String()) and forgets the peer.
package main
import (
"context"
"fmt"
"math/rand"
"net"
"time"
)
func generateMessageToUDP(ctx context.Context, conn *net.UDPConn, addr *net.UDPAddr) {
fmt.Println("Generating message to UDP client", addr)
go func() {
for i := 0; ; i++ {
RandomInt := rand.Intn(100)
d := []byte(fmt.Sprintf("%d", RandomInt))
conn.WriteTo(d, addr)
time.Sleep(time.Second * 1)
}
}()
<-ctx.Done()
fmt.Println("Stopping writing to UDP client", addr)
}
//var addr *net.UDPAddr
//var conn *net.UDPConn
func main() {
fmt.Println("Hi this is a UDP server")
udpServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 5010})
if err != nil {
fmt.Println("Error: ", err)
}
defer func(udpServer *net.UDPConn) {
err := udpServer.Close()
if err != nil {
fmt.Println("Error in closing the UDP Connection: ", err)
}
}(udpServer)
// create a buffer to read data into
type peer struct {
stop func()
since time.Time
}
peers := map[string]peer{}
buffer := make([]byte, 1024)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for {
// read the incoming connection into the buffer
n, addr, err := udpServer.ReadFromUDP(buffer)
if err != nil {
fmt.Println("Error: ", err)
}
fmt.Println("Received ", string(buffer[0:n]), " from ", addr)
if string(buffer[0:n]) == "stop" {
fmt.Println("Stopped listening")
peer, ok := peers[addr.String()]
if !ok {
continue
}
peer.stop()
delete(peers, addr.String())
continue
} else if string(buffer[0:n]) == "start" {
peer, ok := peers[addr.String()]
if ok {
continue
}
pctx, pcancel := context.WithCancel(ctx)
peer.stop = pcancel
peer.since = time.Now()
peers[addr.String()] = peer
// send a response back to the client
_, err = udpServer.WriteToUDP([]byte("Hi, I am a UDP server"), addr)
if err != nil {
fmt.Println("Error: ", err)
}
// start a routine to generate messages to the client
go generateMessageToUDP(pctx, udpServer, addr)
} else if string(buffer[0:n]) == "ping" {
peer, ok := peers[addr.String()]
if !ok {
continue
}
peer.since = time.Now()
peers[addr.String()] = peer
} else {
fmt.Println("Unknown command")
}
for addr, p := range peers {
if time.Since(p.since) > time.Minute {
fmt.Println("Peer timedout")
p.stop()
delete(peers, addr)
}
}
}
}
-- go.mod --
module play.ground
-- client.go --
package main
import (
"fmt"
"log"
"net"
"time"
)
func main() {
fmt.Println("Hello, I am a client")
// Create a new client
localAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:5011")
client3, err := net.DialUDP("udp", localAddr, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 5010})
if err != nil {
fmt.Println(err)
return
}
defer client3.Close()
var n int
n, err = client3.Write([]byte("start"))
if err != nil {
fmt.Println(err)
return
}
log.Println(n)
now := time.Now()
b := make([]byte, 2048)
for time.Since(now) < time.Second*10 {
n, addr, err := client3.ReadFrom(b)
fmt.Println(n, addr, err)
if err != nil {
fmt.Println(err)
continue
}
if addr.String() == "127.0.0.1:5010" {
m := b[:n]
fmt.Println("message:", string(m))
}
}
fmt.Println("Sending stop message")
_, err = client3.Write([]byte("stop"))
if err != nil {
fmt.Println(err)
}
}
In
go func() {
for i := 0; ; i++ {
RandomInt := rand.Intn(100)
d := []byte(fmt.Sprintf("%d", RandomInt))
conn.WriteTo(d, addr)
time.Sleep(time.Second * 1)
}
}()
I left as an exercise to the reader the writing of the missing select on the context channel to figure out if the routine should exit.
Okay, I did a simple hack on the server and added a label Start before creating a context and when I cancel the context, I addded goto label. This means when the task get cancelled it will again create the context and start doings its job
I am a beginner in Go programming and I am confused about a problem about bufio readers.
I'm programming a kind of chat client who must display and send our messages in live time. But messages that I receive are not displayed until I press enter in my terminal.
After few tests, it seems to be my "inputListener()" function being the problem because, if I put it after reading messages from server, messages from server are displaying first.
I supposed that the Read function may blocked my loop until it get a '\n' or something like that.
Here is my code:
package main
import "os"
import "strconv"
import "net"
import "bufio"
/*Recovery our input message into a buffer*/
func inputListener()([] byte){
buf := make([]byte, 512)
readerInput := bufio.NewReader(os.Stdin)
_, err := readerInput.Read(buf)
if err != nil{
panic("Error reading input.")
os.Exit(0)
}
return buf
}
func main(){
if len(os.Args) != 3{
println("Usage: ",os.Args[0], " <host> <port>\n")
os.Exit(0)
}
//Recovery the port.
port, err := strconv.Atoi(os.Args[2])
if err != nil{
panic("Error during the port recovery\n")
os.Exit(0)
}
println(port)
/*Join the adresse*/
addr := os.Args[1] + ":" + strconv.Itoa(port)
println(addr)
/* sources -- https://golang.org/pkg/net/ */
conn, err := net.Dial("tcp", addr)
if err != nil{
panic("Error connecting " + addr)
os.Exit(0)
}
buf := make([]byte, 512)
t := make([]byte, 512)
for {
/*Receive data from server*/
size, err := conn.Read(buf)
if err != nil {
panic("Error reading output.")
os.Exit(0)
}
if size >= 0{
print(string(buf[0:size]))
}
/*Data we need to send*/
t = inputListener()
if len(t) >= 0{
conn.Write(t)
}
}
conn.Close()
}
I need to press enter per messages received :/
Thank you in advance for your answers !
You be try something like this:
package main
import (
"bufio"
"io"
"net"
"os"
"strconv"
)
/*Recovery our input message into a buffer*/
func inputListener() []byte {
buf := make([]byte, 512)
readerInput := bufio.NewReader(os.Stdin)
_, err := readerInput.Read(buf)
if err != nil {
panic("Error reading input.")
}
return buf
}
func main() {
if len(os.Args) != 3 {
println("Usage: ", os.Args[0], " <host> <port>\n")
os.Exit(0)
}
//Recovery the port.
port, err := strconv.Atoi(os.Args[2])
if err != nil {
panic("Error during the port recovery\n")
}
println(port)
/*Join the adresse*/
addr := os.Args[1] + ":" + strconv.Itoa(port)
println(addr)
/* sources -- https://golang.org/pkg/net/ */
conn, err := net.Dial("tcp", addr)
if err != nil {
panic("Error connecting " + addr)
}
defer conn.Close()
go io.Copy(os.Stdout, conn)
r := bufio.NewReader(os.Stdin)
for {
p, err := r.ReadSlice('\n')
if err != nil {
panic("Error reading output.")
}
conn.Write(p)
}
}
I need recive udp package and send their to broadcast address other interface.
I wrote udp forward server. Its work!
How change the source udp address new packages to src address income package?
package main
import (
"fmt"
"net"
"os"
)
func CheckError(err error) {
if err != nil {
fmt.Println("Error: " , err)
os.Exit(0)
}
}
func main() {
ServerAddr,err := net.ResolveUDPAddr("udp4",":10001")
CheckError(err)
LocalAddr, err := net.ResolveUDPAddr("udp4", "192.168.164.83:10001")
CheckError(err)
RemoteAddr, err := net.ResolveUDPAddr("udp4", "192.168.164.255:10002")
CheckError(err)
Conn, err := net.DialUDP("udp4", LocalAddr, RemoteAddr)
CheckError(err)
defer Conn.Close()
ServerConn, err := net.ListenUDP("udp4", ServerAddr)
CheckError(err)
defer ServerConn.Close()
buf := make([]byte, 2048)
for {
n,addr,err := ServerConn.ReadFromUDP(buf)
fmt.Println("Received ",n , "bytes from ",addr)
if err != nil {
fmt.Println("Error-recive: ",err)
} else {
go Conn.Write(buf[0:n])
}
}
}
i can send msg from client to server successfully. But when i try to reply message back to client, somehow client cant receive the message.
Client:
conn, _:= net.Dial("udp", serv_addr:port)
defer conn.close()
buf:= []byte("Hey, server")
conn.Write(buf)
recv:= make([]byte, 1024)
fmt.Println("Reading...\n")
conn.Read(recv)
Server:
addr, _:= net.ResolveUDPAddr("udp", addr:port)
msg := make([]byte, 1024)
conn,_: net.ListenUDP("udp", addr)
_, ret_addr, _: conn.ReadFromUDP(msg)
//print msg
conn.WriteToUDP([]byte("got your msg", ret)
It's a very simple udp connection. server can printout the msg from client, but on client side, it keeps waiting before conn.read() while server finished its task.
I followed this article. my implementation is almost identical.
Here is a minimum code for you to play around with.
start a server part in one terminal:
go run main.go server :53033
start client in the other terminal:
go run main.go client :53033
now type messages at the client terminal and you should see both client and server exchanging messages. You can start multiple clients (in new terminal windows) and communicate with the same server.
package main
import (
"bufio"
"fmt"
"io"
"log"
"net"
"os"
)
func server(url string) {
log.Printf("serving on %s\n", url)
addr, err := net.ResolveUDPAddr("udp", url)
errcheck(err)
conn, err := net.ListenUDP("udp", addr)
errcheck(err)
defer close(conn)
msg := make([]byte, 1024)
for {
n, retAddr, err := conn.ReadFromUDP(msg)
errcheck(err)
log.Printf("received %v bytes, ret addr %v, msg %s", n, retAddr, string(msg[:n]))
reply := []byte(fmt.Sprintf("received from you: %v bytes", n))
n, err = conn.WriteToUDP(reply, retAddr)
errcheck(err)
log.Printf("sent reply %v bytes\n", n)
}
}
func client(url string) {
log.Printf("client for server url: %s\n", url)
addr, err := net.ResolveUDPAddr("udp", url)
errcheck(err)
conn, err := net.DialUDP("udp", nil, addr)
errcheck(err)
defer close(conn)
msg := make([]byte, 512)
scanner := bufio.NewScanner(os.Stdin)
for {
if scanner.Scan() {
line := scanner.Text()
n, err := conn.Write([]byte(line))
errcheck(err)
log.Printf("sent %d bytes \n", n)
n, err = conn.Read(msg)
errcheck(err)
log.Printf("server replied with: %s \n", string(msg[:n]))
}
}
}
func main() {
args := os.Args[1:]
if len(args) < 2 {
log.Fatal("expecting 2 arguments client or server first followed by the address:port")
}
switch args[0] {
case "server":
server(args[1])
case "client":
client(args[1])
default:
log.Fatal("first argument must be server or client")
}
}
func errcheck(err error) {
if err != nil {
log.Fatal(err)
}
}
func close(c io.Closer) {
err := c.Close()
if err != nil {
log.Fatal()
}
}
Have fun!
I'm playing with my first basic udp server and I wondering how support concurrent connections? I think with my code only can get a connection at a time in order to process it, with a tcp simple server the things seems to be more clear than on this case, throwing a goroutine to process the data, but here I'm very lost, thanks in advance.
func main() {
ListenerUDP("127.0.0.1", 1111)
}
func ListenerUDP(ip string, port int) {
buffer := make([]byte, 1024)
log.Println("Listener Started!")
addr := net.UDPAddr{
Port: port,
IP: net.ParseIP(ip),
}
conn, err := net.ListenUDP("udp", &addr)
if err != nil {
log.Fatalf("Error Listening:%s\n", err.Error())
panic(err)
}
defer conn.Close()
for {
_, remoteAddr, err := conn.ReadFromUDP(buffer[0:])
if err != nil {
log.Fatalf("Error:%s\n", err)
}
// Process data here? using a > go something()?
fmt.Printf("Data:%s From:%v\n", buffer, remoteAddr)
}
}
UDP is a connectionless protocol--hosts send packets without establishing a connection first.
To get multiple cores handling UDP packets in parallel, you might start a bunch of goroutines that each do the ReadFromUDP loop:
package main
import (
"fmt"
"net"
"runtime"
)
func listen(connection *net.UDPConn, quit chan struct{}) {
buffer := make([]byte, 1024)
n, remoteAddr, err := 0, new(net.UDPAddr), error(nil)
for err == nil {
n, remoteAddr, err = connection.ReadFromUDP(buffer)
// you might copy out the contents of the packet here, to
// `var r myapp.Request`, say, and `go handleRequest(r)` (or
// send it down a channel) to free up the listening
// goroutine. you do *need* to copy then, though,
// because you've only made one buffer per listen().
fmt.Println("from", remoteAddr, "-", buffer[:n])
}
fmt.Println("listener failed - ", err)
quit <- struct{}{}
}
func main() {
addr := net.UDPAddr{
Port: 12345,
IP: net.IP{127, 0, 0, 1},
}
connection, err := net.ListenUDP("udp", &addr)
if err != nil {
panic(err)
}
quit := make(chan struct{})
for i := 0; i < runtime.NumCPU(); i++ {
go listen(connection, quit)
}
<-quit // hang until an error
}