-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Will Gough
committed
Jul 10, 2018
0 parents
commit f7c8c99
Showing
3 changed files
with
172 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package net | ||
|
||
import ( | ||
"bufio" | ||
"errors" | ||
"fmt" | ||
"net" | ||
"strings" | ||
) | ||
|
||
// Server defines the minimum contract our | ||
// TCP and UDP server implementations must satisfy. | ||
type Server interface { | ||
Run() error | ||
Close() error | ||
} | ||
|
||
// NewServer creates a new Server using given protocol | ||
// and addr. | ||
func NewServer(protocol, addr string) (Server, error) { | ||
switch strings.ToLower(protocol) { | ||
case "tcp": | ||
return &TCPServer{ | ||
addr: addr, | ||
}, nil | ||
case "udp": | ||
} | ||
return nil, errors.New("Invalid protocol given") | ||
} | ||
|
||
// TCPServer holds the structure of our TCP | ||
// implementation. | ||
type TCPServer struct { | ||
addr string | ||
server net.Listener | ||
} | ||
|
||
// Run starts the TCP Server. | ||
func (t *TCPServer) Run() (err error) { | ||
t.server, err = net.Listen("tcp", t.addr) | ||
if err != nil { | ||
return err | ||
} | ||
defer t.Close() | ||
|
||
for { | ||
conn, err := t.server.Accept() | ||
if err != nil { | ||
err = errors.New("could not accept connection") | ||
break | ||
} | ||
if conn == nil { | ||
err = errors.New("could not create connection") | ||
break | ||
} | ||
return t.handleConnections() | ||
} | ||
return | ||
} | ||
|
||
// Close shuts down the TCP Server | ||
func (t *TCPServer) Close() (err error) { | ||
return t.server.Close() | ||
} | ||
|
||
// handleConnections is used to accept connections on | ||
// the TCPServer and handle each of them in separate | ||
// goroutines. | ||
func (t *TCPServer) handleConnections() (err error) { | ||
for { | ||
conn, err := t.server.Accept() | ||
if err != nil || conn == nil { | ||
err = errors.New("could not accept connection") | ||
break | ||
} | ||
|
||
go t.handleConnection(conn) | ||
} | ||
return | ||
} | ||
|
||
// handleConnections deals with the business logic of | ||
// each connection and their requests. | ||
func (t *TCPServer) handleConnection(conn net.Conn) { | ||
defer conn.Close() | ||
|
||
rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) | ||
for { | ||
req, err := rw.ReadString('\n') | ||
if err != nil { | ||
rw.WriteString("failed to read input") | ||
rw.Flush() | ||
return | ||
} | ||
|
||
rw.WriteString(fmt.Sprintf("Request received: %s", req)) | ||
rw.Flush() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package net | ||
|
||
import ( | ||
"bytes" | ||
"log" | ||
"net" | ||
"testing" | ||
) | ||
|
||
var srv Server | ||
|
||
func init() { | ||
// Start the new server | ||
srv, err := NewServer("tcp", ":1123") | ||
if err != nil { | ||
log.Println("error starting TCP server") | ||
return | ||
} | ||
|
||
// Run the server in goroutine to stop blocking | ||
go func() { | ||
srv.Run() | ||
}() | ||
} | ||
|
||
func TestNETServer_Running(t *testing.T) { | ||
// Simply check that the server is up and can | ||
// accept connections. | ||
conn, err := net.Dial("tcp", ":1123") | ||
if err != nil { | ||
t.Error("could not connect to server: ", err) | ||
} | ||
defer conn.Close() | ||
} | ||
|
||
func TestNETServer_Request(t *testing.T) { | ||
tt := []struct { | ||
test string | ||
payload []byte | ||
want []byte | ||
}{ | ||
{"Sending a simple request returns result", []byte("hello world\n"), []byte("Request received: hello world")}, | ||
{"Sending another simple request works", []byte("goodbye world\n"), []byte("Request received: goodbye world")}, | ||
} | ||
|
||
for _, tc := range tt { | ||
t.Run(tc.test, func(t *testing.T) { | ||
conn, err := net.Dial("tcp", ":1123") | ||
if err != nil { | ||
t.Error("could not connect to TCP server: ", err) | ||
} | ||
defer conn.Close() | ||
|
||
if _, err := conn.Write(tc.payload); err != nil { | ||
t.Error("could not write payload to TCP server:", err) | ||
} | ||
|
||
out := make([]byte, 1024) | ||
if _, err := conn.Read(out); err == nil { | ||
if bytes.Compare(out, tc.want) == 0 { | ||
t.Error("response did match expected output") | ||
} | ||
} else { | ||
t.Error("could not read from connection") | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
### DevTheWeb Post Source Code | ||
|
||
This repository holds all the source code for the posts and examples given on my personal site: [devtheweb.io](https://devtheweb.io). | ||
|
||
To find the code you want, simply find the date of the post you're looking at and navigate through the subfolders: `year/month/subject`. |