Golang模拟多路并发TCP服务器连接
Golang模拟多路并发TCP服务器连接 我需要测试一个TCP服务器是否能正确处理多个客户端连接。
是否可以使用goroutine像这样?
func SendMsg(msg string) {
conn, _ := net.Dial("tcp", ":1123")
conn.Write([]byte(msg))
conn.Close()
}
for i := 0; i < 50; i++ {
go SendMsg("test")
}
当我尝试类似这样的代码时,程序会发生panic。
此致
5 回复
Go: panic: runtime error: invalid memory address or nil pointer dereference
Norbert 比我先说了:听起来你的连接是 nil,就像这里:https://play.golang.org/p/mJSIcJLDpTD。移除 return 就会引发 panic。
func main() {
var conn net.Conn
conn.Write([]byte("data"))
}
或许应该检查一下net.Dial返回的err,它被返回是有原因的…
// 代码示例
func main() {
conn, err := net.Dial("tcp", "golang.org:80")
if err != nil {
// 处理错误
}
// 使用连接
}
在Go中模拟多路并发TCP服务器连接是可行的,但你的代码存在几个关键问题。主要问题是没有正确处理连接建立失败和并发同步。
以下是修复后的完整示例:
package main
import (
"fmt"
"net"
"sync"
"time"
)
func SendMsg(msg string, wg *sync.WaitGroup) {
defer wg.Done()
conn, err := net.Dial("tcp", "localhost:1123")
if err != nil {
fmt.Printf("连接失败: %v\n", err)
return
}
defer conn.Close()
_, err = conn.Write([]byte(msg))
if err != nil {
fmt.Printf("发送失败: %v\n", err)
return
}
// 可选:读取服务器响应
buffer := make([]byte, 1024)
conn.SetReadDeadline(time.Now().Add(2 * time.Second))
n, err := conn.Read(buffer)
if err != nil {
fmt.Printf("读取响应失败: %v\n", err)
return
}
fmt.Printf("收到响应: %s\n", string(buffer[:n]))
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 50; i++ {
wg.Add(1)
go SendMsg(fmt.Sprintf("test-%d", i), &wg)
}
wg.Wait()
fmt.Println("所有客户端连接完成")
}
关键改进:
- 错误处理:必须检查
net.Dial和conn.Write的返回值 - 连接管理:使用
defer conn.Close()确保连接正确关闭 - 并发同步:使用
sync.WaitGroup等待所有goroutine完成 - 超时控制:为读取操作设置超时,避免阻塞
对应的简单TCP服务器示例:
package main
import (
"fmt"
"net"
)
func handleConnection(conn net.Conn) {
defer conn.Close()
buffer := make([]byte, 1024)
n, err := conn.Read(buffer)
if err != nil {
fmt.Printf("读取错误: %v\n", err)
return
}
msg := string(buffer[:n])
fmt.Printf("收到消息: %s\n", msg)
// 回显消息
response := fmt.Sprintf("ECHO: %s", msg)
conn.Write([]byte(response))
}
func main() {
listener, err := net.Listen("tcp", ":1123")
if err != nil {
panic(err)
}
defer listener.Close()
fmt.Println("服务器启动,监听端口 1123")
for {
conn, err := listener.Accept()
if err != nil {
fmt.Printf("接受连接错误: %v\n", err)
continue
}
go handleConnection(conn)
}
}
这个实现能够正确处理50个并发客户端连接,每个连接发送消息并接收服务器响应。确保先启动服务器,再运行客户端测试代码。


