0

0

Go语言实现TCP服务器:逐行读取客户端输入并输出到控制台

DDD

DDD

发布时间:2025-09-26 15:11:01

|

790人浏览过

|

来源于php中文网

原创

Go语言实现TCP服务器:逐行读取客户端输入并输出到控制台

本文将指导您如何使用Go语言构建一个简单的TCP服务器。该服务器能够接收客户端的连接,逐行读取客户端发送的数据,并将其实时打印到服务器的标准输出(控制台)。我们将重点介绍如何利用bufio.Reader高效处理流式数据中的行分隔符,并提供完整的代码示例及运行指南,帮助您快速理解和实现这一功能。

概述

go语言中构建网络服务器是常见的任务。当我们需要处理基于行的协议,例如某些简单的文本协议时,从tcp连接中逐行读取数据并进行处理就变得尤为重要。本教程将展示如何实现一个tcp服务器,该服务器监听特定端口,接受客户端连接,并将其发送的每一行数据直接输出到服务器的控制台。

核心问题:从net.Conn中逐行读取

net.Conn接口提供了读写字节流的能力,但它本身并没有直接提供按行读取的方法。客户端发送的数据通常是字节流,可能包含多个行,每行以换行符(\n)结束。为了实现逐行读取,我们需要一个能够缓冲并识别行分隔符的工具

解决方案:使用bufio.Reader

Go标准库中的bufio包提供了一个Reader类型,它能够包装一个io.Reader(net.Conn实现了io.Reader接口),并提供缓冲和高级的读取方法,其中就包括ReadString。

bufio.Reader的ReadString(delim byte)方法会从输入流中读取数据,直到遇到指定的delim字节(例如\n),或者遇到错误(包括io.EOF)。它会返回读取到的字符串(包含分隔符)以及可能发生的错误。

实现步骤

  1. 监听TCP端口: 使用net.Listen("tcp", ":端口号")来创建一个TCP监听器。
  2. 接受客户端连接: 在一个无限循环中,调用srv.Accept()来接受新的客户端连接。每个连接都应该在一个独立的 Goroutine 中处理,以避免阻塞主 Goroutine 并支持并发连接。
  3. 创建bufio.Reader: 在处理每个连接的 Goroutine 中,将net.Conn包装成一个bufio.Reader实例。
  4. 逐行读取数据: 使用一个循环调用bufio.Reader的ReadString('\n')方法来读取每一行数据。
  5. 处理错误和EOF: 检查ReadString返回的错误。如果错误是io.EOF,表示客户端关闭了连接,此时应该跳出循环。其他错误则需要进行适当处理。
  6. 打印到标准输出: 将读取到的每一行数据使用fmt.Print()打印到服务器的标准输出。
  7. 关闭连接: 在Goroutine结束时,确保调用net.Conn的Close()方法来释放资源。

完整代码示例

下面是实现上述功能的Go语言代码:

立即学习go语言免费学习笔记(深入)”;

Bandy AI
Bandy AI

全球领先的电商设计Agent

下载
package main

import (
    "bufio"
    "fmt"
    "io"
    "log"
    "net"
)

func main() {
    // 监听TCP端口2000
    srv, err := net.Listen("tcp", ":2000")
    if err != nil {
        log.Fatalf("无法监听端口: %v", err)
    }
    defer srv.Close() // 确保在main函数退出时关闭监听器
    fmt.Println("TCP服务器已启动,监听端口 2000...")

    for {
        // 接受新的客户端连接
        conn, err := srv.Accept()
        if err != nil {
            log.Printf("接受连接失败: %v", err)
            continue // 继续接受下一个连接
        }
        fmt.Printf("新客户端连接来自: %s\n", conn.RemoteAddr())

        // 为每个连接启动一个Goroutine进行处理
        go handleConnection(conn)
    }
}

