Golang TCP Server and Client Example [Tutorial]


GO

Author: Tuan Nguyen
Reviewer: Deepak Prasad

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:

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:

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.

  • 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

 

Tuan Nguyen

Tuan Nguyen

He is proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise spanning these technologies, he develops robust solutions and implements efficient data processing and management strategies across various projects and platforms. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

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 send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment