UDP server issues with multi ports connections - go

I have a UDP server that expose two ports, 8080 for normal data and 8082 for controll (keep alive signal). When I start the server one new instance of Server is created. It have a list of clients: a client is represented by a struct that contains two types of UDPConn, one for control and one for data. What is happening is when I run my Client.go I connect to server in both ports but, the server creates two clients instead of only one. Downward are part of my Server.go and Client.go. What can I do to create only one user for both connections?
Server.go
func main() {
server := NewLobby()
addressCntrl, err := net.ResolveUDPAddr(CONN_TYPE, CONN_CNTRL_PORT)
if err != nil {
log.Fatalf("Error resolving controller address: %s", err)
}
listenerCntrl, err := net.ListenUDP(CONN_TYPE, addressCntrl)
defer listenerCntrl.Close()
log.Printf("Listening controll on port %s", CONN_CNTRL_PORT)
addressData, err := net.ResolveUDPAddr(CONN_TYPE, CONN_DATA_PORT)
if err != nil {
log.Fatalf("Error Resolving data address: %s", err)
}
listenerData, err := net.ListenUDP(CONN_TYPE, addressData)
defer listenerData.Close()
log.Printf("Listening data on port %s", CONN_DATA_PORT)
for {
buffer = make([]byte, 1024)
listenerData.ReadFromUDP(buffer)
c := NewClient(*listenerData, *listenerCntrl)
server.Join(c)
}
}
NewServer (server.go)
func NewServer() *Server {
server := &Server{
clients: make([]*Client, 0),
chatRooms: make(map[string]*ChatRoom),
incoming: make(chan *Message),
join: make(chan *Client),
leave: make(chan *Client),
delete: make(chan *ChatRoom),
}
server.Listen()
return server
}
NewClient (server.go)
func NewClient(connData net.UDPConn, connCntrl net.UDPConn) *Client {
writerData := bufio.NewWriter(&connData)
readerData := bufio.NewReader(&connData)
writerCntrl := bufio.NewWriter(&connCntrl)
readerCntrl := bufio.NewReader(&connCntrl)
client := &Client{
name: CLIENT_NAME,
chatRoom: nil,
incoming: make(chan *Message),
outgoing: make(chan string),
connData: connData,
connCntrl: connCntrl,
readerData: readerData,
writerData: writerData,
readerCntrl: readerCntrl,
writerCntrl: writerCntrl,
}
log.Printf("New client connected")
client.Listen()
return client
}
Client.go
func main() {
server := NewServer()
addressCntrl, err := net.ResolveUDPAddr(CONN_TYPE, CONN_CNTRL_PORT)
if err != nil {
log.Fatalf("Error resolving controller address: %s", err)
}
listenerCntrl, err := net.ListenUDP(CONN_TYPE, addressCntrl)
defer listenerCntrl.Close()
log.Printf("Listening controll on port %s", CONN_CNTRL_PORT)
addressData, err := net.ResolveUDPAddr(CONN_TYPE, CONN_DATA_PORT)
if err != nil {
log.Fatalf("Error Resolving data address: %s", err)
}
listenerData, err := net.ListenUDP(CONN_TYPE, addressData)
defer listenerData.Close()
log.Printf("Listening data on port %s", CONN_DATA_PORT)
for {
buffer = make([]byte, 1024)
listenerData.ReadFromUDP(buffer)
c := NewClient(*listenerData, *listenerCntrl)
server.Join(c)
}
}
One example of output is bellow
Server output
2021/05/06 20:03:52 Listening controll on port :8082
2021/05/06 20:03:52 Listening data on port :8080
2021/05/06 20:03:56 New client connected
2021/05/06 20:03:58 New client connected
Client output
Welcome to the server! Type "/help" to get a list of commands.
Welcome to the server! Type "/help" to get a list of commands.
If needed my functions Read() and Write() of client is bellow.
Read (client.go)
func Read(connData net.UDPConn, connCntrl net.UDPConn) {
//Controller
go func() {
readerCntrl := bufio.NewReader(&connCntrl)
for {
str, _ := readerCntrl.ReadString('\n')
if strings.Compare(str, "timeout") == 0 {
os.Exit(1)
}
}
}()
//Data
reader := bufio.NewReader(&connData)
for {
str, err := reader.ReadString('\n')
if err != nil {
fmt.Printf(MSG_DISCONNECT)
wg.Done()
return
}
fmt.Print(str)
}
}
Write (client.go)
func Write(connData net.UDPConn, connCntrl net.UDPConn) {
//Controller
go func() {
writerCntrl := bufio.NewWriter(&connCntrl)
for range time.Tick(10 * time.Second) {
writerCntrl.WriteString("ka")
}
}()
//Data
reader := bufio.NewReader(os.Stdin)
writerData := bufio.NewWriter(&connData)
for {
input, err := reader.ReadString('\n')
if err != nil {
log.Fatalf("Error reading input: %s", err)
}
_, err = writerData.WriteString(input)
if err != nil {
log.Fatalf("Error writing input to server: %s", err)
}
err = writerData.Flush()
if err != nil {
log.Fatalf("Error flushing the input: %s", err)
wg.Done()
}
}
}

