从没代码到能跑起来的完整 TCP 网络程序,麻雀虽小五脏俱全。client-server 模型、goroutine 并发、消息广播,Go 网络编程最核心的东西都在里面了。
gopackage main
import (
"bufio"
"fmt"
"net"
"sync"
)
var (
clients = make(map[net.Conn]bool, 1000)
mu sync.Mutex
)
func main() {
listener, err := net.Listen("tcp", ":9999")
if err != nil {
panic(err.Error())
}
defer listener.Close()
for {
conn, _ := listener.Accept()
go handleconn(conn)
}
}
func handleconn(conn net.Conn) {
defer conn.Close()
mu.Lock()
clients[conn] = true
mu.Unlock()
broadcast(conn, fmt.Sprintf("New Friend Join,Now All People Num: %d", len(clients)))
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
msg := scanner.Text()
if scanner.Err() != nil {
fmt.Println(scanner.Err().Error())
break
}
if msg == `\q` {
break
}
broadcast(conn, msg)
}
broadcast(conn, "A Frend Left.")
}
func broadcast(sender net.Conn, msg string) {
mu.Lock()
defer mu.Unlock()
for client := range clients {
if client != sender {
fmt.Fprintln(client, msg)
}
}
}
```go
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
conn, _ := net.Dial("tcp", ":9999")
defer conn.Close()
go func() {
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
if scanner.Err() != nil {
fmt.Println(scanner.Err().Error())
break
}
msg := scanner.Text()
fmt.Printf("Message:%s\n", msg)
}
}()
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
if scanner.Err() != nil {
fmt.Println(scanner.Err().Error())
break
}
text := scanner.Text()
if strings.TrimSpace(text) == `\q` {
fmt.Println("Out!")
break
}
_, err := fmt.Fprintln(conn, text)
if err != nil {
fmt.Println("send message error", err.Error())
break
}
}
}