首页 > 其他分享 >48 小时内基于 TCP 实现简单网络协议的挑战与实践

48 小时内基于 TCP 实现简单网络协议的挑战与实践

时间:2025-01-08 18:29:38浏览次数:3  
标签:return 48 buffer 网络协议 TCP header byte 数据

目录

48 小时内基于 TCP 实现简单网络协议的挑战与实践

1. 笔试题剖析

1.1 题目要求

1.2 关键难点

2. 协议设计思路

2.1 数据帧结构设计

2.2 连接对象设计

2.3 writer 和 reader 实现

3. 代码实现解析

3.1 数据类型与 header 定义

3.2 连接对象实现

3.3 writer 实现

3.4 reader 实现

3.5 测试用例与运行结果

4. 总结与拓展

4.1 成果总结

4.2 优化方向


在网络编程领域,TCP 协议是基石般的存在。今天要和大家分享的是一个有趣且富有挑战性的任务:在 48 小时内基于 TCP 实现一个简单的网络协议。这是一道来自学员反馈的笔试题,不仅考察对 TCP 协议的理解,更考验对网络编程中复杂逻辑的处理能力。

1. 笔试题剖析

1.1 题目要求

题目给定了一个基本框架,要求自定义实现一个连接对象,包含几个关键接口:send 用于发送数据,receive 用于接收数据,close 用于关闭连接,以及一个类似构造函数的接口从 TCP 连接获取自定义连接对象。除了规定接口,可自行定义其他类型、变量和函数来满足实现需求。

1.2 关键难点

  • 数据标识与传输:传统 TCP 发送缺乏数据标识(key)概念,需设计合理方式在发送数据时添加标识,且接收方能够正确解析。
  • 数据分块处理:send 和 receive 返回的 writer 和 reader 需支持灵活数据写入和读取,发送方可能分多次发送不同大小数据块,接收方也需能处理不同接收数据量,同时要确保接收完整数据并正确标识数据结束。

2. 协议设计思路

2.1 数据帧结构设计

为解决上述问题,设计了包含 header、数据帧和结束帧的数据帧结构。header 包含两个字段:类型字段(标识数据是 key、数据正文还是结束帧)和长度字段(表明对应数据长度)。例如,类型字段占 1 字节,长度字段若使用无符号 int64 则占 8 字节,这样 header 固定长度为 9 字节。通过先发送 header,接收方可以预先知道接下来数据类型和长度,从而正确接收和处理数据。

2.2 连接对象设计

连接对象内部包含 TCP 连接对象以及 send、receive 和 close 方法。send 方法发送数据时,先组织 header 并发送 key,接着初始化并返回 writer,之后通过 writer 继续发送数据。receive 方法接收数据时,先接收 header 并解析出 key,然后返回 reader 供业务层读取数据。close 方法则直接关闭 TCP 连接。

2.3 writer 和 reader 实现

writer 实现 write 方法时,每次写入数据前先组织 header,将 header 和数据拼接后通过 TCP 连接发送,同时在 close 方法中组织结束帧 header 发送,告知接收方数据发送完成。reader 实现相对复杂,涉及分包和粘包处理。通过 buffer 缓冲读取的数据,判断 buffer 中数据是否足够填充接收容器,若不足且 TCP 中数据未读完,则继续读取完整数据帧存入 buffer;若 buffer 数据足够则返回给业务层;若 TCP 中数据读完且 buffer 为空则返回 IO.EOF 表示数据读取结束。

3. 代码实现解析

3.1 数据类型与 header 定义

// 数据帧类型定义
const (
    HeaderFrame byte = iota
    DataFrame
    EndFrame
)

// header结构定义
type Header struct {
    FrameType byte
    Length    uint64
}

// header序列化方法
func (h *Header) Serialize() []byte {
    buffer := make([]byte, 9)
    buffer[0] = h.FrameType
    binary.BigEndian.PutUint64(buffer[1:], h.Length)
    return buffer
}

// header反序列化方法
func (h *Header) Deserialize(data []byte) {
    h.FrameType = data[0]
    h.Length = binary.BigEndian.Uint64(data[1:])
}

3.2 连接对象实现

// 自定义连接对象结构
type CustomConnection struct {
    tcpConn    net.TCPConn
    bufferSize int
}

