Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
498 views
in Technique[技术] by (71.8m points)

PHP程序员如何理解TCP协议

做PHP非常久,然后打算转Go,写过几个go的服务,但都是原生的代码自己写的。最近转Go,修改别人的一个Go框架,里面是微服务之间使用TCP协议进行相互握手,秘钥交换,这一块一直都感觉特别晕,之前是只做网站,HTTP请求来一个处理一个再返回断开,但TCP的建立连接之后相互发送数据。

想提问,这样的水平情况,如何能快速理解这种TCP的协议交换。


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

理解成一个TCP连接就是两根相反流动的水管,水就是其中的数据,
数据是没有边界的,水流也没有界限,因此你需要根据水流的大小,来截取对应的数据,解码成你需要的数据。

比如协议规定tcp 的头部2个字节表示长度,余下的字节表示body部分的具体内容(具体协议可以自定义)

于是我在第一次读取数据的时候,先读取2个字节,然后把这两个字节转成10进制,就是body的长度. 然后重新生成body的数组,继续读:

    var conn net.Conn
    type YourStruct struct {
        Username string `json:"username"`
    }
    for {
        b := make([]byte, 2)
        _, err := io.ReadFull(conn, b)
        if err != nil {
            return
        }
        length := binary.BigEndian.Uint16(b)

        body := make([]byte, length)
        _, err = io.ReadFull(conn, body)
        if err != nil {
            return
        } 
        // 解析结构体
        var v = new(YourStruct)
        json.Unmarshal(body, v)
        fmt.Println(v.Username)
    }

写数据也是一样的道理:

  1. 先计算需要写的长度,转换成byte数组发送,然后再发送body。
    var conn net.Conn
    type YourStruct struct {
        Username string `json:"username"`
    }
    for {
        v := YourStruct{Username: "hahah"}
        data, _ := json.Marshal(v)
        header := make([]byte, 2)
        binary.BigEndian.PutUint16(header, uint16(len(data)))

        // 写头
        conn.Write(header)
        // 写body
        conn.Write(data)
    }

tcp的边界定义就是跟据你定的协议,组装好数据包,发送的时候组装包,获取的时候拆包.
2个字节的头,body最长应该是65535个字节,超过这个长度,header就应该增加长度


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...