Go: Reversing TCP Server

Implement a TCP server that accepts messages in the form of a string. Reverse the messages and return them to the client.

The stub function accepts an array of strings, messages, runs the server, waits for it to be ready, then sends the messages one by one to the server and prints responses. The server address is given in the constant address along with maxBufferSize for reading/writing purposes.

Example

messages= [“adi”, “glm”, “tuv”]

The TCP server should respond with [“ida”,”mlg”,”vut”].

Function Description

Complete the function TCPServer in the editor below.

TCPServer has the following parameter:

    bool ready:  a channel that indicates whether the server is ready

Returns

    None:   all responses should be read from the TCP connection initiated by a TCP client 

Constraints

  • The total number of messages does not exceed 500.
  • Each message contains a maximum of 1000 lower case English letters only.

SOLUTION:

				
					package main

import (
    "bufio"
    "fmt"
    "io"
    "net"
    "os"
    "strconv"
    "strings"
)

/*
 * Complete the 'TCPServer' function below.
 *
 * The function accepts chan bool ready as a parameter.
 */

func TCPServer(ready chan bool) {
    ln, err := net.Listen("tcp", address)
    if err != nil {
        panic(err)
    }
    defer ln.Close()

    ready <- true

    for {
        conn, err := ln.Accept()
        if err != nil {
            continue
        }
        go handleConnection(conn)
    }
}

func handleConnection(conn net.Conn) {
    defer conn.Close()

    buffer := make([]byte, maxBufferSize)
    n, err := conn.Read(buffer)
    if err != nil {
        return
    }
    message := string(buffer[:n])
    reversed := reverseString(message)
    conn.Write([]byte(reversed))
}

func reverseString(s string) string {
    runes := []rune(s)
    for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
        runes[i], runes[j] = runes[j], runes[i]
    }
    return string(runes)
}

const maxBufferSize = 1024
const address = "127.0.0.1:3333"

func main() {
    stdout, err := os.Create(os.Getenv("OUTPUT_PATH"))
    checkError(err)

    defer stdout.Close()

    reader := bufio.NewReaderSize(os.Stdin, 16*1024*1024)
    writer := bufio.NewWriterSize(stdout, 16*1024*1024)

    messagesCount, err := strconv.ParseInt(strings.TrimSpace(readLine(reader)), 10, 64)
    checkError(err)

    var messages []string

    for i := 0; i < int(messagesCount); i++ {
        messagesItem := readLine(reader)
        messages = append(messages, messagesItem)
    }

    ready := make(chan bool)
    go TCPServer(ready)
    <-ready
    reversed, err := tcpClient(messages)
    if err != nil {
        panic(err)
    }
    for _, msg := range reversed {
        fmt.Fprintf(writer, "%s\n", msg)
    }
    writer.Flush()
}

func readLine(reader *bufio.Reader) string {
    str, _, err := reader.ReadLine()
    if err == io.EOF {
        return ""
    }

    return strings.TrimRight(string(str), "\r\n")
}

func checkError(err error) {
    if err != nil {
        panic(err)
    }
}

func tcpClient(messages []string) ([]string, error) {
    tcpAddr, err := net.ResolveTCPAddr("tcp", address)
    if err != nil {
        return []string{}, err
    }

    reversed := []string{}

    for _, msg := range messages {

        conn, err := net.DialTCP("tcp", nil, tcpAddr)
        if err != nil {
            return []string{}, err
        }
        _, err = conn.Write([]byte(msg))
        if err != nil {
            return []string{}, err
        }

        reply := make([]byte, maxBufferSize)

        n, err := conn.Read(reply)
        if err != nil {
            return []string{}, err
        }

        reversed = append(reversed, string(reply[:n]))
        conn.Close()
    }

    return reversed, nil
}