// send方法实现
func (c *CustomConnection) Send(key string) io.WriteCloser {
    header := Header{FrameType: HeaderFrame, Length: uint64(len(key))}
    serializedHeader := header.Serialize()
    _, err := c.tcpConn.Write(serializedHeader)
    if err!= nil {
        // 错误处理
    }
    _, err = c.tcpConn.Write([]byte(key))
    if err!= nil {
        // 错误处理
    }
    return &CustomWriter{conn: &c.tcpConn}
}

// receive方法实现
func (c *CustomConnection) Receive() (string, io.Reader) {
    headerBuffer := make([]byte, 9)
    _, err := io.ReadFull(&c.tcpConn, headerBuffer)
    if err!= nil {
        // 错误处理
    }
    header := Header{}
    header.Deserialize(headerBuffer)
    keyBuffer := make([]byte, header.Length)
    _, err = io.ReadFull(&c.tcpConn, keyBuffer)
    if err!= nil {
        // 错误处理
    }
    return string(keyBuffer), &CustomReader{conn: &c.tcpConn, buffer: make([]byte, 0), expectedLength: int(header.Length)}
}

// close方法实现
func (c *CustomConnection) Close() error {
    return c.tcpConn.Close()
}

// 构造函数
func NewCustomConnection(tcpConn net.TCPConn) *CustomConnection {
    return &CustomConnection{tcpConn: tcpConn, bufferSize: 1024}
}

3.3 writer 实现

// 自定义writer结构
type CustomWriter struct {
    conn net.Conn
}

// write方法实现
func (w *CustomWriter) Write(data []byte) (int, error) {
    header := Header{FrameType: DataFrame, Length: uint64(len(data))}
    serializedHeader := header.Serialize()
    combinedData := append(serializedHeader, data...)
    return w.conn.Write(combinedData)
}

// close方法实现
func (w *CustomWriter) Close() error {
    header := Header{FrameType: EndFrame, Length: 0}
    serializedHeader := header.Serialize()
    return w.conn.Write(serializedHeader)
}

3.4 reader 实现

// 自定义reader结构
type CustomReader struct {
    conn           net.Conn
    buffer         []byte
    expectedLength int
    readIndex      int
    endReached     bool
}

// read方法实现
func (r *CustomReader) Read(p []byte) (int, error) {
    if r.endReached {
        return 0, io.EOF
    }
    if len(r.buffer)-r.readIndex >= len(p) {
        // buffer中有足够数据
        copy(p, r.buffer[r.readIndex:r.readIndex+len(p)])
        r.readIndex += len(p)
        return len(p), nil
    } else {
        // buffer中数据不足,从TCP连接读取
        for len(r.buffer)-r.readIndex < len(p) {
            data := make([]byte, r.expectedLength)
            n, err := r.conn.Read(data)
            if err!= nil {
                // 错误处理
            }
            r.buffer = append(r.buffer, data[:n]...)
            if err == io.EOF {
                r.endReached = true
                break
            }
        }
        // 从buffer中复制数据到p
        copy(p, r.buffer[r.readIndex:])
        n := len(r.buffer) - r.readIndex
        r.readIndex = len(r.buffer)
        if r.endReached && n == 0 {
            return 0, io.EOF
        }
        return n, nil
    }
}

3.5 测试用例与运行结果

测试代码包含两个测试用例,分别测试数据发送和接收功能。运行测试代码后,可看到测试用例成功执行,输出结果符合预期,证明基于 TCP 实现的简单网络协议功能正常。

4. 总结与拓展

4.1 成果总结

通过 48 小时的努力,成功基于 TCP 实现了一个具备数据标识、分块处理能力的简单网络协议。这一过程不仅深入理解了 TCP 协议原理,还掌握了在复杂网络编程场景下如何设计合理的数据结构和处理逻辑。

4.2 优化方向

  • 性能优化:当前实现中,数据读写和处理逻辑可能存在性能瓶颈,如频繁的内存分配和数据拷贝。可通过优化 buffer 管理、减少不必要的序列化和反序列化操作等方式提升性能。
  • 错误处理增强:进一步完善错误处理机制,提供更详细准确的错误信息,以便在实际应用中更好地定位和解决问题。

希望这篇文章对大家在网络编程学习和实践中有所帮助。如果你对网络编程、TCP 协议或相关技术有更多兴趣,欢迎继续深入学习和交流。如需获取更多相关资料,如 Go 语言云原生技术资料、面试题等,请关注我们的后续分享。