Related

Transfering file using tcp golang

I'm trying to make a music app that sends file through tcp protocol using go and microservice architecture. Now I'm creating a player service that should:
Get user token and get claims from it
Check is user exists using claims and user_service microservice
Get song from redis
Check is song exists using music_service
Read file by chunks and send it to client using tcp
Redis data looks like this:
{
"user_id": [{
"song_id": "<song_id>"
}]
}
But I faced with a small problem. My music files stored in a flac format and when I receive it on the client, my player doesn't play it. I don't really know what can be the problem. So here's my code:
SERVER
service_setup.go
//this function is called in main function
func setService() {
ln, err := net.Listen("tcp", config.TCPAddress)
if err != nil {
panic("couldn't start tcp server")
}
defer ln.Close()
for {
conn, err := ln.Accept()
if err != nil {
logger.ErrorLog(fmt.Sprintf("Error: couldn't accept connection. Details: %v", err))
return
}
service.DownloadSong(conn)
}
}
downloader_service.go
func DownloadSong(conn net.Conn) {
token, err := bufio.NewReader(conn).ReadString('\n')
if err != nil {
logger.ErrorLog(fmt.Sprintf("Error: couldn't get token. Details: %v", token))
conn.Close()
return
}
claims, err := jwt_funcs.DecodeJwt(token)
if err != nil {
conn.Close()
return
}
songs, err := redis_repo.Get(claims.Id)
if err != nil {
conn.Close()
return
}
for _, song := range songs {
download(song, conn)
}
}
func download(song models.SongsModel, conn net.Conn) {
filePath, err := filepath.Abs(fmt.Sprintf("./songs/%s.flac", song.SongId))
if err != nil {
logger.ErrorLog(fmt.Sprintf("Errror: couldn't create filepath. Details: %v", err))
conn.Close()
return
}
file, err := os.Open(filePath)
defer file.Close()
if err != nil {
logger.ErrorLog(fmt.Sprintf("Errror: couldn't open file. Details: %v", err))
conn.Close()
return
}
read(file, conn)
}
func read(file *os.File, conn net.Conn) {
reader := bufio.NewReader(file)
buf := make([]byte, 15)
defer conn.Close()
for {
_, err := reader.Read(buf)
if err != nil && err == io.EOF {
logger.InfoLog(fmt.Sprintf("Details: %v", err))
fmt.Println()
return
}
conn.Write(buf)
}
}
CLIENT
main.go
func main() {
conn, _ := net.Dial("tcp", "127.0.0.1:6060")
var glMessage []byte
text := "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYzYzlhNmE1OWI3ZmQyNTQ2ZjA4ZWEyYSIsInVzZXJuYW1lIjoiMTIiLCJleHAiOjE2NzQyMTE5ODl9.aarSDhrFF1df3i2pIRyjNxTfSHKObqLU3kHJiPreredIhLNCzs7z7jMgRHQIcLaIvCOECN7bX0OaSvKdW7VKsQ\n"
fmt.Fprint(conn, text)
reader := bufio.NewReader(conn)
b := make([]byte, 15)
c := 0
for i, _ := reader.Read(b); int(i) != 0; i, _ = reader.Read(b) {
c += i
glMessage = append(glMessage, b...)
}
os.WriteFile("./test.flac", glMessage, 0644)
}
If you know what can be the problem, please tell me. I'd really appreciate it!
It looks like you're trying to send the music file over the network in 15 byte chunks, which is likely not enough to play the song on the client side.
You can try increasing the chunk size, for example, to 8192 bytes. To do this, replace buf := make([]byte, 15) with buf := make([]byte, 8192).
Also, it's better to write the received data directly to the file rather than storing it in memory. You can do this by creating a file and using os.Create to write the received data to it:
file, err := os.Create("./test.flac")
if err != nil {
fmt.Println("Error: couldn't create file")
return
}
defer file.Close()
for {
i, err := reader.Read(buf)
if err != nil && err == io.EOF {
break
}
file.Write(buf[:i])
}
I believe that this can solve the issue.

Go net.Conn.Write sending EOF error on TCP Proxy

Overview
I'm currently working on a simple TCP proxy to port forward a connection to an echo server that I've placed on a server in my house. I'm running the TCP proxy and client on the same machine, the echo server is the only program on another device.
The client is just a simple python script that declares and initializes a TCP socket and invokes a socket.send(b'testing some random byte message\n')
If I direct connect the client to the server, everything works fine but it's when I utilize the client/proxy connection when the server never receives the msg. In fact, the server outputs that the proxy and initiated a connection but only when I try to send a packet through from the client is when the server detects an io.EOF error.
Connections
server listening on : 192.168.1.253:6969
proxy listening on : 0.0.0.0:6969
proxy forwarding to server listener
client connecting on proxy listener
I've reduced the functionality to only have the proxy read and send once, then exit. Please excuse any remaining artifacts...
Proxy
func main() {
dstDone := make(chan struct{})
msgChannel := make(chan []byte)
go func(msgs <-chan []byte) {
dst, err := net.DialTimeout("tcp", "192.168.1.253:6969", 750*time.Millisecond)
if err != nil {
fmt.Println("Error connecting to dst -", err)
os.Exit(2)
}
dstWriter := bufio.NewWriter(dst)
n, err := dstWriter.Write(<-msgs)
if err != nil {
fmt.Println("Error writing to dst -", err)
os.Exit(1)
}
fmt.Println("Wrote ", n, "B to dst")
dstDone <- struct{}{}
}(msgChannel)
srcListener, err := net.Listen("tcp", ":6969")
if err != nil {
fmt.Println("Error listening for source -", err)
os.Exit(1)
}
srcConnection, err := srcListener.Accept()
if err != nil {
fmt.Println("Error accepting connection -", err)
os.Exit(1)
}
srcReader := bufio.NewReader(srcConnection)
msg, merr := srcReader.ReadBytes('\n')
if merr != nil {
fmt.Println("Error reading socket info -", err)
os.Exit(1)
}
fmt.Println("Message received [", msg, "]")
fmt.Println("Sending to dst")
msgChannel <- msg
<-dstDone
}
Server
// Start() is called in another go file's main which only consists of this call and
// initializes a channel for indicating when to quit.
func Start(serverDone *chan struct{}) {
listener, err := net.Listen("tcp", ":6969")
if err != nil {
fmt.Println("Could not listen:", err)
*serverDone <- struct{}{}
}
go func(serverDone *chan struct{}) {
buffer := make([]byte, 4096)
fmt.Println("-- Server Running --\nEnter 'Q' to quit.")
for {
s, err := os.Stdin.Read(buffer)
if err != nil {
fmt.Printf("%s\n", err)
break
}
if s > 2 {
fmt.Printf("Invalid Command\n")
} else {
if buffer[0] == 81 {
break
}
}
}
*serverDone <- struct{}{}
}(serverDone)
for {
connection, err := listener.Accept()
if err != nil {
fmt.Println("Error accepting connection:", err)
*serverDone <- struct{}{}
break
}
fmt.Printf("%v connected\n", connection.RemoteAddr())
go customBufferEcho(&connection)
}
}
func customBufferEcho(connection *net.Conn) {
defer (*connection).Close()
inBuffer := make([]byte, 4096)
outBuffer := make([]byte, 4096)
for {
fmt.Println("Waiting for msg...")
n, err := (*connection).Read(inBuffer[0:]) // tried only 'inBuffer' and did not work
if err == io.EOF {
fmt.Println("Client disconnected") // Server prints this msg on any msg sent from proxy
return
}
if err != nil {
fmt.Println("Error reading from connection |", err)
return
}
fmt.Println("-- MSG Received [ ", n, "B ]--\n", Dump(inBuffer, 4, 4))
outBuffer = inBuffer
(*connection).Write(outBuffer[0:n])
}
}
Wireshark Inspection

