Skip to content

Commit

Permalink
引入TPKT编码器TPKTCodec,解决服务端粘包问题
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Jan 4, 2024
1 parent 938d978 commit 0b6046e
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 15 deletions.
6 changes: 3 additions & 3 deletions NewLife.Siemens/Protocols/S7PLC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,11 @@ private async Task<COTP> RequestAsync(Stream stream, COTP request, CancellationT
try
{
var pk = request.GetBytes(true);
var buf = pk.ReadBytes();
//var buf = pk.ReadBytes();

using var closeOnCancellation = cancellationToken.Register(Close);
//await pk.CopyToAsync(stream, cancellationToken);
await stream.WriteAsync(buf, 0, buf.Length, cancellationToken);
await pk.CopyToAsync(stream, cancellationToken);
//await stream.WriteAsync(buf, 0, buf.Length, cancellationToken);
return await COTP.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
}
catch (Exception exc)
Expand Down
2 changes: 2 additions & 0 deletions NewLife.Siemens/Protocols/S7Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public S7Server()
{
Port = 102;
ProtocolType = NetType.Tcp;

Add(new TPKTCodec());
}
}

Expand Down
26 changes: 14 additions & 12 deletions NewLife.Siemens/Protocols/TPKT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace NewLife.Siemens.Protocols;
/// </remarks>
public class TPKT
{
#region 属性
/// <summary>版本</summary>
public Byte Version { get; set; }

Expand All @@ -23,28 +24,20 @@ public class TPKT

/// <summary>数据</summary>
public Packet Data { get; set; }

/// <summary>实例化</summary>
public TPKT() { }

private TPKT(Byte version, Byte reserved1, Int32 length, Byte[] data)
{
Version = version;
Reserved = reserved1;
Length = (UInt16)length;
Data = data;
}
#endregion

/// <summary>解析数据</summary>
/// <param name="pk"></param>
public void Read(Packet pk)
public TPKT Read(Packet pk)
{
var buf = pk.ReadBytes(0, 4);
Version = buf[0];
Reserved = buf[1];
Length = buf.ToUInt16(2, false);

if (pk.Total > 4) Data = pk.Slice(4, Length);

return this;
}

/// <summary>解析数据</summary>
Expand Down Expand Up @@ -87,6 +80,15 @@ public Byte[] ToArray()
return ms.ToArray();
}

/// <summary>获取字节数组</summary>
/// <returns></returns>
public Packet ToPacket()
{
var ms = new MemoryStream();
Write(ms);
return new Packet(ms);
}

/// <summary>
/// Reads a TPKT from the socket Async
/// </summary>
Expand Down
64 changes: 64 additions & 0 deletions NewLife.Siemens/Protocols/TPKTCodec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using NewLife.Data;
using NewLife.Messaging;
using NewLife.Model;
using NewLife.Net.Handlers;

namespace NewLife.Siemens.Protocols;

/// <summary>编码器</summary>
public class TPKTCodec : MessageCodec<TPKT>
{
/// <summary>实例化编码器</summary>
public TPKTCodec() => UserPacket = false;

/// <summary>编码</summary>
/// <param name="context"></param>
/// <param name="msg"></param>
/// <returns></returns>
protected override Object Encode(IHandlerContext context, TPKT msg)
{
if (msg is TPKT cmd) return cmd.ToPacket();

return null;
}

/// <summary>解码</summary>
/// <param name="context"></param>
/// <param name="pk"></param>
/// <returns></returns>
protected override IList<TPKT> Decode(IHandlerContext context, Packet pk)
{
var ss = context.Owner as IExtend;
if (ss["Codec"] is not PacketCodec pc)
ss["Codec"] = pc = new PacketCodec { GetLength = p => GetLength(p, 3, 1) - 4, Offset = 3 };

var pks = pc.Parse(pk);
var list = pks.Select(e => new TPKT().Read(e)).ToList();

return list;
}

/// <summary>连接关闭时,清空粘包编码器</summary>
/// <param name="context"></param>
/// <param name="reason"></param>
/// <returns></returns>
public override Boolean Close(IHandlerContext context, String reason)
{
if (context.Owner is IExtend ss) ss["Codec"] = null;

return base.Close(context, reason);
}

/// <summary>是否匹配响应</summary>
/// <param name="request"></param>
/// <param name="response"></param>
/// <returns></returns>
protected override Boolean IsMatch(Object request, Object response)
{
if (request is not TPKT req || response is not TPKT res) return false;

// 不支持链路复用,任意响应都是匹配的

return true;
}
}

0 comments on commit 0b6046e

Please sign in to comment.