go mod init example-quic
go get github.com/quic-go/quic-go
go run server.go
go run client.go
| // server.go | |
| package main | |
| import ( | |
| "context" | |
| "crypto/tls" | |
| "fmt" | |
| "io" | |
| "log" | |
| "github.com/quic-go/quic-go" | |
| ) | |
| const ( | |
| addr = "127.0.0.1:4242" | |
| alpn = "example-quic" | |
| certF = "cert.pem" | |
| keyF = "key.pem" | |
| ) | |
| func main() { | |
| tlsConf := &tls.Config{ | |
| Certificates: []tls.Certificate{mustLoadTLS(certF, keyF)}, | |
| NextProtos: []string{alpn}, | |
| } | |
| ln, err := quic.ListenAddr(addr, tlsConf, nil) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| log.Println("QUIC server listening on", addr) | |
| for { | |
| conn, err := ln.Accept(context.Background()) // *quic.Conn | |
| if err != nil { | |
| log.Println("accept conn:", err) | |
| continue | |
| } | |
| go handleConn(conn) | |
| } | |
| } | |
| func handleConn(conn *quic.Conn) { | |
| log.Println("new conn from", conn.RemoteAddr()) | |
| for { | |
| st, err := conn.AcceptStream(context.Background()) // *quic.Stream | |
| if err != nil { | |
| log.Println("accept stream:", err) | |
| return | |
| } | |
| go handleStream(st) | |
| } | |
| } | |
| func handleStream(st *quic.Stream) { | |
| defer st.Close() | |
| buf := make([]byte, 4096) | |
| n, err := st.Read(buf) | |
| if err != nil && err != io.EOF { | |
| log.Println("read:", err) | |
| return | |
| } | |
| msg := string(buf[:n]) | |
| log.Println("received:", msg) | |
| if _, err := st.Write([]byte("echo: " + msg)); err != nil { | |
| log.Println("write:", err) | |
| } | |
| } | |
| func mustLoadTLS(certFile, keyFile string) tls.Certificate { | |
| c, err := tls.LoadX509KeyPair(certFile, keyFile) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| return c | |
| } |
| // client.go | |
| package main | |
| import ( | |
| "context" | |
| "crypto/tls" | |
| "fmt" | |
| "io" | |
| "log" | |
| "time" | |
| "github.com/quic-go/quic-go" | |
| ) | |
| const ( | |
| addr = "127.0.0.1:4242" | |
| alpn = "example-quic" | |
| ) | |
| func main() { | |
| ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) | |
| defer cancel() | |
| tlsConf := &tls.Config{ | |
| InsecureSkipVerify: true, // テスト用途 | |
| NextProtos: []string{alpn}, | |
| } | |
| conn, err := quic.DialAddr(ctx, addr, tlsConf, nil) // *quic.Conn | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| defer conn.CloseWithError(0, "done") | |
| st, err := conn.OpenStreamSync(ctx) // *quic.Stream | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| if _, err := st.Write([]byte("hello over quic")); err != nil { | |
| log.Fatal(err) | |
| } | |
| buf := make([]byte, 4096) | |
| n, err := st.Read(buf) | |
| if err != nil && err != io.EOF { | |
| log.Fatal(err) | |
| } | |
| fmt.Println(string(buf[:n])) | |
| } |