Skip to content

Instantly share code, notes, and snippets.

@leyyce
Last active August 10, 2020 21:18
Show Gist options
  • Save leyyce/139faca4cbdceee73812c58f3348533c to your computer and use it in GitHub Desktop.
Save leyyce/139faca4cbdceee73812c58f3348533c to your computer and use it in GitHub Desktop.
[Go] Simple example of how to use sockets for a basic, multithreaded, TCP based client-server communication.
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
arguments := os.Args
if len(arguments) == 1 {
fmt.Printf("Please provide address and port number in the form ADDR:PORT. (Call like this: %s ADDR:PORT)\n", arguments[0])
return
}
service := arguments[1]
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
checkError(err)
conn, err := net.DialTCP("tcp4", nil, tcpAddr)
checkError(err)
for {
fmt.Print("Please enter a command: ")
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
input := scanner.Text()
checkError(err)
_, err = conn.Write([]byte(input + "\x04"))
checkError(err)
if input == "dc"{
fmt.Println("Closing the connection and exiting client...")
err = conn.Close()
checkError(err)
return
}
response, err := bufio.NewReader(conn).ReadString('\x04')
response = strings.TrimSuffix(response, "\x04")
checkError(err)
fmt.Println(response + "\n")
}
}
func checkError(err error) {
if err != nil {
println("Program execution was aborted due to following ERROR: ", err.Error())
os.Exit(1)
}
}
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
"time"
)
func main() {
arguments := os.Args
if len(arguments) == 1 {
fmt.Printf("Please provide the port number the server should listen on. (Call like this: %s PORT)\n", arguments[0])
return
}
var service = ":" + arguments[1]
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
fmt.Printf("Starting local server @PORT %s\n\n", tcpAddr.String()[1:])
checkError(err)
listener, err := net.ListenTCP("tcp4", tcpAddr)
checkError(err)
for {
conn, err := listener.Accept()
fmt.Printf("Connected to client %s\n", conn.RemoteAddr())
checkError(err)
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
fmt.Printf("Handling connection %s\n", conn.RemoteAddr())
for {
message, err := bufio.NewReader(conn).ReadString('\x04')
message = strings.TrimSuffix(message, "\x04")
fmt.Printf("Recived message \"%s\" from %s\n", message, conn.RemoteAddr())
checkForConnDrop(err, conn)
if err != nil {
return
}
switch message {
case "help":
helpText := "List of available commands:\n\n" +
"ping - Makes the server reply with a pong\n" +
"time - The server replies with the current server time\n" +
"echo [message]- The server echos back the [message]\n" +
"dc - Closes the connection with the server\n" +
"help - Gives you this list"
_, err := conn.Write(prepareMessage(helpText))
checkError(err)
case "ping":
_, err := conn.Write(prepareMessage("<- pong"))
checkError(err)
case "time":
curTime := time.Now().Format(time.RFC822)
_, err := conn.Write(prepareMessage(curTime))
checkError(err)
case "dc":
fmt.Printf("Closing connection with client %s.\n", conn.RemoteAddr())
err := conn.Close()
checkError(err)
return
default:
if strings.Contains(message, "echo") {
message = strings.Replace(message, "echo ", "", 1)
_, err := conn.Write(prepareMessage(message))
checkError(err)
} else {
_, err := conn.Write(prepareMessage("The command " + message + " is unknown. For a list of available commands use \"help.\""))
checkError(err)
}
}
}
}
func checkError(err error) {
if err != nil {
println("Program execution was aborted due to following ERROR: ", err.Error())
os.Exit(1)
}
}
func checkForConnDrop(err error, conn net.Conn) {
if err != nil {
fmt.Printf("Connection to client %s was aborted due to following ERROR: %s\n", conn.RemoteAddr().String(), err.Error())
}
}
func prepareMessage(message string) []byte {
return []byte(message + "\x04")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment