Go:创建TCP服务器和客户端

2023-08-10 15:20:20 浏览数 (1)

TCP(Transmission Control Protocol)是一种面向连接的、可靠的、字节流的传输层通信协议,它在互联网协议(IP)之上提供了一种可靠的数据传输方式。在我们的日常编程任务中,可能会需要使用TCP来实现各种通信需求。在本文中,我们将深入探讨在Go语言中使用TCP通信,给出完整的服务端和客户端的示例。

TCP通信原理

在开始编程之前,我们先简单了解一下TCP的工作原理。TCP通信包括三个步骤:建立连接、数据传输和断开连接。当两台机器想通过TCP进行通信时,它们首先需要建立一个连接,然后才能开始数据传输。数据传输完毕后,连接就可以断开。

Go中的TCP服务器

我们先来看看如何在Go中创建一个TCP服务器。以下是一个简单的TCP服务器示例:

代码语言:javascript复制
package main

import (
    "bufio"
    "fmt"
    "net"
    "strings"
)

func main() {
    fmt.Println("Launching server...")
    ln, _ := net.Listen("tcp", ":8081") //监听在8081端口
    defer ln.Close()

    for {
        conn, _ := ln.Accept() //接受连接
        go handleConnection(conn) //处理连接
    }
}

func handleConnection(conn net.Conn) {
    message, _ := bufio.NewReader(conn).ReadString('n')
    fmt.Print("Message Received:", string(message))
    conn.Write([]byte("Message Received: "   strings.ToUpper(message))) // 发送回应信息
    conn.Close() // 关闭连接
}

在这个示例中,我们创建了一个在端口8081监听的TCP服务器。每当有新的连接被接受时,我们就会创建一个新的goroutine来处理该连接。处理函数会读取客户端发送的消息,然后回应一条信息给客户端,最后关闭连接。

Go中的TCP客户端

接下来我们来看看如何在Go中创建一个TCP客户端。以下是一个简单的TCP客户端示例:

代码语言:javascript复制
package main

import (
    "bufio"
    "fmt"
    "net"
    "os"
)

func main() {
    conn, _ := net.Dial("tcp", "localhost:8081") //连接到服务器
    defer conn.Close()

    reader := bufio.NewReader(os.Stdin) // 从标准输入读取数据
    fmt.Print("Text to send: ")
    text, _ := reader.ReadString('n')

    fmt.Fprintf(conn, text   "n") // 发送数据到服务器
    message, _ := bufio.NewReader(conn).ReadString('n') // 读取服务器的回应信息
    fmt.Print("Message from server: " message)
}

在这个示例中,我们创建了一个连接到上述服务器的TCP客户端。客户端从标准输入读取一行文本,然后发送给服务器。然后,客户端读取并打印出服务器的回应信息。

bufio.Reader.ReadString 方法

上面的示例用到了bufio.Reader.ReadString()方法,这里补充介绍一下,bufio.Reader.ReadString是Go标准库中的一个方法,用于从输入中读取字符串,直到遇到指定的分隔符。其函数签名如下:

代码语言:javascript复制
func (r *Reader) ReadString(delim byte) (string, error)

这个方法会从Reader的输入中读取数据,直到遇到delim指定的字节,然后返回读取到的字符串(包含分隔符)。如果在遇到分隔符之前,Reader的输入结束了,ReadString会返回当前累积的字符串和一个io.EOF错误。如果在读取过程中出现其他错误,ReadString会返回迄今为止读取到的字符串和该错误。

关于'n'的使用

在上述示例中,我们将n(换行符)用作分隔符传给了ReadString方法。这是因为在许多情况下,特别是处理文本数据时,换行符经常被用作不同数据项的分隔符。

例如,如果我们有一串逐行输入的文本数据,我们可以使用ReadString('n')来逐行读取数据。当ReadString遇到n时,它就知道当前行已经结束,可以将当前行的内容返回。

fmt.Fprintf函数

fmt.Fprintf函数在Go语言中用于将格式化的数据写入到一个io.Writer接口的实例中。它的函数签名如下:

代码语言:javascript复制

在TCP通信的上下文中,我们常常需要一种方式来界定消息的边界。因为TCP是一个字节流协议,数据的开始和结束并不是明确标记的。在这种情况下,我们可以选择一个特殊的字符(如n)作为消息的结束标志,这样我们就可以使用ReadString('n')来读取整个消息。

代码语言:javascript复制
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)

在这个函数中:

  • w是目标io.Writer接口的实例,表示数据要写入的目标。
  • format是一个格式化字符串,用来指定要写入的数据的格式。
  • a ...interface{}是可变数量的参数,这些参数的值将根据format字符串的指定格式进行格式化,并写入到w中。

Fprintf函数将返回两个值:写入的字节数和可能发生的错误。如果写入成功,错误将是nil;否则,错误将包含发生的错误信息。

在我们的TCP客户端示例中,我们使用fmt.Fprintf来将输入的字符串发送到服务器。因为net.Conn实现了io.Writer接口,所以我们可以直接将它作为fmt.Fprintf的第一个参数。

下面是示例代码的相关部分:

代码语言:javascript复制
fmt.Fprintf(conn, text   "n") // 发送数据到服务器

在这行代码中,我们将用户输入的字符串text(后面加上一个换行符n)写入到conn中,也就是发送到服务器。换行符n的作用是告诉服务器,这个消息已经结束了,服务器应该开始处理这个消息。

总结

通过这个简单的例子,我们可以看到在Go中使用TCP进行通讯是相对简单的。Go的net库为我们提供了丰富的网络编程功能,使得创建TCP服务器和客户端变得非常容易。对于更复杂的网络编程任务,我们可以使用更强大的库,如net/httpgrpc-go

0 人点赞