Skip to content

Instantly share code, notes, and snippets.

@USA-RedDragon
Last active October 11, 2023 08:19
Show Gist options
  • Save USA-RedDragon/bbd012659b3783c9a4a3ba49b6559499 to your computer and use it in GitHub Desktop.
Save USA-RedDragon/bbd012659b3783c9a4a3ba49b6559499 to your computer and use it in GitHub Desktop.
Go Channels demo for a friend
package ipsc
import (
"fmt"
"net"
)
// Structs are sort of like classes
type UDP struct {
// Variable definitions are opposite to a lot of other languages
// in Go's case it's "pc is a net.PacketConn" vs other languages
// "we have a net.PacketConn named pc"
pc net.PacketConn
// the channel type, which can pass an array of bytes
write_chan chan []byte
}
// These New* function sort of function as
// constructors might in object oriented languages
func NewUDP() *UDP {
// The := operator makes a new variable without having
// to declare it. It also manages typing for you, like
// `auto` types in other languages
pc, err := net.ListenPacket("udp", ":31003")
// This is how error checking works in Go, no try-catch or exceptions
if err != nil {
panic(err)
}
// This just instantiates the struct above and returns the pointer to it
return &UDP{
pc: pc,
// make is kinda what it says on the label, make a new channel that takes in bytes
// channels are one of a very few types that requires a pre-allocation with make()
write_chan: make(chan []byte),
}
}
// And these functions with (u *UDP) are declaring them
// a function of the struct so that later
// users can use this with udp.Start() where udp
// is a pointer to a UDP struct as defined above
func (u *UDP) Start() {
// String concatenation with a +!!!
fmt.Println("Listening on " + u.pc.LocalAddr().String())
// the `go` keyword effectively spins up a coroutine
// stylized a "goroutine" because it's technically
// different and more lightweight.
//
// After the following two lines the start function will
// return and the reader (not shown here) and writer
// will be running
go u.reader()
go u.writer()
}
func (u *UDP) writer() {
// infinite loop so we keep the writer running
for {
// select is amazing, it is kinda like a switch-case
// but with channels it will block the thread until
// one of the conditions are met. This helps to avoid
// spinning on the cpu with a nasty infinite loop
select {
// this says create the data variable when data comes in from the write channel
// this is kinda like C++'s streams, but actually useful
case data := <-u.write_chan:
fmt.Printf("Writing %v\n", data)
// nifty little one-liner that also instantiates a UDPAddr pointer
_, err := u.pc.WriteTo(data, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 31000})
if err != nil {
fmt.Println("Error sending packet: ", err)
continue
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment