TCP File Transfer Service Implementation in Go

Retrieving File Metadata with os.Stat()

The os.Stat() function returns a FileInfo interface containing metadata about a file:

info, err := os.Stat(filename)

The FileInfo interface defines the following methods:

type FileInfo interface {
    Name() string       // base name of the file
    Size() int64        // length in bytes for regular files
    Mode() FileMode     // file mode bits
    ModTime() time.Time // modification time
    IsDir() bool        // abbreviation for Mode().IsDir()
    Sys() any           // underlying data source (can return nil)
}

Overview

This implementation provides a TCP-based file transfer solution consisting of two components:

  • Sender: Reads a file from disk and transmits it over the network
  • Receiver: Listens for incoming connections, receives file data, and writes it to disk

Sender Implementation

package main

import (
	"fmt"
	"io"
	"net"
	"os"
)

func transmitFile(filePath string, connection net.Conn) {
	file, openErr := os.Open(filePath)
	if openErr != nil {
		fmt.Println("Failed to open file:", openErr)
		return
	}
	defer file.Close()

	buffer := make([]byte, 4096)
	for {
		bytesRead, readErr := file.Read(buffer)
		if readErr != nil {
			if readErr == io.EOF {
				fmt.Println("File transmission complete")
			} else {
				fmt.Println("Read error:", readErr)
			}
			return
		}
		connection.Write(buffer[:bytesRead])
	}
}

func main() {
	fmt.Println("Enter the file path to transfer:")
	var filePath string
	fmt.Scan(&filePath)

	fileInfo, statErr := os.Stat(filePath)
	if statErr != nil {
		fmt.Println("Stat error:", statErr)
		return
	}

	connection, dialErr := net.Dial("tcp", "127.0.0.1:8080")
	if dialErr != nil {
		fmt.Println("Connection error:", dialErr)
		return
	}
	defer connection.Close()

	_, writeErr := connection.Write([]byte(fileInfo.Name()))
	if writeErr != nil {
		fmt.Println("Write error:", writeErr)
		return
	}

	responseBuffer := make([]byte, 1024)
	bytesRead, readErr := connection.Read(responseBuffer)
	if readErr != nil {
		fmt.Println("Read error:", readErr)
		return
	}

	if string(responseBuffer[:bytesRead]) == "READY" {
		transmitFile(filePath, connection)
	}
}

Workflow:

  1. Prompt user for file path input
  2. Retrieve file metadata using os.Stat()
  3. Establish TCP connection to server
  4. Send filename to receiver
  5. Wait for acknowledgment response
  6. Stream file contents in chunks

Receiver Implementation

package main

import (
	"fmt"
	"io"
	"net"
	"os"
)

func receiveFile(filename string, connection net.Conn) {
	outputFile, createErr := os.Create(filename)
	if createErr != nil {
		fmt.Println("File creation error:", createErr)
		return
	}
	defer outputFile.Close()

	buffer := make([]byte, 4096)
	for {
		bytesRead, readErr := connection.Read(buffer)
		if readErr != nil {
			if readErr == io.EOF {
				fmt.Println("File reception complete")
			} else {
				fmt.Println("Connection read error:", readErr)
			}
			return
		}
		outputFile.Write(buffer[:bytesRead])
	}
}

func main() {
	listener, listenErr := net.Listen("tcp", "127.0.0.1:8080")
	if listenErr != nil {
		fmt.Println("Listen error:", listenErr)
		return
	}
	defer listener.Close()

	connection, acceptErr := listener.Accept()
	if acceptErr != nil {
		fmt.Println("Accept error:", acceptErr)
		return
	}
	defer connection.Close()

	receiveBuffer := make([]byte, 1024)
	bytesRead, readErr := connection.Read(receiveBuffer)
	if readErr != nil {
		fmt.Println("Read error:", readErr)
		return
	}

	receivedFilename := string(receiveBuffer[:bytesRead])
	connection.Write([]byte("READY"))
	receiveFile(receivedFilename, connection)
}

Workflow:

  1. Create TCP listener on specified address
  2. Accept incoming client connection
  3. Read filename from sender
  4. Send acknowledgment signal
  5. Continuously receive data and write to fille

Transfer Process

The communication follows this sequence:

  1. Sender connnects to receiver on port 8080
  2. Sender transmits the filename
  3. Receiver creates local file with same name
  4. Receiver sends "READY" acknowledgment
  5. Sender streams file contents in 4KB chunks
  6. Receiver writes each chunk to disk until EOF

Both implementations use buffered I/O with 4KB chunks for efficient network transfer. The receiver creates the file with the same name as the original, preserving the filename while the content is copied exact.

Tags: Go tcp Network Programming file transfer Golang

Posted on Tue, 06 Oct 2026 16:07:20 +0000 by NogDog