为了账号安全,请及时绑定邮箱和手机立即绑定

TCP 客户端或服务器卡在处理数据

TCP 客户端或服务器卡在处理数据

Go
沧海一幻觉 2022-09-19 10:43:17
我正在尝试编写一个简单的tcp服务器和客户端程序。当我同时运行下面的服务器和客户端代码时,客户端将仅接收来自服务器的时间消息并退出,并且服务器继续接受新连接。我预期的程序行为是我希望服务器也从客户端接收“hello world”消息并关闭连接,客户端也使用“响应连接”功能也是如此。但问题是,当我启动客户端时,服务器似乎卡在了conn。读取“响应连接”函数内的函数,当我首先停止客户端时,错误为“EOF退出状态1”,这对于调试来说确实是模棱两可的。当我首先停止服务器时,客户端将从服务器接收时间数据。如果您有任何想法,请帮助回答,因为我完全是Golang的新手。非常感谢!服务器.gopackage mainimport (    "fmt"    "io"    "log"    "net"    "time")type connection struct {    host    string    port    string    network string}func checkError(err error) {    if err != nil {        log.Fatalln(err)    }}func responseConnection(conn net.Conn) {    defer conn.Close() // <-- When responseConnection() is used, add this    buf := make([]byte, 0, 4096)    tmp := make([]byte, 256)    for {        n, err := conn.Read(tmp)        if err != nil {            checkError(err)            if err != io.EOF {                fmt.Println("Error reading: ", err)            }            // fmt.Println(err)            break        }        buf = append(buf, tmp[:n]...)    }    fmt.Println("Data from client ========> ", string(buf))    // c <- buf}func handleConnection(conn net.Conn) {    defer conn.Close() // <- When responseConnection() is used, remove this    dayTime := time.Now().String()    conn.Write([]byte(dayTime))    // responseConnection(conn)    fmt.Println("The end of handleConnection")}func main() {    localConn := connection{        host:    "",        port:    "5555",        network: "tcp",    }    // servicePort := ":5555"    tcpAddr, err := net.ResolveTCPAddr(localConn.network, ":"+localConn.port)    checkError(err)    l, err := net.ListenTCP("tcp", tcpAddr)    fmt.Println("Server starts listening on port", localConn.port)    checkError(err)        for {        fmt.Println("Accepting a new connection....")        conn, err := l.Accept()        checkError(err)        handleConnection(conn)        // responseConnection(conn)    }}
查看完整描述

1 回答

?
慕桂英3389331

TA贡献2036条经验 获得超8个赞

我认为你的问题非常标准:不注意TCP不实现消息边界的事实,只是通过连接传输两个不透明的字节流。

这意味着,当您将一串字节“Hello world从客户端”发送到连接的套接字(已建立的TCP连接)时,连接的另一端不知道客户端的消息在哪里结束,除非客户端以某种方式传达它本身;根本没有办法使用TCP本身来划分单个消息。

输入“应用程序级协议”:除非您打算使用TCP的数据交换任务自然地传输单个“消息” - 想象一下服务器将单个文件的内容转储到每个连接的客户端并关闭连接 - 您必须发明一些方法让客户端告诉服务器它发送的每条消息实际上在哪里结束。

考虑一下您的示例:在读取过程中,您基本上有一个循环,该循环从套接字重复读取数据块,具有单个退出条件:到达该套接字上的文件末尾。只有当远程端(在本例中为客户端)关闭其连接端时,才会报告 EOF,而客户端从不这样做:它发送一个字符串,然后等待服务器发回一些东西,但服务器从不回复,因为它永远不会完成读取。

有多种方法可以解决问题。

  • 发明一个自定义协议(例如,在TLV系列中),它将实现消息成帧。

    例如,在最简单的形式中,该协议可以定义为单个无符号字节,其中包含以下消息的长度(以字节为单位)。
    然后,服务器将有一个两步过程来读取客户端的每条消息:

    1. 读取单个字节;

    2. 如果成功,请读取由前导字节值定义的任意数量的后续字节;

    3. 成功后,请返回步骤 1 以阅读以下消息。

  • 想出一个消息分隔符,如ASCII LF字符 - 可以编码为Go的字符串文本,并使服务器继续读取,直到遇到LF;一旦它发现了一个LF,它就知道它应该处理消息,然后开始读取另一个消息。\n

    围棋有方便的类型布菲奥。读取器在其标准包中,可以从由LF分隔的任何单个行中读取。io.Reader

  • 具有更复杂的消息框架,例如使用 JSON 流发送 JSON 文档。

    由库存包实现的解码器的一个经常监督的功能是,它可以解码JSON对象的流,以此为例。encoding/json

可能性实际上很多,所以我只是触及了表面,我认为你应该明白这个想法。


查看完整回答
反对 回复 2022-09-19
  • 1 回答
  • 0 关注
  • 93 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号