经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
基于EasyTcp4Net开发一个功能较为完善的去持久化聊天软件
来源:cnblogs  作者:BruceNeter  时间:2024/7/31 15:00:11  对本文有异议

之前自己写了一篇介绍TCP的一些常用的功能介绍和特征,并且用代码做了示例,最终开发了一个EasyTcp4Net的TCP工具库,其最大的特色就是使用了微软提供的高性能库中的一些数据结构来处理TCP数据。
最近辞职待业在家,也没啥事做,就利用自己写的TCP通讯库基础上开发了一个示例的聊天程序,功能包括,文本发送,图片发送,断线重连,消息发送成功确认,消息发送失败提示等。

示例

发消息给自己

image

收到消息

image

发送图片

image

消息发送中

image

重连中

image

发送失败

image

数据包结构以及拆包

定义数据包结构

数据包结构定义了每次发送一个数据的完整的数据结构,我们将包体长度定义在包头中来解决粘包和断包的问题。
数据包我们采用了简单的序列化成byte数组的方式来发送。

  1. [StructLayout(LayoutKind.Sequential)]
  2. public class Message<TBody> : IMsssage<TBody> where TBody : Packet
  3. {
  4. //数据包包体长度 4字节
  5. public int BodyLength { get; private set; }
  6. //消息类型 4字节
  7. public MessageType MessageType { get; set; }
  8. public TBody? Body { get; set; }
  9. private Message<TBody> Deserialize(byte[] bodyData)
  10. {
  11. var bodyStr = System.Text.Encoding.Default.GetString(bodyData);
  12. Body = JsonSerializer.Deserialize<TBody>(bodyStr);
  13. return this;
  14. }
  15. public static Message<TBody> FromBytes(ReadOnlyMemory<byte> data)
  16. {
  17. Message<TBody> packet = new Message<TBody>();
  18. packet.BodyLength = BinaryPrimitives.ReadInt32BigEndian(data.Slice(0, 4).Span);
  19. packet.MessageType = (MessageType)BinaryPrimitives.ReadInt32BigEndian(data.Slice(4, 4).Span);
  20. packet.Deserialize(data.Slice(8, packet.BodyLength).Span.ToArray());
  21. return packet;
  22. }
  23. public byte[] Serialize()
  24. {
  25. var Length = 4 + 4;
  26. var bodyArray = System.Text.Encoding.Default.GetBytes(JsonSerializer.Serialize(Body));
  27. BodyLength = bodyArray.Length;
  28. Length += bodyArray.Length;
  29. byte[] result = new byte[Length];
  30. result.AddInt32(0, bodyArray.Length);
  31. result.AddInt32(4, (int)MessageType);
  32. Buffer.BlockCopy(bodyArray, 0, result, 8, bodyArray.Length);
  33. return result;
  34. }
  35. public TBody GetBody()
  36. {
  37. return Body;
  38. }
  39. }
  40. public interface IMsssage <out TBody> where TBody : Packet
  41. {
  42. public TBody GetBody();
  43. }

我们在服务端和客户端根据我们定义的数据结构,来调用EasyTcp4Net提供的固定包头来解析数据包

  1. _easyTcpClient.SetReceiveFilter(new FixedHeaderPackageFilter(8, 0, 4, false));

文本/图片发送

我们可以定义消息基类,再拓展两个消息类,一个文本消息,一个图片消息

  1. public class SendMessagePacket : Packet
  2. {
  3. public string MessageId { get; set; } = Guid.NewGuid().ToString();
  4. public string From { get; set; }
  5. public string To { get; set; }
  6. }

图片消息

  1. public class SendImageMessagePacket : SendMessagePacket
  2. {
  3. public byte[] Data { get; set; }
  4. public string FileName { get; set; }
  5. }

文本消息

  1. public class SendTextMessagePacket : SendMessagePacket
  2. {
  3. public string Text { get; set; }
  4. }

我们还需要在界面中增加相关的文本和图片的ViewModel
发送消息的时候,发送者可以立刻将消息添加到聊天界面,然后等待收到自己发送的消息从服务端发来的时候,根据状态判断消息是否发送成功,等待的时候可以将消息设置发送中的界面状态显示,这种发送消息逻辑和微信基本一致。

断线处理

利用EasyTcp4Net提供的断线的事件,可以非常方便的在服务端知道客户端突然断开了,或者在客户端知道和服务端连接断开了。

客户端

  1. _easyTcpClient.OnDisConnected += async (obj, e) =>
  2. {
  3. Title = Title + _disConnectTip;
  4. await ReConnectAsync();
  5. };

主要是触发了重连的机制。

服务端

  1. _easyTcpServer.OnClientConnectionChanged += (obj, e) =>
  2. {
  3. if (e.Status == ConnectsionStatus.DisConnected)
  4. {
  5. _accounts.TryRemove(e.ClientSession.SessionId, out var account);
  6. }
  7. };

主要是将该用户从在线列表中移除。

总结

总体来说做一个聊天软件需要考虑的细节比较多。
示例地址:https://github.com/BruceQiu1996/EasyChat

原文链接:https://www.cnblogs.com/qwqwQAQ/p/18330325

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号