标签:return,48,buffer,网络协议,TCP,header,byte,数据
From: https://blog.csdn.net/m0_57836225/article/details/144970456

相关文章

  • 1048 数字加密(java)
    本题要求实现一种数字加密方法。首先固定一个加密用正整数A,对任一正整数B,将其每1位数字与A的对应位置上的数字进行以下运算:对奇数位,对应位的数字相加后对13取余——这里用J代表10、Q代表11、K代表12;对偶数位,用B的数字减去A的数字,若结果为负数,则再加10。这......
  • 假如你想自定义一个网络协议
    一、引言在当今数字化时代,网络通信无处不在。虽然现有的TCP/IP协议簇已广泛应用且极为成熟,但在某些特定场景下,如工业控制网络、科研专用网络、对安全性和性能有特殊要求的军事通信等领域,自定义网络协议具有独特优势。它能够根据具体需求精细优化网络性能、强化安全保障、适......
  • tcp_wrappers模块实现服务访问控制
    介绍:1、对有状态连接的特定服务进行安全检测并实现访问控制,所以只能用于tcp服务2、判断进程是否接收tcp_wrappers的控制,取决于程序在编译时是否添加了libwrap库3、类似防火墙的功能,但需要程序支持;对于一些访问控制可简单配置即可实现 查询程序是否tcpwrap模块存放位置:/lib......
  • 用 Modbus 软件配置 Modbus tcp 转 ETHERCAT 步骤
     在工业自动化控制系统中,常常会遇到不同协议设备集成的需求。例如,部分设备采用Modbustcp协议进行通信,而另一些设备则基于ETHERCAT协议运行。这种协议差异导致设备之间无法直接进行数据交互,严重影响了整个系统的协同工作和自动化程度。为解决这一问题,我们引入捷米特JM-ECT......
  • 空压机网络接入实战:基于 MODBUS - TCP 转 Ethernet IP 网关的配置过程剖析
     在工业自动化生产环境中,空压机作为重要的气源设备,其稳定运行和有效监控对于整个生产流程至关重要。然而,不同厂家生产的空压机可能采用不同的通信协议,这给集中监控和管理带来了挑战。在本次案例中,我们遇到的空压机采用MODBUS-TCP协议进行数据传输,但企业的自动化控制系统主......
  • 传输层重点协议(TCP协议)深度解剖
    传输控制协议(TCP,TransmissionControlProtocol)是传输层中最重要的协议之一。它提供可靠的、面向连接的通信服务,确保数据在网络中准确传输。以下是对TCP协议的深度解剖。TCP协议概述TCP协议的设计目标是提供可靠的数据传输服务。它通过建立连接、数据分段、流量控制、拥塞控制和......
  • 【编码】如何实现一套自定义网络协议?
    前言下文介绍的自定义协议仅作为学习示例,纯粹是玩具项目,没有实际可用性。无需过度关注和讨论其合理性进行通信的双方是谁?常见的模型客户端-服务器,例如HTTP协议,浏览器<=>Web服务器。中转站模型,如MQTT协议,应用服务<=>中转站<=>硬件客户端对等模型,例如Thrift协议,应用服务<=>应......
  • 网络协议
    网络协议计算机网络定义计算机网络的标准定义是:利用通信线路将地理上分散的、具有独立功能的计算机系统和通信设备按不同的形式连接起来,以功能完善的网络软件及协议实现资源共享和信息传递的系统。分类计算机网络从覆盖范围上划分可以分为三类:局域网、城域网、广域网。局域......
  • SpringBoot民宿管理系统l2548(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表客户,员工,客房类型,客房信息,客房预订,入住登记,退房登记,财务,换房登记开题报告内容一、选题背景与意义随着旅游业的快速发展,民宿作为一种新兴的住宿方式,因其......
  • springboot健康挑战社区小程序-计算机毕业设计源码84348
    目 录摘要1绪论1.1选题背景1.2选题意义1.3论文结构与章节安排2 健康挑战社区小程序系统分析2.1可行性分析2.1.1技术可行性分析2.1.2 经济可行性分析2.1.3法律可行性分析2.2系统功能分析2.2.1功能性分析2.2.2非功能性分析2.3 系统用例......