Golang grpc: how to determine when the server has started listening?

So I have the following:
type Node struct {
Table map[string]string
thing.UnimplementedGreeterServer
address string
}
func (n *Node) Start() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
thing.RegisterGreeterServer(s, n)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
In my main function I'll spin up mulitple nodes like so:
func main() {
n :=Node{Table: map[string]string{}}
go n.Start()
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
}
The problem is, because I'm spinning up the node concurrently, there's a chance the dial up connection might not work because the node might not have been setup yet.
Ideally, I'd like a done channel that tells me when the grpc server has actually started listening. How do I accomplish this?
This is essntially the same problem as How to add hook on golang grpc server start? which doesn't have an answer
s.Serve(listener) blocks, so you can't achieve your purpose by having a done chan, instead you have to implement the healthcheck and readiness for your service, and check those before performing any request by the client.
The server should implement the following proto:
syntax = "proto3";
package grpc.health.v1;
message HealthCheckRequest {
string service = 1;
}
message HealthCheckResponse {
enum ServingStatus {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
SERVICE_UNKNOWN = 3; // Used only by the Watch method.
}
ServingStatus status = 1;
}
service Health {
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}
For example, the envoy proxy grpc_health_check works with the above proto.
Read GRPC Health Checking Protocol for more information.
The server can be Dialed as soon as net.Listen returns a nil error. Dial will block until the server calls Accept (which will happen somewhere in s.Serve in this case).
Either move creation of the listener into the caller and pass it as an argument:
func (n *Node) Start(lis net.Listener) {
s := grpc.NewServer()
thing.RegisterGreeterServer(s, n)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
n := Node{Table: map[string]string{}}
go n.Start(lis)
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
}
Or signal that the listener is up after Listen returns:
func (n *Node) Start(up chan struct{}) {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
if up != nil {
close(up)
}
s := grpc.NewServer()
thing.RegisterGreeterServer(s, n)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
func main() {
n := Node{Table: map[string]string{}}
up := make(chan struct{})
go n.Start(up)
<-up
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
}
For all those who are still looking for an answer to this, here is another simple way to do it. Start the server in a child routine. Here is a code snippet:
// Start the server in a child routine
go func() {
if err := s.Serve(listener); err != nil {
log.Fatalf("Failed to serve: %v", err)
}
}()
fmt.Println("Server succesfully started on port :50051")
In my case I am using MongoDB as well, so when you run it, you get:
grpc-go-mongodb-cobra>go run server/main.go
Starting server on port :50051...
Connecting to MongoDB...
Connected to MongoDB
Server succesfully started on port :50051
I have also written a Blog post on this, with working code in GitHub. Here is the link: https://softwaredevelopercentral.blogspot.com/2021/03/golang-grpc-microservice.html

How to cache a TCP reverse proxy data transmission?

I've accomplished implementing TCP reverse proxy in GoLang. But unfortunately couldn't come up with implementing caching to a TCP reverse proxy. Is it possible to do so, if yes, is there any resource out there? Is caching possible on a TCP (Transport Layer of Network)?
Here's the simple TCP reverse proxy in Golang.
package main
import (
"io"
"log"
"net"
)
//Proxy struct
type Proxy struct {
laddr, raddr *net.TCPAddr
lconn, rconn io.ReadWriteCloser
errorSignal chan bool
}
// New Create a new Proxy instance.
func New(lconn *net.TCPConn, laddr, raddr *net.TCPAddr) *Proxy {
return &Proxy{
lconn: lconn,
laddr: laddr,
raddr: raddr,
errorSignal: make(chan bool),
}
}
//TCPAddressResolver resolves an address and returns to a struct having ip and port.
func TCPAddressResolver(addr string) (tcpAddress *net.TCPAddr, err error) {
tcpAddress, err = net.ResolveTCPAddr("tcp", addr)
return
}
func main() {
listenerAddress, err := TCPAddressResolver(":8080")
if err != nil {
log.Fatalf("Failed to resolve local address: %v", err)
}
remoteAddress, err := TCPAddressResolver(":3000")
if err != nil {
log.Fatalf("Failed to resolve remote address: %v", err)
}
listener, err := net.ListenTCP("tcp", listenerAddress)
if err != nil {
log.Fatalf("Failed to open local port to listen: %v", err)
}
log.Printf("Simple Proxy started on: %d and forwards to port %d", listenerAddress.Port, remoteAddress.Port)
for {
conn, err := listener.AcceptTCP()
if err != nil {
log.Fatalf("Failed to accept connection: %v", err)
continue
}
var p *Proxy
// HTTP is a stateless protocol thus a proxy needs to reinitiate the new next incoming call (conn)
// each time it finishes handling the previous one.
p = New(conn, listenerAddress, remoteAddress)
p.Start()
}
}
//Start initiates transmission of data to and from the remote to client side.
func (p *Proxy) Start() {
defer p.lconn.Close()
var err error
p.rconn, err = net.DialTCP("tcp", nil, p.raddr)
if err != nil {
log.Fatalf("Remote connection failure: %v", err)
}
defer p.rconn.Close()
go p.CopySrcDst(p.lconn, p.rconn)
go p.CopySrcDst(p.rconn, p.lconn)
//Wait for everything to close -- This one blocks the routine.
<-p.errorSignal
log.Printf("Closing Start routine \n")
}
func (p *Proxy) err(err error) {
if err != io.EOF {
log.Printf("Warning: %v: Setting error signal to true", err)
}
p.errorSignal <- true
}
//CopySrcDst copies data from src to dest
func (p *Proxy) CopySrcDst(src, dst io.ReadWriteCloser) {
buff := make([]byte, 1024)
for {
n, err := src.Read(buff)
if err != nil {
// Reading error.
p.err(err)
return
}
dataFromBuffer := buff[:n]
n, err = dst.Write(dataFromBuffer)
if err != nil {
// Writing error.
p.err(err)
return
}
}
}
You are asking how to save data read from an io.Reader. That's different from caching.
The easiest approach is to tee the reader into a buffer.
While you are at it, you might as well use io.Copy instead of the similar code in the question. The code in the question does not handle the case when read returns n > 0 and a non-nil error.
Use an error group to coordinate waiting for the goroutines and collecting error status.
var g errgroup.Group
var rbuf, lbuf bytes.Buffer
g.Go(func() error {
_, err := io.Copy(lconn, io.TeeReader(p.rconn, &rbuf))
return err
})
g.Go(func() error {
_, err := io.Copy(rconn, io.TeeReader(p.lconn, &lbuf))
return err
})
if err := g.Wait(); err != nil {
// handle error
}
// rbuf and lbuf have the contents of the two streams.
The name of the programming language is "Go", not "Golang" or "GoLang".

GoLang TCP Connection - Remote Network is down check

I am creating a GoLang application and clients are android phones. I am able to handle connections. If user closes the android application connection is dropped with EOF
My problem is, if client just turn off wifi network connection is still alive.
Here is my code
func main() {
fmt.Println("Starting server...")
connection, err := net.Listen("tcp", ":4406")
if err != nil {
fmt.Println(err)
}
defer connection.Close()
manager := ClientManager{
clients: make(map[*Client]bool),
broadcast: make(chan []byte),
register: make(chan *Client),
}
go manager.start()
for {
connection, _ := connection.Accept()
if err != nil {
fmt.Println(err)
}
client := &Client{socket: connection, data: make(chan []byte), uuid: connection.RemoteAddr().String()}
manager.register <- client
go manager.receive(client)
go handleConnection(client)
}
}
Handeling connections
func handleConnection(client *Client) {
conn := client.socket
defer conn.Close()
notify := make(chan error)
go func() {
buf := make([]byte, 1024)
for {
n, err := conn.Read(buf)
if err != nil {
notify <- err
return
}
if n > 0 {
fmt.Println("unexpected data: %s", buf[:n])
}
}
}()
for {
select {
case err := <-notify:
if err != nil {
fmt.Println("connection dropped message", err)
return
}
case <-time.After(time.Second * 1):
fmt.Println("timeout 1, still alive")
}
}
}
When remote wifi is off (cable removed) I want to disconnect the user. I tried to read a byte and every second and it is reading it. I sent a byte and it is sent as well.

Resources