// handleConnection 处理单个客户端连接
func handleConnection(c net.Conn) {
    defer c.Close() // 确保在函数退出时关闭客户端连接
    fmt.Printf("开始处理连接 %s\n", c.RemoteAddr())

    // 将net.Conn包装成bufio.Reader,以便逐行读取
    reader := bufio.NewReader(c)

    for {
        // 逐行读取数据,直到遇到换行符 '\n'
        line, err := reader.ReadString('\n')

        if err == io.EOF {
            // 客户端关闭了连接
            fmt.Printf("客户端 %s 已断开连接。\n", c.RemoteAddr())
            break
        } else if err != nil {
            // 其他读取错误
            log.Printf("从 %s 读取数据时发生错误: %v", c.RemoteAddr(), err)
            break
        }

        // 成功读取到一行数据,打印到服务器的标准输出
        // fmt.Print() 会直接输出字符串,包括其中的换行符
        fmt.Print(line)
    }
    fmt.Printf("连接 %s 处理结束。\n", c.RemoteAddr())
}

运行与测试

  1. 保存代码: 将上述代码保存为 server.go 文件。
  2. 编译: 打开终端,导航到文件所在目录,然后运行:
    go build -o server server.go
  3. 运行服务器:
    ./server

    您将看到输出 TCP服务器已启动,监听端口 2000...

  4. 使用 telnet 测试: 打开另一个终端,连接到服务器:
    telnet localhost 2000

    您将看到 Connected to localhost. 等信息。

  5. 输入数据: 在 telnet 客户端中输入几行文字,每行按回车键结束:
    test 123
    foobar
    Go is great!

    当您输入并按回车后,这些行将立即显示在运行 ./server 的那个终端窗口中。

  6. 关闭 telnet: 您可以通过输入 ^] (Ctrl + ]) 然后输入 quit 来退出 telnet。服务器端会打印 客户端 127.0.0.1:xxxxx 已断开连接。

注意事项与最佳实践

  • 错误处理: 示例代码中包含了基本的错误处理,如监听失败、接受连接失败以及读取数据时的错误。在生产环境中,应采用更健壮的错误处理机制,例如记录错误日志、返回特定的错误码或优雅地关闭连接,而不是简单地使用 panic。
  • 资源管理: 务必使用 defer srv.Close() 和 defer c.Close() 来确保在函数退出时正确关闭监听器和客户端连接,防止资源泄露。
  • 标准输出同步: Go语言的 fmt.Print 函数通常是线程安全的,但在高并发场景下,多个 Goroutine 同时向标准输出写入可能会导致输出交错,影响可读性。如果对输出顺序有严格要求,可以考虑使用一个共享的通道(channel)来收集所有 Goroutine 的输出,然后在一个独立的 Goroutine 中统一写入标准输出。
  • 缓冲区大小: bufio.NewReader 默认会使用一个内置的缓冲区。对于大量或非常长的行,这个缓冲区大小可能需要根据实际情况进行调整,以优化性能。
  • 协议设计: 本示例适用于简单的文本协议。对于更复杂的二进制协议或需要更多状态管理的协议,可能需要实现自定义的读取逻辑或使用特定的协议库。

总结

通过本教程,我们学习了如何利用Go语言的 net 包和 bufio 包构建一个简单的TCP服务器,该服务器能够高效地接收客户端连接,并逐行读取其发送的数据并输出到标准输出。掌握 bufio.Reader 的 ReadString 方法是处理基于行文本协议的关键。在实际应用中,请务必考虑完善的错误处理、资源管理以及在高并发场景下的输出同步问题。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
python中print函数的用法
python中print函数的用法

python中print函数的语法是“print(value1, value2, ..., sep=' ', end=' ', file=sys.stdout, flush=False)”。本专题为大家提供print相关的文章、下载、课程内容,供大家免费下载体验。

186

2023.09.27

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

320

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1502

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

624

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

653

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

609

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

172

2025.07.29

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

9

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4.4万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号