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

3 回复

很好,感谢你的帮助,这解决了我的服务器代码中的一个问题。

更多关于Golang新手提问:如何使用TCP连接实现客户端与服务端通信的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你已经很接近了 😉 只需要做两个小改动:

  1. 使用 fmt.Fprintln 替代 fmt.Fprint,这样会输出换行符,否则 Scanner.Scan 不会返回
  2. 客户端也必须有一个读取数据的协程:我直接复制了你服务器中的代码

做得好!

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)
        }
    }
}

主要问题修正说明:

  1. 移除了WaitGroup的误用:原代码中WaitGroup导致服务器在第一个连接后就阻塞,无法接受新连接。

  2. 正确的连接处理:为每个客户端连接启动独立的goroutine,避免阻塞主接受循环。

  3. 改进的消息格式:使用fmt.Fprintln确保每条消息以换行符结束,这是bufio.Scanner正确工作的前提。

  4. 独立的输入输出处理:输入和输出在各自的goroutine中运行,不会相互阻塞。

  5. 错误处理改进:添加了适当的错误处理和连接关闭逻辑。

运行修正后的代码,服务器和客户端将能够正常通信,每3秒相互发送消息并在控制台显示接收到的消息。

回到顶部