Golang中TCP连接 - 每次发送消息前需要重新拨号的问题
Golang中TCP连接 - 每次发送消息前需要重新拨号的问题 我需要一个能够来回交换消息的客户端和服务器。
目前,客户端进行拨号并发送问候信息。 服务器接受连接并回复3次。
客户端只听到第一个回复,然后似乎没有收到另外两个,除非服务器在发送这些消息之前也向客户端拨号。
TCP 应该是这样工作的吗? 如果不是,为什么客户端只接受一条消息?
终端输出… (服务器) 已听到 2022/03/21 01:43:16 新客户端 正在拨号 正在发送消息 正在发送第二条消息 正在发送第三条消息
(客户端) 接受前 已接受 127.0.0.1:53047 接受后 接受前 2022/03/21 01:43:20 收到: 消息
代码… 服务器
package main
import (
"log"
"net"
"time"
"fmt"
)
var rc net.Conn
func main() {
ln, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatal(err)
}
for {
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
defer conn.Close()
rc = conn
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
log.Fatal(err)
}
fmt.Println("heard")
log.Println(time.Now())
fmt.Println("newClient")
time.Sleep(time.Second * 2)
fmt.Println("Dialing")
conn2, err := net.Dial("tcp", "127.0.0.1:8081")
if err != nil {
log.Fatal(err)
}
fmt.Println("sending msg")
conn2.Write([]byte("msg"))
time.Sleep(time.Second * 2)
fmt.Println("sending 2nd msg")
conn2.Write([]byte("msg2"))
time.Sleep(time.Second * 2)
fmt.Println("sending 3rd msg")
conn2.Write([]byte("msg3"))
}
客户端
package main
import (
"net"
"log"
)
func main() {
ln, err := net.Listen("tcp", ":8081")
if err != nil {
log.Fatal(err)
}
for {
fmt.Println("preAccept")
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
fmt.Println("accepted", conn.RemoteAddr())
fmt.Println("postAccept")
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
defer conn.Close()
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
log.Fatal(err)
}
log.Println("rcv:", string(buf[:n]))
}
更多关于Golang中TCP连接 - 每次发送消息前需要重新拨号的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我通过让客户端监听拨号连接来接收消息,而不是使用它自己的监听函数,从而解决了这个问题。
更多关于Golang中TCP连接 - 每次发送消息前需要重新拨号的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
buf := make([]byte, 1024)
n, _ := c.Read(buf)
got := string(buf[:n])
log.Print("rcv: "+got)
return
}
问题在于 handleMessage 只从每个连接读取单条消息。
你需要类似这样的代码:
func handleMessage(c net.Conn){
buf := make([]byte, 1024)
for {
n, err := c.Read(buf)
if err != nil {
break
}
log.Print("rcv: %s ", buf[:n])
}
c.Close()
}
但是,当然,TCP/IP 是一种流式协议。 因此接收到的消息边界可能与发送时的边界不同。
你的代码存在几个关键问题导致客户端只收到第一条消息:
- 服务器端错误地建立了新连接:服务器在收到客户端连接后,又主动向客户端建立了一个新连接(
net.Dial),这创建了完全独立的TCP连接。 - 客户端只读取一次:客户端的
handleConnection函数只调用一次conn.Read(),读取一次后就退出了。
这是修复后的代码:
服务器端:
package main
import (
"fmt"
"log"
"net"
"time"
)
func main() {
ln, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatal(err)
}
defer ln.Close()
for {
conn, err := ln.Acept()
if err != nil {
log.Println("Accept error:", err)
continue
}
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
defer conn.Close()
// 读取客户端问候
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
log.Println("Read error:", err)
return
}
fmt.Printf("Heard: %s\n", string(buf[:n]))
log.Println(time.Now())
fmt.Println("New client connected")
// 使用同一个连接发送回复
time.Sleep(time.Second * 2)
fmt.Println("Sending 1st message")
conn.Write([]byte("Message 1\n"))
time.Sleep(time.Second * 2)
fmt.Println("Sending 2nd message")
conn.Write([]byte("Message 2\n"))
time.Sleep(time.Second * 2)
fmt.Println("Sending 3rd message")
conn.Write([]byte("Message 3\n"))
}
客户端:
package main
import (
"fmt"
"log"
"net"
"time"
)
func main() {
// 连接到服务器
conn, err := net.Dial("tcp", "127.0.0.1:8080")
if err != nil {
log.Fatal("Dial error:", err)
}
defer conn.Close()
// 发送问候
fmt.Println("Sending greeting to server")
conn.Write([]byte("Hello Server\n"))
// 持续读取服务器回复
buf := make([]byte, 1024)
for i := 0; i < 3; i++ {
n, err := conn.Read(buf)
if err != nil {
log.Println("Read error:", err)
return
}
log.Printf("Received: %s", string(buf[:n]))
}
// 或者使用无限循环读取所有消息
// for {
// n, err := conn.Read(buf)
// if err != nil {
// log.Println("Connection closed:", err)
// return
// }
// log.Printf("Received: %s", string(buf[:n]))
// }
}
关键修改说明:
-
服务器端:
- 移除了
net.Dial调用,使用ln.Accept()接受的同一个连接发送所有消息 - 直接使用
conn.Write()在原始连接上发送数据
- 移除了
-
客户端:
- 改为主动连接到服务器(
net.Dial) - 使用循环读取多次消息,而不是只读取一次
- 移除了监听端口的代码,因为现在它是TCP客户端
- 改为主动连接到服务器(
TCP连接的工作方式:
- TCP连接是全双工的,一旦建立,双方都可以通过同一个连接发送和接收数据
- 不需要为每条消息重新建立连接
- 连接保持打开状态直到显式关闭或发生错误
这样修改后,客户端将能正确接收所有三条消息,因为它们在同一个TCP连接上传输。

