Golang新手提问:如何使用TCP连接实现客户端与服务端通信
Golang新手提问:如何使用TCP连接实现客户端与服务端通信 大家好,
我是Go语言的新手,正在尝试学习这门语言。以下是我试图编写的程序(服务器和客户端)的说明及代码。这段代码无法正常工作,我正在找出问题所在。
我试图创建一个服务器,能够处理传入的文本并打印,同时它应该能够向客户端发送数据,而客户端既要发送数据也要接收来自服务器的数据,并读取和打印。
但是当我同时运行服务器和客户端代码时,它们虽然运行了,但无法发送和接收任何内容。请您查看我的代码,指出我哪里做错了。
服务器代码如下:
package main
import (
"net"
"fmt"
"time"
"bufio"
"sync"
)
var wg sync.WaitGroup
func main(){
wg.Add(2)
li,err := net.Listen("tcp",":9999")
if err != nil{
panic(err)
}
defer li.Close()
for {
fmt.Println("Requesting for connection...")
conn,error := li.Accept()
fmt.Println("Connection request received from ",conn.RemoteAddr())
if error != nil{
panic(error)
}
fmt.Println("The request for Input")
handleInputClient(conn)
fmt.Println("The request for Output")
handleOutputClient(conn)
wg.Wait()
fmt.Println("The wait group is exiting and main program is closing...")
}
}
func handleOutputClient(conn net.Conn){
go func() {
for {
fmt.Println("This is for the trial…")
fmt.Fprint(conn,"This is for the trial…")
time.Sleep(time.Second * 3)
}
wg.Done()
}()
}
func handleInputClient(conn net.Conn) {
go func() {
fmt.Println("Creating scanner…")
scanner := bufio.NewScanner(conn)
for scanner.Scan(){
str := scanner.Text()
fmt.Println("Scanning data ",str)
fmt.Println(str)
}
wg.Done()
}()
}
========================================================================
客户端代码如下:
package main
import (
"net"
"fmt"
"time"
"sync"
)
var wg sync.WaitGroup
func main(){
wg.Add(1)
conn,err := net.Dial("tcp",":9999")
fmt.Println("The connection is established")
if err != nil{
panic(err)
}
defer conn.Close()
go func() {
fmt.Println("Connection establisted with server ",conn.RemoteAddr())
//connection is established..so first thing client does is introduce itself.
fmt.Fprint(conn, "The connection is established")
fmt.Println("The connection is established")
for {
fmt.Fprint(conn,"Lets keep on talking....")
fmt.Println("Lets keep on talking....")
time.Sleep(time.Second * 3)
}
wg.Done()
}()
wg.Wait()
}
更多关于Golang新手提问:如何使用TCP连接实现客户端与服务端通信的实战教程也可以访问 https://www.itying.com/category-94-b0.html
很好,感谢你的帮助,这解决了我的服务器代码中的一个问题。
更多关于Golang新手提问:如何使用TCP连接实现客户端与服务端通信的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你已经很接近了 😉 只需要做两个小改动:
- 使用 fmt.Fprintln 替代 fmt.Fprint,这样会输出换行符,否则 Scanner.Scan 不会返回
- 客户端也必须有一个读取数据的协程:我直接复制了你服务器中的代码
做得好!
server.go
package main
import (
"bufio"
"fmt"
"net"
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
wg.Add(2)
li, err := net.Listen("tcp", ":9999")
if err != nil {
panic(err)
}
defer li.Close()
for {
fmt.Println("Requesting for connection…")
conn, error := li.Accept()
fmt.Println("Connection request received from ", conn.RemoteAddr())
if error != nil {
panic(error)
}
fmt.Println("The request for Input")
handleInputClient(conn)
fmt.Println("The request for Output")
handleOutputClient(conn)
wg.Wait()
fmt.Println("The wait group is exiting and main program is closing...")
}
}
func handleOutputClient(conn net.Conn) {
go func() {
for {
fmt.Println("This is for the trial…")
// Use Fprintln so line ends with newline (otherwise will Scanner not work)
fmt.Fprintln(conn, "This is for the trial…")
time.Sleep(time.Second * 3)
}
wg.Done()
}()
}
func handleInputClient(conn net.Conn) {
go func() {
fmt.Println("Creating scanner…")
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
str := scanner.Text()
fmt.Println("Scanning data ", str)
fmt.Println(str)
}
wg.Done()
}()
}
client.go
package main
import (
"bufio"
"fmt"
"net"
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
wg.Add(2)
conn, err := net.Dial("tcp", ":9999")
fmt.Println("The connection is established")
if err != nil {
panic(err)
}
defer conn.Close()
go func() {
fmt.Println("Connection establisted with server ", conn.RemoteAddr())
//connection is established..so first thing client does is introduce itself.
fmt.Fprint(conn, "The connection is established")
fmt.Println("The connection is established")
for {
// Use Fprintln so line ends with newline (otherwise will Scanner not work)
fmt.Fprintln(conn, "Lets keep on talking....")
fmt.Println("Lets keep on talking....")
time.Sleep(time.Second * 3)
}
wg.Done()
}()
go func() {
fmt.Println("Creating scanner…")
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
str := scanner.Text()
fmt.Println("Scanning data ", str)
fmt.Println(str)
}
wg.Done()
}()
wg.Wait()
}
你的代码中存在几个关键问题,导致TCP通信无法正常工作。主要问题包括并发控制不当和连接处理逻辑错误。以下是修正后的代码:
服务器端修正代码
package main
import (
"bufio"
"fmt"
"net"
"time"
)
func main() {
li, err := net.Listen("tcp", ":9999")
if err != nil {
panic(err)
}
defer li.Close()
fmt.Println("Server listening on :9999")
for {
conn, err := li.Accept()
if err != nil {
fmt.Println("Accept error:", err)
continue
}
fmt.Printf("Connection established from %s\n", conn.RemoteAddr())
// 为每个连接启动独立的goroutine处理
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
defer conn.Close()
// 启动输出goroutine
go handleOutput(conn)
// 处理输入
handleInput(conn)
}
func handleOutput(conn net.Conn) {
ticker := time.NewTicker(3 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
message := "Server message: " + time.Now().Format("15:04:05")
_, err := fmt.Fprintln(conn, message)
if err != nil {
fmt.Printf("Send error to %s: %v\n", conn.RemoteAddr(), err)
return
}
fmt.Printf("Sent to %s: %s\n", conn.RemoteAddr(), message)
}
}
}
func handleInput(conn net.Conn) {
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
message := scanner.Text()
fmt.Printf("Received from %s: %s\n", conn.RemoteAddr(), message)
}
if err := scanner.Err(); err != nil {
fmt.Printf("Scanner error from %s: %v\n", conn.RemoteAddr(), err)
}
fmt.Printf("Connection closed from %s\n", conn.RemoteAddr())
}
客户端修正代码
package main
import (
"bufio"
"fmt"
"net"
"time"
)
func main() {
conn, err := net.Dial("tcp", "localhost:9999")
if err != nil {
panic(err)
}
defer conn.Close()
fmt.Printf("Connected to server %s\n", conn.RemoteAddr())
// 立即发送初始消息
fmt.Fprintln(conn, "Client connected: Hello Server!")
// 启动接收goroutine
go handleServerMessages(conn)
// 主goroutine处理发送
handleClientOutput(conn)
}
func handleServerMessages(conn net.Conn) {
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
message := scanner.Text()
fmt.Printf("Received from server: %s\n", message)
}
if err := scanner.Err(); err != nil {
fmt.Printf("Server message error: %v\n", err)
}
fmt.Println("Server connection closed")
}
func handleClientOutput(conn net.Conn) {
ticker := time.NewTicker(3 * time.Second)
defer ticker.Stop()
messageCount := 0
for {
select {
case <-ticker.C:
messageCount++
message := fmt.Sprintf("Client message #%d: %s", messageCount, time.Now().Format("15:04:05"))
_, err := fmt.Fprintln(conn, message)
if err != nil {
fmt.Printf("Send error: %v\n", err)
return
}
fmt.Printf("Sent to server: %s\n", message)
}
}
}
主要问题修正说明:
-
移除了WaitGroup的误用:原代码中WaitGroup导致服务器在第一个连接后就阻塞,无法接受新连接。
-
正确的连接处理:为每个客户端连接启动独立的goroutine,避免阻塞主接受循环。
-
改进的消息格式:使用
fmt.Fprintln确保每条消息以换行符结束,这是bufio.Scanner正确工作的前提。 -
独立的输入输出处理:输入和输出在各自的goroutine中运行,不会相互阻塞。
-
错误处理改进:添加了适当的错误处理和连接关闭逻辑。
运行修正后的代码,服务器和客户端将能够正常通信,每3秒相互发送消息并在控制台显示接收到的消息。

