zoukankan      html  css  js  c++  java
  • 详解S7源码3-COTP and TPKT

    连接 S7COMM简介 https://www.anquanke.com/post/id/186099

    OSI layer    Protocol
    Application Layer    S7 communication
    Presentation Layer    S7 communication(COTP)
    Session Layer    S7 communication(TPKT)
    Transport Layer    ISO-on-TCP (RFC 1006)
    Network Layer    IP
    Data Link Layer    Ethernet
    Physical Layer    Ethernet

    1,TPKT(默认端口号102)

    tpkt主要为

    version 1byte 0x03 3
    resrved 1byte 0x00 0
    length 2byte 0x16 22

    length为包括这4字节+Payload在内的字节数.(Payload)为data包装后数据.

    1,TPKT类,返回TPKT信息和数据包.根据length-4求得data.就是Payload的数据.(解封).

    internal class TPKT
        {
            public byte Version;
            public byte Reserved1;
            public int Length;
            public byte[] Data;
    
            /// <summary>
            /// Reads a TPKT from the socket
            /// </summary>
            /// <param name="stream">The stream to read from</param>
            /// <returns>TPKT Instance</returns>
            public static TPKT Read(Stream stream)
            {
                var buf = new byte[4];
                int len = stream.Read(buf, 0, 4);
                if (len < 4) throw new TPKTInvalidException("TPKT is incomplete / invalid");
                var pkt = new TPKT
                {
                    Version = buf[0],
                    Reserved1 = buf[1],
                    Length = buf[2] * 256 + buf[3] //BigEndian
                };
                if (pkt.Length > 0)
                {
                    pkt.Data = new byte[pkt.Length - 4];
                    len = stream.Read(pkt.Data, 0, pkt.Length - 4);
                    if (len < pkt.Length - 4)
                        throw new TPKTInvalidException("TPKT is incomplete / invalid");
                }
                return pkt;
            }
    
            /// <summary>
            /// Reads a TPKT from the socket Async
            /// </summary>
            /// <param name="stream">The stream to read from</param>
            /// <returns>Task TPKT Instace</returns>
            public static async Task<TPKT> ReadAsync(Stream stream)
            {
                var buf = new byte[4];
                int len = await stream.ReadAsync(buf, 0, 4);
                if (len < 4) throw new TPKTInvalidException("TPKT is incomplete / invalid");
                var pkt = new TPKT
                {
                    Version = buf[0],
                    Reserved1 = buf[1],
                    Length = buf[2] * 256 + buf[3] //BigEndian
                };
                if (pkt.Length > 0)
                {
                    pkt.Data = new byte[pkt.Length - 4];
                    len = await stream.ReadAsync(pkt.Data, 0, pkt.Length - 4);
                    if (len < pkt.Length - 4) throw new TPKTInvalidException("TPKT is incomplete / invalid");
                }
                return pkt;
            }
    
            public override string ToString()
            {
                return string.Format("Version: {0} Length: {1} Data: {2}",
                    Version,
                    Length,
                    BitConverter.ToString(Data)
                    );
            }
        }


    2,TPDU-----Transport protocol data unit---一个基本数据传输单元(COTP)


    第一个byte--标识为length---不包括本身.标识

    第二给byte---标识为PDUType--分为以下几种


    0x0d 连接确认 0x05 拒绝
    0x0e 连接请求 0xf0 数据包
    0x08 断开请求
    0x0c 断开确认

    当其为0xf0的时候:

    第三个byte---flags:其位7标志是否为最后的TPDU,位0-6标识块NUMBER---TPDU NUMBER.


    从stream---->TPKT---->TPDU---->再从TPDU中读取数据TSDU.(减去4个字节的TPKT包裹+headerLength).

     public class TPDU
            {
                public byte HeaderLength;
                public byte PDUType;
                public int TPDUNumber;
                public byte[] Data;
                public bool LastDataUnit;
    
                public TPDU(TPKT tPKT)
                {
                    var br = new BinaryReader(new MemoryStream(tPKT.Data));
                      
                    HeaderLength = br.ReadByte();
                    if (HeaderLength >= 2)
                    {
                        PDUType = br.ReadByte();
                        if (PDUType == 0xf0) //DT Data
                        {
                            var flags = br.ReadByte();
                            TPDUNumber = flags & 0x7F;
                            LastDataUnit = (flags & 0x80) > 0;
                            Data = br.ReadBytes(tPKT.Length - HeaderLength - 4); //4 = TPKT Size
                            return;
                        }
                        //TODO: Handle other PDUTypes
                    }
                    Data = new byte[0];
                }
    
                /// <summary>
                /// Reads COTP TPDU (Transport protocol data unit) from the network stream
                /// See: https://tools.ietf.org/html/rfc905
                /// </summary>
                /// <param name="stream">The socket to read from</param>
                /// <returns>COTP DPDU instance</returns>
                public static TPDU Read(Stream stream)
                {
                    var tpkt = TPKT.Read(stream);
                    if (tpkt.Length > 0) return new TPDU(tpkt);
                    return null;
                }
    
                /// <summary>
                /// Reads COTP TPDU (Transport protocol data unit) from the network stream
                /// See: https://tools.ietf.org/html/rfc905
                /// </summary>
                /// <param name="stream">The socket to read from</param>
                /// <returns>COTP DPDU instance</returns>
                public static async Task<TPDU> ReadAsync(Stream stream)
                {
                    var tpkt = await TPKT.ReadAsync(stream);
                    if (tpkt.Length > 0) return new TPDU(tpkt);
                    return null;
                }
    
                public override string ToString()
                {
                    return string.Format("Length: {0} PDUType: {1} TPDUNumber: {2} Last: {3} Segment Data: {4}",
                        HeaderLength,
                        PDUType,
                        TPDUNumber,
                        LastDataUnit,
                        BitConverter.ToString(Data)
                        );
                }
    
            }

    3,TSDU---服务数据单元---定义了将连续的TPDU转换为一个TSDU单元.

     public class TSDU
            {
                /// <summary>
                /// Reads the full COTP TSDU (Transport service data unit)
                /// See: https://tools.ietf.org/html/rfc905
                /// </summary>
                /// <param name="stream">The stream to read from</param>
                /// <returns>Data in TSDU</returns>
                public static byte[] Read(Stream stream)
                {
                    var segment = TPDU.Read(stream);
                    if (segment == null) return null;
    
                    var output = new MemoryStream(segment.Data.Length);
                    output.Write(segment.Data, 0, segment.Data.Length);
    
                    while (!segment.LastDataUnit)
                    {
                        segment = TPDU.Read(stream);
                        output.Write(segment.Data, (int)output.Position, segment.Data.Length);
                    }
                    return output.GetBuffer().Take((int)output.Position).ToArray();
                }
    
                /// <summary>
                /// Reads the full COTP TSDU (Transport service data unit)
                /// See: https://tools.ietf.org/html/rfc905
                /// </summary>
                /// <param name="stream">The stream to read from</param>
                /// <returns>Data in TSDU</returns>
                public static async Task<byte[]> ReadAsync(Stream stream)
                {
                    var segment = await TPDU.ReadAsync(stream);
                    if (segment == null) return null;
    
                    var output = new MemoryStream(segment.Data.Length);
                    output.Write(segment.Data, 0, segment.Data.Length);
    
                    while (!segment.LastDataUnit)
                    {
                        segment = await TPDU.ReadAsync(stream);
                        output.Write(segment.Data, (int)output.Position, segment.Data.Length);
                    }
                    return output.GetBuffer().Take((int)output.Position).ToArray();
                }
            }
  • 相关阅读:
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    微信小程序TodoList
    C语言88案例-找出数列中的最大值和最小值
    C语言88案例-使用指针的指针输出字符串
  • 原文地址:https://www.cnblogs.com/frogkiller/p/14678615.html
Copyright © 2011-2022 走看看