GoLang – TCP Server Example

http://golang.org/

One more concurrent server topic, following to the previous post – EventMachine – UDP Server Example. As I sometimes hear that GoLang (Go Programming Language) is good for concurrent programming, I just tried on the similar logic.

After struggling on the fact that “learning a new language is tough”, I could manage to make the code work as follows (I was looking for some ways to simplify the code, but I gave up…).

Server

% go run server.go
2013/07/17 00:41:23 Completed in 5 second with param = A
2013/07/17 00:41:24 Completed in 5 second with param = B
2013/07/17 00:41:26 Completed in 5 second with param = C
2013/07/17 00:41:31 Completed in 1 second with param = E
2013/07/17 00:41:34 Completed in 5 second with param = D
2013/07/17 00:41:36 Invalid command is specified

Client

% telnet localhost 5000
Trying ::1...
Connected to localhost.
Escape character is '^]'.
LARGE A
LARGE B
LARGE C
Completed in 5 second with param = A
Completed in 5 second with param = B
Completed in 5 second with param = C
LARGE D
SMALL E
Completed in 1 second with param = E
Completed in 5 second with param = D
xxx
Invalid command is specified

SouceCode

package main

import (
  "io"
  "log"
  "net"
  "bytes"
  "bufio"
  "strings"
  "time"
)

type JobInterface interface {
  run() string
}
type Job        struct { param string }
type SmallJob   struct { Job }
type LargeJob   struct { Job }
type InvalidJob struct { Job }

func (job SmallJob) run() string {
  time.Sleep(1 * time.Second)
  return "Completed in 1 second with param = " + job.param
}

func (job LargeJob) run() string {
  time.Sleep(5 * time.Second)
  return "Completed in 5 second with param = " + job.param
}

func (job InvalidJob) run() string {
  return "Invalid command is specified"
}

func job_runner(job JobInterface, out chan string) {
  out <- job.run() + "\n"
}

func job_factory(input string) JobInterface {
  array := strings.Split(input, " ")
  if len(array) >= 2 {
    command := array[0]
    param   := array[1]

    if command == "SMALL" {
      return SmallJob{Job{param}}
    } else if command == "LARGE" {
      return LargeJob{Job{param}}
    }
  }
  return InvalidJob{Job{""}}
}

func request_handler(conn net.Conn, out chan string) {
  defer close(out)

  for {
    line, err := bufio.NewReader(conn).ReadBytes('\n')
    if err != nil { return }

    job := job_factory(strings.TrimRight(string(line), "\n"))
    go job_runner(job, out)
  }
}

func send_data(conn net.Conn, in <-chan string) {
  defer conn.Close()

  for {
    message := <- in
    log.Print(message)
    io.Copy(conn, bytes.NewBufferString(message))
  }
}

func main() {
  psock, err := net.Listen("tcp", ":5000")
  if err != nil { return }

  for {
    conn, err := psock.Accept()
    if err != nil { return }

    channel := make(chan string)
    go request_handler(conn, channel)
    go send_data(conn, channel)
  }
}

‘Personal’ Impression

The language is interesting, but there’re some good/bad parts. Actually, I haven’t been able to find the good spot to use this language yet. It would be more concise than Java/C++, but not sure if the good parts are large enough to switch from script languages like JavaScript or Ruby.

  • Good
    • Rigid static analysis of codes, which catches many errors at the beginning. For example, if the imported package or defined variables is never used, it throws an error (rather than warning).
    • Fast compile time. It’s fast enough to start executing, which may be comparable to script languages (not the same, but good enough).
    • Concept of asynchronous/concurrent execution is interesting, and built-in features (go/channel/defer) would work nicely once we get the concept.
  • Bad
    • Though basic language concept is similar as standard C++/Java based language, there’re too many small differences (keywords, statements, etc.). It may be better than Objective-C, but may not be enough to get accustomed to it easily.
    • Object Oriented Programming is supported (GoLang Tutorials), and inheritance/polymorphism can be applied. However, the separation between data (struct) and methods makes me feel like it’s not fully integrated. For example, JavaScript doesn’t have class concept, but it can be defined like class (variable and methods) through some idioms (or use CoffeeScript).
    • In the if/else statement “} else if”, putting line-break between “}” and “else” throws “unexpected semicolon or newline before else” error. I personally don’t like this style.
Advertisements

Posted on July 18, 2013, in GoLang, Software Design, Web. Bookmark the permalink. 2 Comments.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: