Golang TCP Server and Client Example [Tutorial]

In this tutorial, we'll see how to build a straightforward TCP server that takes incoming connections. The server will reply with a message with some information. Beginners who wish to learn about the Go net package and how to process requests should check out this tutorial.

Package net provides a portable interface for network I/O, including TCP/IP, UDP, domain name resolution, and Unix domain sockets.

Although the package provides access to low-level networking primitives, most clients will need only the basic interface provided by the Dial, Listen, and Accept functions and the associated Conn and Listener interfaces. The crypto/tls package uses the same interfaces and similar Dial and Listen functions.

 

Building a Simple Golang TCP Server

Set the variables and listen and close TCP connections

First of all, we need to define the variables for the TCP connection:

Advertisement
const (
    HOST = "localhost"
    PORT = "8080"
    TYPE = "tcp"
)

The following step is to listen to new connections. The net package provides Listen() function to do that. If the listener raises any errors, logs the error message to the console and exists with a status code of 1.

func Listen(network, address string) (Listener, error): Listen announces on the local network address. The network must be "tcp", "tcp4", "tcp6", "unix" or "unixpacket". For TCP networks, if the host in the address parameter is empty or a literal unspecified IP address, Listen listens on all available unicast and anycast IP addresses of the local system.

listen, err := net.Listen(TYPE, HOST+":"+PORT)
if err != nil {
    log.Fatal(err)
    os.Exit(1)
}

To close the listener after the server terminates, use the defer keyword and the Close() method:

func (c *IPConn) Close() error: Close closes the connection.

 

Continuously listen for connections and handle requests

To continuously listen for connections, use an infinity loop:

for {
    conn, err := listen.Accept()
    if err != nil {
        log.Fatal(err)
        os.Exit(1)
}

We can write a function to handle any incoming requests:

Advertisement

Our function will take the type net.Conn struct as the parameter. We define a new buffer to store the incoming data of size 1024. Using the Write method to send data back to the client:

	// incoming request
	buffer := make([]byte, 1024)
	_, err := conn.Read(buffer)
	if err != nil {
		log.Fatal(err)
	}

	// write data to response
	time := time.Now().Format(time.ANSIC)
	responseStr := fmt.Sprintf("Your message is: %v. Received time: %v", string(buffer[:]), time)
	conn.Write([]byte(responseStr))

	// close conn
	conn.Close()

 

Full TCP Server Code

We will wrap the handle request function to a go routine:

package main

import (
	"fmt"
	"log"
	"net"
	"os"
	"time"
)

const (
	HOST = "localhost"
	PORT = "8080"
	TYPE = "tcp"
)

func main() {
	listen, err := net.Listen(TYPE, HOST+":"+PORT)
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
	// close listener
	defer listen.Close()
	for {
		conn, err := listen.Accept()
		if err != nil {
			log.Fatal(err)
			os.Exit(1)
		}
		go handleRequest(conn)
	}
}

func handleRequest(conn net.Conn) {
	// incoming request
	buffer := make([]byte, 1024)
	_, err := conn.Read(buffer)
	if err != nil {
		log.Fatal(err)
	}

	// write data to response
	time := time.Now().Format(time.ANSIC)
	responseStr := fmt.Sprintf("Your message is: %v. Received time: %v", string(buffer[:]), time)
	conn.Write([]byte(responseStr))

	// close conn
	conn.Close()
}

 

Building a Simple Golang TCP Client

Set the variables and set up a connection to TCP Server

First of all, we need to define the variables for the TCP connection:

const (
    HOST = "localhost"
    PORT = "8080"
    TYPE = "tcp"
)

Next, we have to resolve TCP server's address

tcpServer, err := net.ResolveTCPAddr(TYPE, HOST+":"+PORT)

To dial to TCP server, we will use DialTCP() function:

func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error): DialTCP acts like Dial for TCP networks. The network must be a TCP network name; see func Dial for details. If laddr is nil, a local address is automatically chosen. If the IP field of raddr is nil or an unspecified IP address, the local system is assumed. Dial connects to the address on the named network.

conn, err := net.DialTCP(TYPE, nil, tcpServer)
if err != nil {
	println("Dial failed:", err.Error())
	os.Exit(1)
}

We need to close the connection after sending and receiving data:

conn.Close()

 

Send and receive data from the server

To send and receive data, we can use Write() and Read() functions as shown below:

_, err = conn.Write([]byte("This is a message"))
if err != nil {
	println("Write data failed:", err.Error())
	os.Exit(1)
}

// buffer to get data
received := make([]byte, 1024)
_, err = conn.Read(received)
if err != nil {
	println("Read data failed:", err.Error())
	os.Exit(1)
}

 

Full TCP client code

package main

import (
	"net"
	"os"
)

const (
	HOST = "localhost"
	PORT = "8080"
	TYPE = "tcp"
)

func main() {
	tcpServer, err := net.ResolveTCPAddr(TYPE, HOST+":"+PORT)

	if err != nil {
		println("ResolveTCPAddr failed:", err.Error())
		os.Exit(1)
	}

	conn, err := net.DialTCP(TYPE, nil, tcpServer)
	if err != nil {
		println("Dial failed:", err.Error())
		os.Exit(1)
	}

	_, err = conn.Write([]byte("This is a message"))
	if err != nil {
		println("Write data failed:", err.Error())
		os.Exit(1)
	}

	// buffer to get data
	received := make([]byte, 1024)
	_, err = conn.Read(received)
	if err != nil {
		println("Read data failed:", err.Error())
		os.Exit(1)
	}

	println("Received message:", string(received))

	conn.Close()
}

Output:

Received message: Your message is: This is a message and received time: Wed Nov  2 14:36:37 2022

We can use the terminal to get the same result:

 

Summary

List the main points once more.

Advertisement
  • With the help of the net package, a TCP server and client can be made with incredibly little code.
  • Listen on all possible local unicast and anycast IP addresses if the host supplied in the address argument is null or a literal IP address that is not specified.

After reading this article, you should have a deeper comprehension of the principles involved in setting up a TCP server and client.

 

References

https://pkg.go.dev/net
https://en.wikipedia.org/wiki/Transmission_Control_Protocol

 

Categories GO

Didn't find what you were looking for? Perform a quick search across GoLinuxCloud

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment

X