Documentation
¶
Overview ¶
Package network implements a communication layer with a server and a client. Clients can connect to servers and receive and send messages. Depending on the implementation, communication may differ.
srv := network.NewTCPServer(zerolog.Nop()) // or any other available server
srv.OnConnect(handleConnection)
if err := srv.Open(":3900"); err != nil {
panic(err)
}
In the above example, handleConnection is a func that accepts a network.Conn as parameter. Do with this connection what you'd like. The connections have an ID.
func handleConnection(conn network.Conn) {
loginMsg, err := conn.Receive() // receive a message
// handle loginMsg and err
// create loginResponse
err = conn.Send(loginResponse) // send a message
// handle err
connectionPool.Add(conn) // remember the connection for further use
}
To connect to the above server, do as follows.
conn, err := network.DialTCP(":3900") // or any other available dial method
// handle err
defer conn.Close()
err = conn.Send(loginMsg) // send a message
// handle err
loginResponse, err := conn.Receive() // receive a message
Please note, that the dial functions will only work with the respective server, e.g. DialTCP will only work on TCPServers.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Conn ¶
type Conn interface {
io.Closer
// ID returns the ID of this connection. It can be used to uniquely identify
// this connection globally.
ID() ID
// Send sends the given payload to the remote part of this connection. The
// message will not be chunked, and can be read with a single call to
// Conn.Receive.
Send(context.Context, []byte) error
// Receive reads a whole message and returns it in a byte slice. A message
// is a byte slice that was sent with a single call to Conn.Send.
Receive(context.Context) ([]byte, error)
}
Conn describes a network connection. One can send a message with Conn.Send, and receive one with Conn.Receive. Unlike an io.Writer, the data that is passed into Send is guaranteed to be returned in a single Receive call on the other end, meaning that you don't have to worry about where your messages end. Maximum message length is 2GiB.
type ConnHandler ¶
type ConnHandler func(Conn)
ConnHandler is a handler function for handling new connections. It will be called with a fully initialized Conn, and is used as a callback in the server.
type Error ¶
type Error string
Error is a helper type for creating constant errors.
const ( // ErrOpen indicates, that the component was already opened, and it is // unable to be opened another time. ErrOpen Error = "already open" // ErrClosed indicates, that the component is already closed, and it cannot // be used anymore. ErrClosed Error = "already closed" // ErrTimeout indicates, that a the operation took longer than allowed. // Maybe there was a deadline from a context. ErrTimeout Error = "timeout" )
type ID ¶
ID describes an identifier that is used for connections. An ID has to be unique application-wide. IDs must not be re-used.
type Server ¶
type Server interface {
io.Closer
// Open opens the server on the given address. To make the server choose a
// random free port for you, specify a port ":0".
Open(string) error
// Listening can be used to get a signal when the server has allocated a
// port and is now actively listening for incoming connections.
Listening() <-chan struct{}
// Addr returns the address that this server is listening to.
Addr() net.Addr
// OnConnect sets a callback that will be executed whenever a new connection
// connects to this server.
OnConnect(ConnHandler)
}
Server describes a server component, that listens for connecting clients. Before opening, it is recommended that one sets a connect handler with Server.OnConnect. A server can only be opened once. Closing a server must not close the accepted connections, but must only stop accepting new connections and release the allocated address.
Example ¶
package main
import (
"context"
"fmt"
"log"
"github.com/TimSatke/add/internal/network"
"github.com/rs/zerolog"
)
func main() {
// When using, please don't ignore all the errors as we do here.
ctx := context.Background()
srv := network.NewTCPServer(zerolog.Nop()) // or whatever server is available
srv.OnConnect(func(conn network.Conn) {
_ = conn.Send(ctx, []byte("Hello, World!"))
})
go func() {
if err := srv.Open(":59513"); err != nil {
log.Fatal(err)
}
}()
<-srv.Listening() // wait for the server to come up
client, _ := network.DialTCP(ctx, ":59513")
defer func() {
_ = client.Close()
}()
received, _ := client.Receive(ctx)
fmt.Println(string(received))
}
Output: Hello, World!
func NewTCPServer ¶
NewTCPServer creates a new ready to use TCP server that uses the given logger.