前言
闲暇之余,利用.net core写了一个在线客服系统。我把业余时间写的这个小系统留在网上。人们纷纷来找我索要私有化版本,我都给了。毕竟,软件行业的初衷就是免费和共享。
后来干脆发了一个100%私有版给大家直接下载,方便大家自行部署。同时,为了方便暂时不想私有化自己部署的朋友使用,我搭建了一个线上环境供大家免费使用。
今天查看了线上使用环境的数据库,累计处理的消息数居然达到了历史新高! !超过 480,000 条参赛作品! !
我对这个数字感到非常震惊,因为我安装了这个线上环境之后,除了正常的版本更新之外,我基本上不关心它,也不需要维护它。今天我想了一下,居然处理了这么多消息!
虽然系统是完全免费的,免费供客户使用,但是取得了这样的成绩,自己的小系统的用户还是很欣慰的。
有朋友说:程序员写的系统如果被人用了,就已经超越了99%的程序员。哈哈,我就放心了。
我是怎么做到的
系统架构
服务器程序除了提供一般的数据增删改查能力外,还需要实现稳定的消息中间件,对内存中的站点状态、客服状态、访客状态等上下文数据进行稳定的管理。作为稳定的TCP/IP长连接维护机制。
考虑到技术指标和开发效率,我使用.net core作为服务器程序,SQL作为数据库解决方案。
.net core目前拥有完善的技术指标,能够提供其他开发平台无法比拟的开发效率。感谢整个.net技术体系,让我能够独立完成整个系统。
我使用SQL作为数据库,它可以与Core和.net core无缝集成,提供无与伦比的开发效率。同时,在数据处理性能方面,完全能够满足各项技术指标的要求。在日常使用和运维方面,也提供了无与伦比的便利性和工作效率。
我使用WPF框架作为客户端程序。与程序相比,WPF提供了更高的开发效率和更完整的基础框架,使屏幕呈现、数据处理和模块解耦变得更加容易。
同样,基于.net系统的WPF提供了其他开发平台无法提供的极高的开发效率。对于每天需要稳定运行十几个小时不退出的程序来说,原生客户端程序的稳定性是基于网页的程序无法比拟的。
上面我们提到系统可以水平扩展,并且具有弹性扩展的能力。初期可以在较低配置环境下运行。当用户增加时,可以水平扩展,不影响原有结构。或者它可能会由于服务规模的缩小而缩小。
下面我将从系统的整体结构来详细阐述这个问题:
从上图可以看出,这是一个典型的分布式部署系统。当嵌入客户网站的文件运行时,它首先连接到路由服务器。路由服务器保存一个表,其中包含每个站点应使用的应用程序服务器地址。

就像DNS服务器一样,告诉客户端网站应该在哪里发起真正的连接请求。
然后,嵌入客户网站的程序向相应的应用服务器发起连接,报告访客状态,并接收服务器指令。
很容易理解,我们只需要扩展我们的应用服务器的数量就可以轻松增加系统的承载能力。反之,也可以进行归约操作。
在处理客户私有化部署需求时,我们还可以根据实际需要取消路由服务器、文件服务器、CDN内容分发网络。
简单的解决方案,满足流量较小的中小企业的需求。在此基础上,我们还可以利用当前的云服务器实现灵活配置,从配置较低的服务器开始运行,甚至将数据库和缓存服务完全部署在一台服务器上。在使用过程中,我们发现确实有必要,首先添加单个服务器的配置。如果不能满足要求,则将数据库和缓存服务分离。如果仍不满足要求,请添加路由服务器并添加应用服务器。
消息传输
首先,我们回顾一下TCP协议。 TCP报文格式一般如下:
ACK 表示对消息是否已送达的响应。
ACK 是 TCP 标头中的一个标志和字段。发送消息至少需要一个标头,以及所有较低级别的内容。
下图展示了TCP通信时客户端和服务器之间消息传输的过程。
从图中可以看到,发送的消息和回复的消息都会带有编号,如:#1、#2
当ACK消息响应时,它返回收到的消息的编号。那么发送方只需根据收到的ACK消息中的编号判断消息是否已经送达即可。包。
如果在一定时间内没有收到响应的ACK消息,发送方将在一定时间内重试发送。
处理网络异常
这种情况最好处理一下。由于客户端程序异常退出,会直接抛出异常。
我们只需要在服务器端捕获这个异常并处理即可:
public bool Send(byte[] data)
{
// 连接已经断开了
try
{
_networkStream.Write(data, 0, data.Length);
}
catch (Exception ex)
{
OnDisconnected(ex);
return false;
}
return true;
}

对于这种情况,我们只需要检测对象的属性即可。
但需要特别注意的是:该对象的属性是从最后一次I/O操作中获取连接状态。当它返回时,它要么从未连接过,要么不再连接。当与另一个线程断开连接时,它可能会在操作中止后返回。
如果您需要确定连接的当前状态,请发出非阻塞零字节发送调用。
如果调用成功返回或引发错误代码(),则套接字仍处于连接状态;否则,套接字不再连接。
我们可以通过实现预定的心跳来检测网络链接:
_heartbeatTimer = new Timer((state) =>
{
HeartbeatMessage heartbeatMessage = new HeartbeatMessage();
Send(heartbeatMessage);
}, null, 3000, 3000);
当定时器发送心跳时,如果网络链路中断,我们可以收到以下消息:
private void _socketClient_Disconnected(object sender, EventArgs e)
{
if (_heartbeatTimer != null)
_heartbeatTimer.Dispose();
if (_socketClient != null)
{
_socketClient.Close();
_socketClient = null;
}
}
只需处理该事件并将两端的状态置于等待即可。
介绍一下.net开发的这个小系统
它可以跟踪所有正在访问网站或使用APP的访客,并收集他们的浏览状态,以便客服可以主动用他们的话来促进订单完成。 *客户端支持PC上所有新旧浏览器。即使不支持的IE8也能正常使用。
移动端支持与所有手机浏览器、APP、各大平台公众号对接。
支持访客信息交换,可将访客ID、姓名等任意信息传输至客服系统。
凭借一线专业技术,如果网络中断,拔掉网线,将手机调至飞行模式,消息不会丢失。类似的软件可以通过视频进行对比和测试。
我们希望创造:开放、开源、共享。努力为.net社区打造优秀的开源产品。
终于
如果您觉得这篇文章对您有帮助,请点赞支持!您的支持是我继续分享知识的动力。如果您有任何疑问或需要进一步帮助,请随时留言。您还可以加入微信公众号【技术工匠】社区,与其他热爱技术的同仁交流经验,共同成长!