Golang:TCP客户端/服务器数据分隔符 [英] Golang: TCP client/server data delimiter

查看:110
本文介绍了Golang:TCP客户端/服务器数据分隔符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

不知道如何制定这个问题,如果它只涉及到语言,但我想要做的是有一个tcp服务器和客户端之间交换数据,基本上客户端将流大量的数据转换成服务器的小块,服务器将等待读取每一块数据,然后回复一个状态码,该码将被客户端读取,并基于该状态进行其他工作。



我使用下面的函数作为 test 来从客户端和服务器读取数据(请注意,我知道这并不完美,但它只是测试):

  func createBufferFromConn(conn net.Conn)* bytes.Buffer {
buffer:=& amp ; bytes.Buffer {}
doBreak:= false
for {
incoming:= make([] byte,BUFFER_SIZE)

conn.SetReadDeadline(time.Now ().Add(time.Second * 2))
bytesRead,err:= conn.Read(incoming)
conn.SetReadDeadline(time .Time {})

if err!= nil {
if err == io.EOF {
fmt.Println(err)
} else if neterr, OK:= err。(net.Error);好的&& neterr.Timeout(){
fmt.Println(err)
}
doBreak = true
}

if doBreak == false&& bytesRead == 0 {
continue
}

if bytesRead> 0 {
buffer.Write(incoming [:bytesRead])
如果bytes.HasSuffix(buffer.Bytes(),[] byte(|)){
bb:= bytes。 (b)
doBreak = true


$
$ b if doBreak {
break
}
}
返回缓冲区
}

现在在我的情况下,如果我通过telnet连接(go代码还包含一个 client()来连接到 server())和我输入类似于 test 12345 | 足够合理一切正常,缓冲区包含所有从Telnet写入的字节(除了由Trim()调用删除的管道)。

如果我删除 if bytes.HasSuffix(buffer.Bytes(),[] byte(|)){从代码块,然后我会得到一个超时2秒后,再次,如预期,因为在这段时间内没有收到数据和服务器关闭连接,如果我没有设置从读取截止日期连接,它将永远等待读取数据,并永远不会知道何时停止。



我想我的问题是,如果我发送多个数据块,我必须指定一个我自己的分隔符,以便我知道何时停止从连接读取,并避免永久等待或等待服务器超时连接? 解决方案


我想我的问题是,如果我发送多个数据块,是否有
来指定我自己的分隔符,以便我知道何时停止读取
,避免永久等待或等待
服务器超时连接




是的。 TCP是一种流协议,无法确定协议中的消息在哪里启动和停止,而无需以某种方式对其进行组帧。

使用更常见的成帧方法是发送大小前缀,以便接收器知道要读取多少而不用必须缓存结果并扫描分隔符。这可以像 message_length:data .... 一样简单(另见 netstring 类型长度值编码)。

Not sure how to formulate the question and if it really relates only to go language, but what i am trying to do is to have a tcp server and client that will exchange data in between, basically the client will stream big amounts of data into smaller chunks to the server, the server will wait to read every chunk of data and then reply with a status code which will be read by the client and based on that it will do other work.

I use the function below as a test to read the data from client and server (please note, i am aware that is not perfect, but it's just testing) :

func createBufferFromConn(conn net.Conn) *bytes.Buffer {
    buffer := &bytes.Buffer{}
    doBreak := false
    for {
        incoming := make([]byte, BUFFER_SIZE)

        conn.SetReadDeadline(time.Now().Add(time.Second * 2))
        bytesRead, err := conn.Read(incoming)
        conn.SetReadDeadline(time.Time{})

        if err != nil {
            if err == io.EOF {
                fmt.Println(err)
            } else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
                fmt.Println(err)
            }
            doBreak = true
        }

        if doBreak == false && bytesRead == 0 {
            continue
        }

        if bytesRead > 0 {
            buffer.Write(incoming[:bytesRead])
            if bytes.HasSuffix(buffer.Bytes(), []byte("|")) {
                bb := bytes.Trim(buffer.Bytes(), "|")
                buffer.Reset()
                buffer.Write(bb)
                doBreak = true
            }
        }

        if doBreak {
            break
        }
    }
    return buffer
}

Now in my case if i connect via telnet(the go code also includes a client() to connect to the server()) and i type something like test 12345| fair enough everything works just fine and the buffer contains all the bytes written from telnet(except the pipe which is removed by the Trim() call).

If i remove the if bytes.HasSuffix(buffer.Bytes(), []byte("|")) { block from the code then i will get a timeout after 2 seconds, again, as expected because no data is received in that amount of time and the server closes the connection, and if i don't set a read deadline from the connection, it will wait forever to read data and will never know when to stop.

I guess my question is, if i send multiple chunks of data, do i have to specify a delimiter of my own so that i know when to stop reading from the connection and avoid waiting forever or waiting for the server to timeout the connection ?

解决方案

I guess my question is, if i send multiple chunks of data, do i have to specify a delimiter of my own so that i know when to stop reading from the connection and avoid waiting forever or waiting for the server to timeout the connection

Yes. TCP is a stream protocol, and there's no way to determine where messages within the protocol start and stop without framing them in some way.

A more common framing method used is to send a size prefix, so that the receiver knows how much to read without having to buffer the results and scan for a delimiter. This can be as simple as message_length:data.... (see also netstring, and type-length-value encoding).

这篇关于Golang:TCP客户端/服务器数据分隔符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