Writing A TCP Client In Go
Writing A TCP Client In Go
In a previous post I wrote about writing a concurrent TCP server in go.
However one thing that is unfortunate is that nc
or netcat
is not native to Windows, and might also not be avaible on lightweight containers.
So in this post we will talk about writing a TCP client that can be compiled to windows/darwin/linux/etc..
The simple client
All code will be explained using comments in the code block
package main
import (
"bufio"
"fmt"
"log"
"net"
"os"
)
func main() {
// ip and port of TCP server
ip := "127.0.0.1"
port := "8081"
// format ip and port
addr := ip + ":" + port
// dial into the tcp server and have access to the connection via `conn`
conn, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal(err)
}
// block main() and set up a reader for stdin to read inputs from the shell
for {
reader := bufio.NewReader(os.Stdin)
// grab all text prior to hitting enter
text, err := reader.ReadString('\n')
if err != nil {
log.Fatal(err)
}
// send over payload to the connection
fmt.Fprintf(conn, text+"\n")
// read the response from the server
// if you modified your server to not send a response you can omit everything below
message, err := bufio.NewReader(conn).ReadString('\n')
if err != nil {
log.Fatal(err)
}
fmt.Print(message)
}
}
Great! Now you have a simple client that does mostly what we use netcat for anyways.
If your TCP server is being interacted with from a windows client you will have to add some logic to check for \r\n
instead of just \n
.
Truly multi platform
Setting ENVs on Windows can also be a pain so here we will add usage of the flag
parser built into the Go std lib.
I have only added comments where we add new functionality:
package main
import (
"bufio"
"flag"
"fmt"
"log"
"net"
"os"
)
func main() {
var ip string
// make a CLI flag for the IP address
// go run main.go -ip=10.0.0.42
// default is "127.0.0.1"
flag.StringVar(&ip, "ip", "127.0.0.1", "ip addr of TCP server")
var port string
// make a CLI flag for the IP address
// go run main.go -port=9000
// default is "8081"
flag.StringVar(&port, "port", "8081", "port of TCP server")
// full custom use of both ip and port: go run main.go -ip=10.0.0.42 -port=9000
flag.Parse()
addr := ip + ":" + port
conn, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal(err)
}
for {
reader := bufio.NewReader(os.Stdin)
text, err := reader.ReadString('\n')
if err != nil {
log.Fatal(err)
}
fmt.Fprintf(conn, text+"\n")
message, err := bufio.NewReader(conn).ReadString('\n')
if err != nil {
log.Fatal(err)
}
fmt.Print(message)
}
}
So now you can have a nice CLI interface. You can also ask for “help” by doing:
go run main.go -h
-ip string
ip addr of TCP server (default "127.0.0.1")
-port string
port of TCP server) (default "8081")
So without having to think about how to make a nice output block, the flag
lib has got your back.
Conclusion
Hope you learned how to use flag
as well as how to make a crossplatform TCP client that will work anywhere you have Go, or if you cross compile your binary, anywhere you please!