- go-hua/log 已弃用: *log.Logger 参数改为两方法接口 spmux.Logger (*logrus.Logger 天然满足), 传 nil 静默(logErrorf/logDebugf 判空) - 协议识别改用 zogo/httpprobe; 测试与例程同步适配 - 附测试、examples/spmux 例程(含 Logger 适配演示)与包 README
90 lines
2.1 KiB
Go
90 lines
2.1 KiB
Go
// spmux 包示例:单端口多路复用——同一端口上按报文特征把流量分发给 HTTP / HTTPS / TCP 三个 Listener
|
||
package main
|
||
|
||
import (
|
||
"bufio"
|
||
"fmt"
|
||
"io"
|
||
"log"
|
||
"net"
|
||
"net/http"
|
||
"os"
|
||
"time"
|
||
|
||
"git.zeroonesoft.cn/golib/zogo/spmux"
|
||
)
|
||
|
||
// stdoutLogger 适配 spmux.Logger 接口(*logrus.Logger 天然满足,无需适配)
|
||
type stdoutLogger struct{}
|
||
|
||
func (stdoutLogger) Debugf(format string, a ...any) { log.Printf("DEBUG "+format, a...) }
|
||
func (stdoutLogger) Errorf(format string, a ...any) { log.Printf("ERROR "+format, a...) }
|
||
|
||
func main() {
|
||
// 找一个空闲端口
|
||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
port := l.Addr().(*net.TCPAddr).Port
|
||
l.Close()
|
||
|
||
// 创建端口复用器(logger 实现 spmux.Logger 即可,也可传 nil 静默)
|
||
pm := spmux.NewPortMux(port, stdoutLogger{})
|
||
if err := pm.Start(); err != nil {
|
||
panic(err)
|
||
}
|
||
|
||
// HTTP 流量交给 HttpListener
|
||
go http.Serve(pm.HttpListener(), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
fmt.Fprintln(w, "hello from http over spmux")
|
||
}))
|
||
|
||
// 其他 TCP 流量交给 TcpListener(echo 服务,回显内容并补换行)
|
||
tcpL := pm.TcpListener()
|
||
go func() {
|
||
for {
|
||
c, err := tcpL.Accept()
|
||
if err != nil {
|
||
return
|
||
}
|
||
go func(cc net.Conn) {
|
||
defer cc.Close()
|
||
buf := make([]byte, 1024)
|
||
for {
|
||
n, err := cc.Read(buf)
|
||
if n > 0 {
|
||
cc.Write(append(buf[:n:n], '\n'))
|
||
}
|
||
if err != nil {
|
||
return
|
||
}
|
||
}
|
||
}(c)
|
||
}
|
||
}()
|
||
|
||
time.Sleep(100 * time.Millisecond)
|
||
|
||
// HTTP 请求会被识别并路由到 HttpListener
|
||
resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/", port))
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
body, _ := io.ReadAll(resp.Body)
|
||
resp.Body.Close()
|
||
fmt.Print("HTTP 响应:", string(body))
|
||
|
||
// 普通数据会被路由到 TcpListener
|
||
raw, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", port))
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
fmt.Fprint(raw, "ping")
|
||
line, _ := bufio.NewReader(raw).ReadString('\n')
|
||
fmt.Print("TCP 响应:", line)
|
||
raw.Close()
|
||
|
||
_ = os.Stdout
|
||
}
|