Skip to content

Instantly share code, notes, and snippets.

@jreisinger
Created September 7, 2023 07:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jreisinger/37c7524f220a161f0819749ff1968dae to your computer and use it in GitHub Desktop.
Save jreisinger/37c7524f220a161f0819749ff1968dae to your computer and use it in GitHub Desktop.
// Chat is a TCP server that connects couples so they can talk.
// Adapted from https://go.dev/talks/2012/chat.slide
package main
import (
"fmt"
"io"
"log"
"net"
)
const addr = ":1234"
func main() {
ln, err := net.Listen("tcp", addr)
if err != nil {
log.Fatal(err)
}
for {
conn, err := ln.Accept()
if err != nil {
log.Print(err)
continue
}
go match(conn)
}
}
var partner = make(chan io.ReadWriteCloser)
// match simultaneously tries to send and receive a connection on a channel.
func match(conn net.Conn) {
log.Printf("connection from %s", conn.RemoteAddr())
fmt.Fprint(conn, "Waiting for a partner...")
select {
case partner <- conn:
// now handled by the other goroutine
case p := <-partner:
// start chat session between the two connections
chat(p, conn)
}
}
// chat copies data between the two connections.
func chat(a, b io.ReadWriteCloser) {
fmt.Fprintln(a, "Found one! Say hi.")
fmt.Fprintln(b, "Found one! Say hi.")
errc := make(chan error, 1)
go cp(a, b, errc)
go cp(b, a, errc)
if err := <-errc; err != nil {
log.Print(err)
}
a.Close()
b.Close()
}
// cp copies data with error handling.
func cp(w io.Writer, r io.Reader, errc chan<- error) {
_, err := io.Copy(w, r)
errc <- err
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment