网络开发高手请进,想问你们个netty服务器的问题

coding梦想_起点 2020-09-19 08:46:34
时隔N年,第二次在csdn发帖,不足之处,谢谢指正


由于笔者公司是做物联网这一块的,用到了tcp协议传递消息,笔者主要是负责tcp client这一块的开发,基本上逻辑很简单,连上服务器,发送认证,等待返回,如果成功、发送心跳、处理心跳返回,接受服务端的下发控制指令; 如果认证失败,超时后继续重连服务器,发送认证... 基本没有任何问题。如果说是客户端某些情况下无法重连服务器,那是客户端的bug。

就是服务端每次更新重启之后,大量客户端开始发送登录认证,就导致服务端出问题,表现现象如下:

1、有的客户端已经认证发送了,服务器也返回认证成功了,之后心跳都正常,服务端有时候显示设备还是离线,有时候显示在线,但是此时客户端不能收到任何服务器的控制消息,我说是服务端的问题,他说是我客户端的问题,根本扯不清
2、另外有这种情况,客户端拔掉电源,之后服务器重启,服务器显示设备还是在线,按理说,tcp服务重启之后,之前记录的所有的tcp会话id都没有意义了,所以一般不用持久化存储的对吧,都是保存在内存里面的吧,我不清楚为什么他们用的持久化存储



另外,不清楚那些诸如腾讯公司的qq、微信,包括认证,状态存储等等都是怎么tcp和服务器进行通讯的,先说说我们目前的设计问题点:


1、tcp消息传输限制在65535,因为他们设计的包头就两个字节,用的Netty分隔符解码器DelimiterBasedFrameDecoder,我个人觉得这样拆包效率太低,是不是应该考虑LengthFieldBasedFrameDecoder分包机制效率最高

2、tcp包运载效率太低,即使心跳包实际传输内容为空的情况下,还会产生62字节的数据包,因为他们要求每个tcp包都要把认证信息附带上,不清楚为什么这么做

3、按理说tcp只有第一次连接时候需要认证,之后只要当前tcp连接不断开,tcp会话id并不会发生变化,认证身份也不会发生变化,不需要每条消息都验证吧,个人觉得每次都校验数据包无故浪费大量服务器运算资源,也可能导致服务器在每次重启后瞬间根本处理不过来

4、他们所有tcp包数据做了xor运算,得到一个值,接收方每次都要计算一遍,但是不能实现加密,数据在公网上处于裸奔状态,另外tcp通讯已经实现可靠传输,个人觉得纯属多余

5、是不是应该考虑TLS加密,包括证书的认证,管理等等?
...全文
13296 15 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
一只三黄鸡 2020-11-16
  • 打赏
  • 举报
回复
猜测是服务端在重连或者收到消息后,处理在线/离线逻辑出错,因为既然心跳都应答了,为啥不是在线呢?也可能是服务端对设备的标识出错,例如:设备A本来现在,后来断电后再次重连,在服务端把它作为一台新的设备记录了
  • 打赏
  • 举报
回复
单片机的东西也做过,只是能力不足,甚至都跑不了LWIP协议栈,也许ST的几颗可以,配置稍微高些能跑个RTOS什么的,要么外挂PHY实现RJ45有线联网,很多ST单片机就是这么干的。 但是仍然无法通过wifi之类的联网,或许很多人都选择了外挂个什么ESP8266的玩意来实现联网,当然我说的是诸如8266,EMW3080之类的wifi模块,他们上面也跑的RTOS,也有LWIP,WiFi协议栈,可以实现联网,我说的主要是这上面的一些tcp/ip处理。 当然,一个MTU在很多路由器上也就1500撑死了,tcp/ip分隔符这种方式,真的就只适合小包通讯,不具有通用性,当然,很多人用的uart协议,那就分隔符做分包无疑了。
冰思雨 2020-11-02
  • 打赏
  • 举报
回复
引用 12 楼 coding梦想_起点 的回复:
“带分隔符的拆包效率应该高于带长度字段的数据包,因为运算相对简单”,这句话应该错了,分隔符导致程序在未知tcp数据流中检索特定分隔符,就要一个字节一个字节进行对比,不做逐个对比,你根本不知道分隔符什么时候到来。看看http的协议大概就明白了,只有header才使用回车换行这种作为分隔符,因为他header里面有content-length,就知道后续的包内容多长了,一次从buffer里面读取指定的content-length就可以了,不必遍历找分隔符,效率就很高。
楼主的眼界和观念,与我还是有着比较大的差别的。 我理解的物联网,里面是包含那种处理能力很低的单片机的,而且,绝大多数设备都是由单片机构成的。最重要的原因是控制生成成本。 带分隔符的通信协议里面,最大包长度是必须要规定的,通常要小于MTU。换句话说,如果通信协议是带分隔符的,那么指的就是小型的数据包的传输协议。 我实在想不出来,一个热水壶或者说是电饭锅,在什么样的情况下能一次向服务端发送100MB的数据过去。通常情况下,这种简单的设备,一次发送的数据量超过1K就算是比较超纲的数据包了。 楼主还是没太理解我对物联网的观念和看法,还是执着于更强计算性能的数据终端。楼主能聊一下你们公司,你负责的是什么类型的产品吗? 如果客户端是手机上面运行的,我就啥话都不说了。因为手机,PAD,PDA这种智能终端和服务端互联的项目,在我的观念里面,根本称不上是物联网,虽然它属于广义上的万物互联,但我是不认可的。 楼主做过单片机的开发吗?比如温度传感器每隔一分钟或者半分钟采集一次温度发送到服务端,一个温室大棚可能需要六个以上的温度湿度传感器。单片机的存储空间,如果是32K的都算是比较高级的了,每次交互的数据如果超过100字节都算是比较大的了。 你知道二层交换机吗?就是把你的电脑的网线和其他电脑以及路由器串在一起的设备,他们之间的通信就是采用带分隔符的数据包来进行的,当然MTU是必须设置的。 你知道带分隔符的数据包,有什么优点吗?非常适合串行通信和数据转发。 楼主在协议设计上面的经验,我觉得还是需要进行落地,要更亲民一些才好。在数据通信方面的协议里面,像楼主提到的100MB的那种大的数据包,我们一般都会有两种选择:A. 将大的拆分成为小的,分组进行传送,因为,我们要对传输进行控制。B.为这个大数据包单独发起一个连接进行传输,新连接不涉及分隔符什么的,就是纯数据,比如FTP协议就是这么搞的。主要的目的就是为了进行传输控制。 老实说,我是没有参与过物联网方面的项目的,所以,对物联网的眼界可能会有分歧。得罪之处,还请海涵。 我总觉得,物联网就是要解决万物互联。 万物要面临的最尖锐的问题应该就是把传统的物件变成一个数据采集终端(传感器+控制芯片), 互联要面临问题应该是与互联网的整合。 如果只是搞个科研的话,是不计成本的,但是,如果是搞生产的话,成本就是首先要关注的。 较高的计算能力,意味着更高的生产成本(无论硬件还是软件)。 我比较赞同在现在的大环境下,数据安全将会逐渐推向更重要的位置,如果硬件上面多几块钱就能解决这个问题的话,数据安全就不再成为问题。 之所以目前绝大多数的厂商都没有考虑数据安全(或者考虑的比较少)就是因为生产成本不是几块钱能解决的事儿。 数据安全是一个比较综合的领域,硬件软件传输协议都有涉及,在国内,做的最好的就是银行的POS支付系统,平常的支付信息是三层加密的,最核心的数据是五层加密的。我觉得一般的用户没有必要搞这么复杂。但是,做到什么样的程度,还是要看能给公司带来多大的价值,以及公司要投入多少成本了。
  • 打赏
  • 举报
回复
遇到这种极端的情况,最好的办法还是tcpdump抓包,在中间路由上进行抓包,这样服务器有没有返回数据,以及客户端发送的数据是否正常,都可以看到了; “带分隔符的拆包效率应该高于带长度字段的数据包,因为运算相对简单”,这句话应该错了,分隔符导致程序在未知tcp数据流中检索特定分隔符,就要一个字节一个字节进行对比,不做逐个对比,你根本不知道分隔符什么时候到来。看看http的协议大概就明白了,只有header才使用回车换行这种作为分隔符,因为他header里面有content-length,就知道后续的包内容多长了,一次从buffer里面读取指定的content-length就可以了,不必遍历找分隔符,效率就很高。 另外,如果接收100MB的tcp数据包,用分隔符的话,导致需要循环遍历上千万次,这其中的消耗是惊人的,另外不具有通用性,对传输的内容要做特定处理,比如转义,比较麻烦,分隔符这种方式,只适合小包通讯,对于大包,比如几十兆,几百兆,效率实在不要太低。 个人觉得物联网的大环境下,安全性必须首先考虑,tcp认证机制必须要加密,只要认证通过以后,数据包就不需要每次附带其他信息了,这样也可以进一步降低带宽的消耗。 目前tls1.2协议的确有很多不足,导致在嵌入式设备上性能不是很理想,不过很多wifi类产品都有AES硬件加速,所以接入诸如阿里云,中移动云什么的都可以实现加密传输,tls1.3目前还没有完全应用于生产环境,还需要一段时间。
冰思雨 2020-11-02
  • 打赏
  • 举报
回复
一说到物联网,我总是联想到单片机,已经成了潜意识了。 1. 遇到扯皮的事情,我一般会把多种情况都拆分开来进行解决。 A.登录认证成功了,心跳也正常了,但是,设备还是离线的,那说明,网关或者服务端出现了问题,这是很明显的,没必要扯皮。 B.登录认证成功了,心跳也正常了,设备也是在线的,但是,服务端处于僵尸状态,没有任何反馈,这个问题到底出在哪儿,不能武断的下结论,要先把场景重现出来,找客户端和服务端进行联调。以我的经验判断,如果客户端发送数据及时清空了发送缓冲区的话,大概率还是服务端的问题。 2.设备的状态(在线、离线),有的服务端保存在缓存中,有的服务端做了持久化操作,两种方式各有优点。 在缓存中的信息可以实时更新,但是,查询相对麻烦,我是说编程复杂度比较大,因为,一般情况下,和设备终端连接的服务端,那个玩意叫网关,只负责连接设备和转发数据(不同协议之间要进行转换),而查询设备状态的服务端会另外开发一套程序,有的是管理后台模式的,有的是网站形式的,两个服务端要建立数据通路才能把实时数据弄过来。如果进行了持久化,数据库就是这个通路了。但是,采用持久化方案就会产生网关重启(包括意外重启)状态没有进行重置的问题,如果系统由多个网关构成,那么,重置状态就不能由网关来做了,还要另外找一个单点服务,或者,分布式任务来定时的(或网关重启触发的)重置数据。 下面聊一下通信协议相关的事情: 1. 数据格式 A. 采用分隔符还是长度字段来区分数据包,各有优缺点。采用分隔符应该是考虑到组包拆包比较方便,降低了单片机的编程复杂度。带长度字段的数据包要测量包体的长度,组包拆包都比前者复杂。至于说拆包效率,带分隔符的拆包效率应该高于带长度字段的数据包,因为运算相对简单。 B. 认证信息,一般是由设备码(或者用户ID)和密码组成,以后的每个数据包一般都要带上设备码(或者用户ID),理论上可以不带,但是,带上有带上的好处。当然,密码就不要带了,带上密码就失去了认证的意义了。有的协议是在认证之后反回一个认证令牌,每次数据交互都带着令牌。作用都一样,就是识别终端设备(或者用户)。为啥非要带上设备码?因为有的系统,你看着是一个服务端,其实后面是一个服务器阵列,你这次交互的数据可能分给1号服务器来处理了,下一次交互的数据就分给别的服务器来处理了,为了容易识别客户端就带上了设备ID。所以说,理论上是可以不带的,因为认证成功后,TCP连接就代表了设备,但是,实际上,为了系统的扩展性,还是要带上设备ID。 C. 包尾的校验字段的作用有两个,一个是防止数据传输错误,当然,如果承载协议是TCP协议的话,可以不必考虑数据传输错误的问题。但是,有了这个校验码,在编程的时候就可以很方便的检查组包拆包数据是否存在人为的错误。另一个作用是防止网络入侵,就是说终端的数据先经过第三方的节点,将终端发送的某些数据更改后再转发到服务器,这个时候,校验码不失为一种防御手段,虽然很容易被破解。但是包尾校验码,一般在物联网的数据通信中(尤其是底层通信中)都是常常被采用的,可以很大概率的确保收到的数据不是被更改过的。相比数字签名的签名算法,异或(同或)算法是最简便的一种。 D. 为啥不考虑TLS加密,证书认证?主要原因还是因为单片机的计算能力,以及研发成本吧。物联网的概念里面就是万物互联。万物里面有PC机,PAD这种计算能力很强的设备,也有洗衣机,热水壶这种计算能力很低的设备,所以,在设计通信协议的时候,可能会考虑降低计算量和复杂度。 楼主的想法,可能是把客户端当成了PC机了吧,我感觉讨论的东西,都比较偏向于相对较复杂一些的应用程序开发,而且,有时候还觉得会造成服务端的计算过于复杂的问题。服务端,我觉得没有太大的必要降低计算复杂度,服务端可以优化代码或者优化架构,关键问题应该是怎样降低客户端或者说是数据终端的计算复杂度。等什么时候,所有的客户端都由操作系统构成,内存都2G开外了,那么,计算能力应该就可以适应一些复杂的计算了。我觉得这是一种趋势。但是对于更简单的数据终端而言,相对精简一些的通讯协议,更加适用。没有最完美的协议,只有更适合的协议。如果公司肯投钱,搞两种以上的协议也不是问题。
  • 打赏
  • 举报
回复
引用 9 楼 哈希塞特 的回复:
客户端应该没什么大问题,你们服务端的童鞋应该是写http写久了,所以每次传输数据都要带校验,你可以跟他解释下为什么校验一次就不用再校验了
应该是惯性思维,tcp只要连接认证成功,之后只要不断开会话,其实是不用验证的,每次都验证,消耗了大量的服务器计算资源,再说也不是银行这种高要求的环境,必须要OTP密码什么的都要加持上
哈希塞特 2020-10-29
  • 打赏
  • 举报
回复
客户端应该没什么大问题,你们服务端的童鞋应该是写http写久了,所以每次传输数据都要带校验,你可以跟他解释下为什么校验一次就不用再校验了
  • 打赏
  • 举报
回复
引用 7 楼 张层平 的回复:
要看下服务端有没有收到心跳,或者你客户端,有没有收到服务端的返回,如果有那就是他的状态问题。
客户端主动给服务器发送心跳,服务器有返回心跳,但是服务器没有显示设备在线,显然就是服务器的bug
  • 打赏
  • 举报
回复
引用 4 楼 张层平 的回复:
在不在线,主要判断不是服务端能不能收到对应的心跳包么?确认离线或者在线的时候有没有收发包应该就能找到问题了,多写点日志
客户端这边显示server的心跳回复都是正常的,但是server显示该设备不在线
书断华 2020-10-07
  • 打赏
  • 举报
回复
要看下服务端有没有收到心跳,或者你客户端,有没有收到服务端的返回,如果有那就是他的状态问题。
八爻老骥 2020-10-07
  • 打赏
  • 举报
回复
引用 5 楼 coding梦想_起点 的回复:
[quote=引用 4 楼 张层平 的回复:]在不在线,主要判断不是服务端能不能收到对应的心跳包么?确认离线或者在线的时候有没有收发包应该就能找到问题了,多写点日志


客户端这边显示server的心跳回复都是正常的,但是server显示该设备不在线[/quote]

那应该是服务端的处理逻辑的问题,没更新到状态缓存吧。
书断华 2020-10-06
  • 打赏
  • 举报
回复
在不在线,主要判断不是服务端能不能收到对应的心跳包么?确认离线或者在线的时候有没有收发包应该就能找到问题了,多写点日志
  • 打赏
  • 举报
回复
tcp分包拆包,个人觉得用分隔符的效率实在太低,看一下netty的解码器DelimiterBasedFrameDecoder的decode实现就知道了,用了for循环外加indexof进行查找,有对比有遍历,就会消耗大量cpu资源,这种分包方式只适合那种每次通讯都非常小的数据包,如果很大,效率就很低

如果每条数据包都校验的话,应该适用于银行交易那种高安全性的业务吧,一般应用都这样校验,客户端数量庞大情况下,开销是不是会非常大?

另外,在线离线状态的记录,我认为应该存储在内存数据库中,也可以用redis这种非持久的存储,因为会经常变化的,还做持久化存储,岂不是刻舟求剑吗

xor就是校验数据完整性,我想根本没必要,一般数据经过各级公网路由,如果不是明文,而是tls加密了,谁还能修改你的信息做重放攻击呢,是不太可能的,根据目前的国家防火墙对tcp流量,也只能做特征分析,没法拆出内容进行分析,tls目前至少说还是安全的

如果使用了tls加密,就没必要每个数据包都要token,只要tcp会话不断开,没有了重放,认证身份应该不会变化
tianfang 2020-09-20
  • 打赏
  • 举报
回复
1 看需求 2 信息包要求携带token吧,正常,识别客户端用啊 3 tcp连接会被中间设备伪造,仅仅token不够,数据最好使用token对应的otp(one time password)加密 4 xor是数据校验?单向验证数据正确性 5 如果用token和otp加密就没必要tls了,和tls效果差不多。 单向认证otp密码生成思路: 1 客户端提交客户端ID,时间戳和一个随机数,认证过程使用服务器公钥加密提交给服务器,服务器返回时间(客户端对时),token和服务器随机数 2 时间信息+客户端随机数+服务器随机数,形成otp密码, 3 客户端使用otp 对称密钥加密(如AES算法)
  • 打赏
  • 举报
回复
我觉得在tcp服务器重启一瞬间,不是客户端数量太多,处理不过来,而是已经处理过来了,不然怎么会给客户端回复认证成功的消息呢,个人猜测可能是tcp会话id的记录存储,设备在线/离线的状态记录这一块出了bug

67,549

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