精华内容
下载资源
问答
  • UDP主要丢包原因及具体问题分析

    万次阅读 2015-08-28 00:20:44
    UDP主要丢包原因及具体问题分析   一、主要丢包原因   1、接收端处理时间过长导致丢包:调用recv方法接收端收到数据后,处理数据花了一些时间,处理完后再次调用recv方法,在这二次调用间隔里,发过来的包可能...

    文章来源:http://www.2cto.com/net/201311/254835.html

     

    UDP主要丢包原因及具体问题分析

     

    一、主要丢包原因

     

    1、接收端处理时间过长导致丢包:调用recv方法接收端收到数据后,处理数据花了一些时间,处理完后再次调用recv方法,在这二次调用间隔里,发过来的包可能丢失。对于这种情况可以修改接收端,将包接收后存入一个缓冲区,然后迅速返回继续recv。

     

    2、发送的包巨大丢包:虽然send方法会帮你做大包切割成小包发送的事情,但包太大也不行。例如超过50K的一个udp包,不切割直接通过send方法发送也会导致这个包丢失。这种情况需要切割成小包再逐个send。

     

    3、发送的包较大,超过接受者缓存导致丢包:包超过mtu size数倍,几个大的udp包可能会超过接收者的缓冲,导致丢包。这种情况可以设置socket接收缓冲。以前遇到过这种问题,我把接收缓冲设置成64K就解决了。

    int nRecvBuf=32*1024;//设置为32K

    setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));

     

    4、发送的包频率太快:虽然每个包的大小都小于mtu size 但是频率太快,例如40多个mut size的包连续发送中间不sleep,也有可能导致丢包。这种情况也有时可以通过设置socket接收缓冲解决,但有时解决不了。所以在发送频率过快的时候还是考虑sleep一下吧。

     

    5、局域网内不丢包,公网上丢包。这个问题我也是通过切割小包并sleep发送解决的。如果流量太大,这个办法也不灵了。总之udp丢包总是会有的,如果出现了用我的方法解决不了,还有这个几个方法: 要么减小流量,要么换tcp协议传输,要么做丢包重传的工作。

     

     

    二、具体问题分析

     

    1.发送频率过高导致丢包

     

    很多人会不理解发送速度过快为什么会产生丢包,原因就是UDP的SendTo不会造成线程阻塞,也就是说,UDP的SentTo不会像TCP中的SendTo那样,直到数据完全发送才会return回调用函数,它不保证当执行下一条语句时数据是否被发送。(SendTo方法是异步的)这样,如果要发送的数据过多或者过大,那么在缓冲区满的那个瞬间要发送的报文就很有可能被丢失。至于对“过快”的解释,作者这样说:“A few packets a second are not an issue; hundreds or thousands may be an issue.”(一秒钟几个数据包不算什么,但是一秒钟成百上千的数据包就不好办了)。 要解决接收方丢包的问题很简单,首先要保证程序执行后马上开始监听(如果数据包不确定什么时候发过来的话),其次,要在收到一个数据包后最短的时间内重新回到监听状态,其间要尽量避免复杂的操作(比较好的解决办法是使用多线程回调机制)。

     

    2.报文过大丢包

     

    至于报文过大的问题,可以通过控制报文大小来解决,使得每个报文的长度小于MTU。以太网的MTU通常是1500 bytes,其他一些诸如拨号连接的网络MTU值为1280 bytes,如果使用speaking这样很难得到MTU的网络,那么最好将报文长度控制在1280 bytes以下。

     

    3.发送方丢包

     

    发送方丢包:内部缓冲区(internal buffers)已满,并且发送速度过快(即发送两个报文之间的间隔过短);  接收方丢包:Socket未开始监听;  虽然UDP的报文长度最大可以达到64 kb,但是当报文过大时,稳定性会大大减弱。这是因为当报文过大时会被分割,使得每个分割块(翻译可能有误差,原文是fragmentation)的长度小于MTU,然后分别发送,并在接收方重新组合(reassemble),但是如果其中一个报文丢失,那么其他已收到的报文都无法返回给程序,也就无法得到完整的数据了。

     

    --------------------------------------------------------------------------------

    最近在研究linux下的UDP的传输,但是由于UDP协议本身的一些原因,在数据量非常大的时候会造成一定数量的丢包,数量越大,丢包率越高.

    为了解决丢包这个问题,我从网上查到了一些资料,大致可以从三个方面来解决这个问题.

    1. 从发送端解决(推荐)

    适用条件: ①发送端是可以控制的.②微秒数量级的延迟可以接受.

    解决方法:发送时使用usleep(1)延迟1微秒发送,即发送频率不要过快,延迟1微妙发送,可以很好的解决这个问题.

    2.从接收端解决方法一

    适用条件:①无法控制发送端发送数据的频率

    解决方法: 用recvfrom函数收到数据之后尽快返回,进行下一次recvfrom,可以通过多线程+队列来解决.收到数据之后将数据放入队列中,另起一个线程去处理收到的数据.

    3.从接收端解决方法二

    适用条件:①使用方法2依然出现大规模丢包的情况,需要进一步优化

    解决方法:使用setsockopt修改接收端的缓冲区大小,

     

    1. int rcv_size = 1024*1024; //1M

    2. int optlen=sizeof(rcv_size);

    3. int err=setsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char *)&rcv_size,optlen);//设置好缓冲区大小


    设置完毕可以通过

     

    setsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char *)&rcv_size,(socklen_t *)&optlen);

     

           来查看当前sock的缓冲区大小

    但是,会发现查到的大小并不是1M而是256kb,后来发现原来是linux系统默认缓冲区大小为128kb,设置最大是这个的2倍

    所以需要通过修改系统默认缓冲区大小来解决

    使用root账户在命令行下输入: 

    vi /etc/sysctl.conf

     

    添加一行记录(1049576=1024*1024=1M)

    net.core.rmem_max=1048576

     

    保存之后输入

    /sbin/sysctl -p

     

    使修改的配置生效

    此时可以通过 sysctl -a|grep rmem_max 来看配置是否生效. 

    生效之后可以再次运行程序来getsockopt看缓冲区是否变大了,是否还会出现丢包现象了

     

    楼主使用的是方法2+方法3 双管齐下,已经不会出现丢包现象了,如果还有不同程度的丢包 可以通过方法三种继续增加缓冲区大小的方式来解决

     

    --------------------------------------------------------------------------------

     

    UDP丢包

    我们是后一个包丢掉了

     

    最近在做一个项目,在这之前,做了个验证程序.
    发现客户端连续发来1000个1024字节的包,服务器端出现了丢包现象.
    纠其原因,是服务端在还未完全处理掉数据,客户端已经数据发送完毕且关闭了.

    有没有成熟的解决方案来解决这个问题.
    我用过sleep(1),暂时解决这个问题,但是这不是根本解决办法,如果数据量大而多,网络情况不太好的话,还是有可能丢失.

     

    你试着用阻塞模式吧...
    select...我开始的时候好像也遇到过..不过改为阻塞模式后就没这个问题了...

     

    采用回包机制,每个发包必须收到回包后再发下一个

     

    UDP丢包是正常现象,因为它是不安全的。

     

    丢包的原因我想并不是“服务端在还未完全处理掉数据,客户端已经数据发送完毕且关闭了”,而是服务器端的socket接收缓存满了(udp没有流量控制,因此发送速度比接收速度快,很容易出现这种情况),然后系统就会将后来收到的包丢弃。你可以尝试用setsockopt()将接收缓存(SO_RCVBUF)加大看看能不能解决问题。

     

    服务端采用多线程pthread接包处理

     

    UDP是无连接的,面向消息的数据传输协议,与TCP相比,有两个致命的缺点,一是数据包容易丢失,二是数据包无序。
    要实现文件的可靠传输,就必须在上层对数据丢包和乱序作特殊处理,必须要有要有丢包重发机制和超时机制。
    常见的可靠传输算法有模拟TCP协议,重发请求(ARQ)协议,它又可分为连续ARQ协议、选择重发ARQ协议、滑动窗口协议等等。
    如果只是小规模程序,也可以自己实现丢包处理,原理基本上就是给文件分块,每个数据包的头部添加一个唯一标识序号的ID值,当接收的包头部ID不是期望中的ID号,则判定丢包,将丢包ID发回服务端,服务器端接到丢包响应则重发丢失的数据包。
    模拟TCP协议也相对简单,3次握手的思想对丢包处理很有帮助。

     

    udp是不安全的,如果不加任何控制,不仅会丢失包,还可能收到包的顺序和发送包的顺序不一样。这个必须在自己程序中加以控制才行。
    收到包后,要返回一个应答,如果发送端在一定时间内没有收到应答,则要重发。

    UDP本来存在丢包现象,现在的解决方案暂时考虑双方增加握手.
    这样做起来,就是UDP协议里面加上了TCP的实现方法.
    程序中采用的是pthread处理,丢包率时大时小,不稳定可靠

     

    我感觉原因可能有两个,一个是客户端发送过快,网络状况不好或者超过服务器接收速度,就会丢包。
    第二个原因是服务器收到包后,还要进行一些处理,而这段时间客户端发送的包没有去收,造成丢包。

    解决方法,一个是客户端降低发送速度,可以等待回包,或者加一些延迟。
    二是,服务器部分单独开一个线程,去接收UDP数据,存放在一个缓冲区中,又另外的线程去处理收到的数据,尽量减少因为处理数据延时造成的丢包。

     

    有两种方法解决楼主的问题:
    方法一:重新设计一下协议,增加接收确认超时重发。(推荐)
    方法二:在接收方,将通信和处理分开,增加个应用缓冲区;如果有需要增加接收socket的系统缓冲区。(本方法不能从根本解决问题,只能改善)

     

    网络丢包,是再正常不过的了。
    既然用UDP,就要接受丢包的现实,否则请用TCP。
    如果必须使用UDP,而且丢包又是不能接受的,只好自己实现确认和重传,说白了,就是自己实现TCP(当然是部分和有限的简单实现)。

     

    UDP是而向无连接的,用户在实施UDP编程时,必须制定上层的协议,包括流控制,简单的超时和重传机制,如果不要求是实时数据,我想TCP可能会更适合你!

     

    -------------------------

    1:什么是丢包率? 

    你的电脑向目标发送一个数据包,如果对方没有收到.就叫丢包. 
    比如你发10个,它只收到9个. 那么丢包率就是 10% 
    数据在网络中是被分成一各个个数据报传输的,每个数据报中有表示数据信息和提供数据路由的桢.而数据报在一般介质中传播是总有一小部分由于两个终端的距离过大会丢失,而大部分数据包会到达目的终端.所谓网络丢包率是数据包丢失部分与所传数据包总数的比值.正常传输时网络丢包率应该控制在一定范围内.

    2:什么是吞吐量?
    网络中的数据是由一个个数据包组成,防火墙对每个数据包的处理要耗费资源。吞吐量是指在没有帧丢失的情况下,设备能够接受的最大速率。其测试方法是:在测试中以一定速率发送一定数量的帧,并计算待测设备传输的帧,如果发送的帧与接收的帧数量相等,那么就将发送速率提高并重新测试;如果接收帧少于发送帧则降低发送速率重新测试,直至得出最终结果。吞吐量测试结果以比特/秒或字节/秒表示。

    吞吐量和报文转发率是关系防火墙应用的主要指标,一般采用FDT(Full Duplex Throughput)来衡量,指64字节数据包的全双工吞吐量,该指标既包括吞吐量指标也涵盖了报文转发率指标。 

    随着Internet的日益普及,内部网用户访问Internet的需求在不断增加,一些企业也需要对外提供诸如WWW页面浏览、FTP文件传输、DNS域名解析等服务,这些因素会导致网络流量的急剧增加,而防火墙作为内外网之间的唯一数据通道,如果吞吐量太小,就会成为网络瓶颈,给整个网络的传输效率带来负面影响。因此,考察防火墙的吞吐能力有助于我们更好的评价其性能表现。这也是测量防火墙性能的重要指标。

    吞吐量的大小主要由防火墙内网卡,及程序算法的效率决定,尤其是程序算法,会使防火墙系统进行大量运算,通信量大打折扣。因此,大多数防火墙虽号称100M防火墙,由于其算法依靠软件实现,通信量远远没有达到100M,实际只有10M-20M。纯硬件防火墙,由于采用硬件进行运算,因此吞吐量可以达到线性90-95M,是真正的100M防火墙。

    对于中小型企业来讲,选择吞吐量为百兆级的防火墙即可满足需要,而对于电信、金融、保险等大公司大企业部门就需要采用吞吐量千兆级的防火墙产品。

    3:检测丢包率
    下载一个世纪前线,在百度可以找到,很小的程序。

    NetIQ Chariot  一款网络应用软件性能测试工具

    网络吞吐量测试,CHARIOT测试网络吞吐量

    http://wenku.baidu.com/link?url=JgKLSru8LBtaqxTIwAzJHAn-S-rhqZQgO1FQB_snRK5n3GYUFFhO9pQJs3bjyxWenH-rFv_H5qm7ke3mfcGK3MDFDO23zTf05GoLs2S7O8O

    展开全文
  • 目标检测存在问题总结

    千次阅读 2019-11-22 09:49:24
    目标检测存在问题总结 作者:种树的左耳 链接:https://www.zhihu.com/question/280703314/answer/564235579 1.从专注精度的Faster RCNN、RFCN相关系列,以及专注速度的YOLO系列,未来的方向更专注于精度和速度的...

    目标检测存在的问题总结

    作者:种树的左耳
    链接:https://www.zhihu.com/question/280703314/answer/564235579

    1.从专注精度的Faster RCNN、RFCN相关系列,以及专注速度的YOLO系列,未来的方向更专注于精度和速度的结合,这也是过去的很多模型在SSD系列上产生的原因,主要代表有RefineDet、RFBNet等。所以SSD系列的研究会成为主流。

    2.目标选框从Region Based 和Anchor Based到基于角点,甚至是基于segmentation,包括semantic segmentation 和 instance segmentation 。今年比较有代表的CornerNet和Grid RCNN是一个开拓思路的方向,细节就不用说了吧。。。未来的目标选框方法依旧是研究的一个重要方向。

    3.多尺度问题(尺度变换问题),目前常见的三种思路,采用专门设计的尺度变换模块,可以参考STDN: Scale-Transferrable Object Detection。多个scale的目标检测设计,没记错的话之前有在Faster RCNN基础上,做多个scale的rpn。当然最新的SNIP也是多个RPN。还有就是SNIPER,先用SNIPER的模块进行一个粗检测,检测出多个scale关注区域,然后再进行细检测。目前的问题是,如果是才有scale transfer moudle的话,可能会丢失一些信息,也就是多scale融合学习存在问题,那么如何设计一个单scale模型transfer moudle进行有效学习,这一点我是存疑的,总感觉这个多scale融合哪里存在问题。同时,采用多scale的先初步多scale检测再细检测会增加计算时间,如何有效的将两个模块进行结合,进行进一步的再设计是未来一个重点。

    4.重新思考目标检测的训练,凯明今年的新作Rethinking imagenet pre-training已经验证了一个问题,pre-training再training和training from scratch这一点在目标检测问题理论上也是适用的。当目标检测数据集达到一定规模,目标选框问题是否可以单独抽离出来,做好更精确的选框预训练,再在具体的数据集上主要进行选框适应性训练和分类训练?另外由于目前的目标检测backbone网络都是从图像分类网络过来的,图像分类网络之前的提法是尺度不变性,而目标检测有尺度变化性,今年清华的一篇文章就是做了这个问题,设计了一个专门针对目标检测问题的backbone,但是还是基于ImgNet进行了预训练,那么不在ImgNet进行预训练是否可行?另外如何从一个小的数据集上进行一个转向任务的无预训练的学习 or 有预训练的小规模数据学习训练。目标检测的小规模数据训练是在实际工程应用中,尤其是工业化场景中一个比较需要关注的问题。

    5.重新思考卷积神经网络的旋转不变性和尺度变化,有一些我在上面已经提到了,从一些论文的研究表明,卷积神经网络的旋转不变性似乎是一个伪命题,卷积网络的旋转不变性主要是通过数据的增强和大样本的学习获取的,本身应该不具备旋转不变性。这个问题我看一些研究者提到过,我的感觉是应该是不具备旋转不变性的,可能需要进行进一步的研究进行分析。旋转不变性和尺度变化会影响目标检测算法的基本框架。

    6.目标检测以及深度学习的分割、关键点检测、跟踪都需要在数据标注上耗费巨大的成本,如何采用算法进行更有效的标注是一个核心的问题,包括上面4中提到的如何用更少的样本进行学习是关键。如果不能进行无监督的话,那么小规模数据的监督学习如何更有效进行训练达到大幅度精度提升将会是研究的重点。还有就是采用单图像单类别的弱标注,不进行选框标注,通过对大型目标检测数据集进行预训练,然后在这种单类单图像场景进行弱监督多类检测学习,进而泛化到多类单图像检测。

    7.IOU的算法设计和阈值的选择,今年比较有特点的是IOUNet和Cascade RCNN。

    8.更好的NMS。

    1. one shot learning,我看来一个样本和小样本的数据增强和学习,也会有一些有意思的研究。参考评论里面的提到的参考文章:LSTD: A Low-Shot Transfer Detector for Object Detection 发表在AAAI2018。

    10.如何实现未知目标类的检测,也就是我们常说的zero shot learning。从结合语义等信息从已知类别的目标检测,迁移到对未知类别的目标进行检测。参考论文Zero-Shot Object Detection(ECCV2018)。

    11.如何从已经训练的模型去迁移到新增数据、新增类别的学习,也就是增量学习(Incremental Learning)。可以参考的论文有Incremental Learning of Object Detectors without Catastrophic Forgetting(ICCV2017)目标检测的论文以及End-to-End Incremental Learning(ECCV2018)。

    1. CNN、Pooling、Loss 目前都有各种各样的变体,更有效的CNN、Pooling、Loss依旧会出现。

    13.将目标检测方法的一些研究迁移到SOT(Single Object Tracking)和MOT(Multiple Object Tracking),可以有效的观察到今年表现比较好的SOT算法和MOT算法都有和检测的结合出现。单目标跟踪可参考商汤和中科院计算所的SiameseRPN:High Performance Visual Tracking with Siamese Region Proposal Network(CVPR2018)以及最新的SiamRPN++: Evolution of Siamese Visual Tracking with Very Deep Networks(刚刚发布)。多目标跟踪可参考清华艾海舟组的REAL-TIME MULTIPLE PEOPLE TRACKING WITH DEEPLY LEARNED CANDIDATE SELECTION AND PERSON RE-IDENTIFICATION(CVPR2018)

    14.目标检测的FineGrained问题。

    15.模型的轻量级化,从目前的轻量级网络对于计算资源的压缩上,主要是集中在对于backebone的压缩,那么对于模型整体上针对目标检测的考虑进行再设计是否可行?

    16.大尺寸图像的目标检测问题,目前很多检测的基本主要集中在512x512和1000x600左右的图像操作,但是在未来,4k图像和视频会成为主流,大尺寸图像的目标检测、跟踪都会成为主流,今年CVPR2018有一篇文章Dynamic Zoom-in Network for Fast Object Detection in Large Images是进行大尺寸图像的目标检测,主要是做的2k,设计了一个粗检测和精细检测的模块。所以针对大尺度的图像如何进行计算资源的压缩、有效的目标检测or跟踪是一个非常有前瞻性的研究工作。尤其是未来的网络电视剧、电影、短视频会出现更多的4k内容。

    17.AR场景下的跨类检测融合,这个属于我的想象,一个简单的比如是AR眼镜会跟人类的眼睛一样的视野。那么在这个场景下对于视觉获取内容的有效提取包括图像里面就包括文字、商标、各类目标等等内容的融合检测。

    18.3d 激光雷达lidar和深度相机的目标检测,在自动驾驶这一块用的比较多,但是更精细的应用场景还是很多的,还有很多的应用场景比如裁判之类的要求更精细化的检测(包括关键点检测分割之类的)。

    19.视频流的检测,主要是应用到移动端场景的手机或者FPGA。由于视频流的图片信息具有时间和空间相关性,相邻帧之间的特城提取网络会输出有冗余的特征图信息,会造成没必要的计算浪费。同时图片的目标检测算法在目标物体运动模糊,拍摄焦距失调,物体部分遮挡,非刚性物体罕见变形姿态的情况下,很难获得较为准确的结果。同时权衡精度、计算时间以及计算资源变得尤为重要。可参考论文包括Towards High Performance Video Object Detection for Mobiles(Arxiv Tech Report 2018)、Towards High Performance Video Object Detection(CVPR2018)、Fully Motion-Aware Network for Video Object Detection(ECCV2018),ECCV2018和CVPR2018都有两三篇,主要贴一下Jifeng Dai的工作,其它就不贴了。。。

    展开全文
  • 空指针异常主要原因以及解决方案

    千次阅读 2020-03-23 00:14:44
    空指针异常产生的主要原因如下: (1)当一个对象不存在时又调用其方法会产生异常obj.method() // obj对象不存在 (2)当访问或修改一个对象不存在的字段时会产生异常obj.method() // method方法不存在 (3)字符串...

    空指针异常产生的主要原因如下:

    (1)当一个对象不存在时又调用其方法会产生异常obj.method() // obj对象不存在
    (2)当访问或修改一个对象不存在的字段时会产生异常obj.method() // method方法不存在
    (3)字符串变量未初始化;
    (4)接口类型的对象没有用具体的类初始化,比如:
    List a;会报错
    List a = new ArrayList();则不会报错了
    当一个对象的值为空时,你没有判断为空的情况。你可以试着把下面的代码前加一行代码:
    if(rb!=null && rb!="")
    改成:
    if(rb==null);
    if(rb!==null&&rb!="") 或者if((“”).equals(rb))
    空指针的解决办法:
    重点关注报错发生的所在行,通过空指针异常产生的两条主要原因诊断具体的错误。
    同时为了避免空指针的发生,最好在做判断处理时将“null”或者空值放于设定的值之前。

    另:
    Java 中任何对象都有可能为空,当我们调用空对象的方法时就会抛出 NullPointerException 空指针异常,这是一种非常常见的错误类型。我们可以使用若干种方法来避免产生这类异常,使得我们的代码更为健壮。本文将列举这些解决方案,包括传统的空值检测、编程规范、以及使用现代 Java 语言引入的各类工具来作为辅助。

    运行时检测

    最显而易见的方法就是使用 if (obj == null) 来对所有需要用到的对象来进行检测,包括函数参数、返回值、以及类实例的成员变量。当你检测到 null 值时,可以选择抛出更具针对性的异常类型,如 IllegalArgumentException,并添加消息内容。我们可以使用一些库函数来简化代码,如 Java 7 开始提供的 Objects#requireNonNull 方法:

    public void testObjects(Object arg) {
      Object checked = Objects.requireNonNull(arg, "arg must not be null");
      checked.toString();
    }
    

    Guava 的 Preconditions 类中也提供了一系列用于检测参数合法性的工具函数,其中就包含空值检测:

    public void testGuava(Object arg) {
      Object checked = Preconditions.checkNotNull(arg, "%s must not be null", "arg");
      checked.toString();
    }
    

    我们还可以使用 Lombok 来生成空值检测代码,并抛出带有提示信息的空指针异常:

    public void testLombok(@NonNull Object arg) {
      arg.toString();
    }
    

    生成的代码如下:

    public void testLombokGenerated(Object arg) {
      if (arg == null) {
        throw new NullPointerException("arg is marked @NonNull but is null");
      }
      arg.toString();
    }
    

    这个注解还可以用在类实例的成员变量上,所有的赋值操作会自动进行空值检测。

    编程规范

    通过遵守某些编程规范,也可以从一定程度上减少空指针异常的发生。

    使用那些已经对 null 值做过判断的方法,如 String#equals、String#valueOf、以及三方库中用来判断字符串和集合是否为空的函数:

    if (str != null && str.equals("text")) {}
    if ("text".equals(str)) {}
    
    if (obj != null) { obj.toString(); }
    String.valueOf(obj); // "null"
    
    // from spring-core
    StringUtils.isEmpty(str);
    CollectionUtils.isEmpty(col);
    // from guava
    Strings.isNullOrEmpty(str);
    // from commons-collections4
    CollectionUtils.isEmpty(col);
    

    如果函数的某个参数可以接收 null 值,考虑改写成两个函数,使用不同的函数签名,这样就可以强制要求每个参数都不为空了:

    public void methodA(Object arg1) {
      methodB(arg1, new Object[0]);
    }
    
    public void methodB(Object arg1, Object[] arg2) {
      for (Object obj : arg2) {} // no null check
    }
    

    如果函数的返回值是集合类型,当结果为空时,不要返回 null 值,而是返回一个空的集合;如果返回值类型是对象,则可以选择抛出异常。Spring JdbcTemplate 正是使用了这种处理方式:

    // 当查询结果为空时,返回 new ArrayList<>()
    jdbcTemplate.queryForList("SELECT * FROM person");
    
    // 若找不到该条记录,则抛出 EmptyResultDataAccessException
    jdbcTemplate.queryForObject("SELECT age FROM person WHERE id = 1", Integer.class);
    
    // 支持泛型集合
    public <T> List<T> testReturnCollection() {
      return Collections.emptyList();
    }
    

    静态代码分析

    Java 语言有许多静态代码分析工具,如 Eclipse IDE、SpotBugs、Checker Framework 等,它们可以帮助程序员检测出编译期的错误。结合 @Nullable 和 @Nonnull 等注解,我们就可以在程序运行之前发现可能抛出空指针异常的代码。

    但是,空值检测注解还没有得到标准化。虽然 2006 年 9 月社区提出了 JSR 305 规范,但它长期处于搁置状态。很多第三方库提供了类似的注解,且得到了不同工具的支持,其中使用较多的有:

    javax.annotation.Nonnull:由 JSR 305 提出,其参考实现为 com.google.code.findbugs.jsr305;
    org.eclipse.jdt.annotation.NonNull:Eclipse IDE 原生支持的空值检测注解;
    edu.umd.cs.findbugs.annotations.NonNull:SpotBugs 使用的注解,基于 findbugs.jsr305;
    org.springframework.lang.NonNull:Spring Framework 5.0 开始提供;
    org.checkerframework.checker.nullness.qual.NonNull:Checker Framework 使用;
    android.support.annotation.NonNull:集成在安卓开发工具中;
    我建议使用一种跨 IDE 的解决方案,如 SpotBugs 或 Checker Framework,它们都能和 Maven 结合得很好。

    SpotBugs 与 @NonNull、@CheckForNull

    SpotBugs 是 FindBugs 的后继者。通过在方法的参数和返回值上添加 @NonNull 和 @CheckForNull 注解,SpotBugs 可以帮助我们进行编译期的空值检测。需要注意的是,SpotBugs 不支持 @Nullable 注解,必须用 @CheckForNull 代替。如官方文档中所说,仅当需要覆盖 @ParametersAreNonnullByDefault 时才会用到 @Nullable。

    官方文档 中说明了如何将 SpotBugs 应用到 Maven 和 Eclipse 中去。我们还需要将 spotbugs-annotations 加入到项目依赖中,以便使用对应的注解。

    <dependency>
        <groupId>com.github.spotbugs</groupId>
        <artifactId>spotbugs-annotations</artifactId>
        <version>3.1.7</version>
    </dependency>
    

    以下是对不同使用场景的说明:

    @NonNull
    private Object returnNonNull() {
      // 错误:returnNonNull() 可能返回空值,但其已声明为 @Nonnull
      return null;
    }
    
    @CheckForNull
    private Object returnNullable() {
      return null;
    }
    
    public void testReturnNullable() {
      Object obj = returnNullable();
      // 错误:方法的返回值可能为空
      System.out.println(obj.toString());
    }
    
    private void argumentNonNull(@NonNull Object arg) {
      System.out.println(arg.toString());
    }
    
    public void testArgumentNonNull() {
      // 错误:不能将 null 传递给非空参数
      argumentNonNull(null);
    }
    
    public void testNullableArgument(@CheckForNull Object arg) {
      // 错误:参数可能为空
      System.out.println(arg.toString());
    }
    

    对于 Eclipse 用户,还可以使用 IDE 内置的空值检测工具,只需将默认的注解 org.eclipse.jdt.annotation.Nullable 替换为 SpotBugs 的注解即可:

    Checker Framework 与 @NonNull、@Nullable

    Checker Framework 能够作为 javac 编译器的插件运行,对代码中的数据类型进行检测,预防各类问题。我们可以参照 官方文档,将 Checker Framework 与 maven-compiler-plugin 结合,之后每次执行 mvn compile 时就会进行检查。Checker Framework 的空值检测程序支持几乎所有的注解,包括 JSR 305、Eclipse、甚至 lombok.NonNull。

    import org.checkerframework.checker.nullness.qual.Nullable;
    
    @Nullable
    private Object returnNullable() {
      return null;
    }
    
    public void testReturnNullable() {
      Object obj = returnNullable();
      // 错误:obj 可能为空
      System.out.println(obj.toString());
    }
    

    Checker Framework 默认会将 @NonNull 应用到所有的函数参数和返回值上,因此,即使不添加这个注解,以下程序也是无法编译通过的:

    private Object returnNonNull() {
      // 错误:方法声明为 @NonNull,但返回的是 null。
      return null;
    }
    
    private void argumentNonNull(Object arg) {
      System.out.println(arg.toString());
    }
    
    public void testArgumentNonNull() {
      // 错误:参数声明为 @NonNull,但传入的是 null。
      argumentNonNull(null);
    }
    

    Checker Framework 对使用 Spring Framework 5.0 以上的用户非常有用,因为 Spring 提供了内置的空值检测注解,且能够被 Checker Framework 支持。一方面我们无需再引入额外的 Jar 包,更重要的是 Spring Framework 代码本身就使用了这些注解,这样我们在调用它的 API 时就能有效地处理空值了。举例来说,StringUtils 类里可以传入空值的函数、以及会返回空值的函数都添加了 @Nullable 注解,而未添加的方法则继承了整个框架的 @NonNull 注解,因此,下列代码中的空指针异常就可以被 Checker Framework 检测到了:

    // 这是 spring-core 中定义的类和方法
    public abstract class StringUtils {
      // str 参数继承了全局的 @NonNull 注解
      public static String capitalize(String str) {}
    
      @Nullable
      public static String getFilename(@Nullable String path) {}
    }
    
    // 错误:参数声明为 @NonNull,但传入的是 null。
    StringUtils.capitalize(null);
    
    String filename = StringUtils.getFilename("/path/to/file");
    // 错误:filename 可能为空。
    System.out.println(filename.length());
    

    Optional 类型

    Java 8 引入了 Optional 类型,我们可以用它来对函数的返回值进行包装。这种方式的优点是可以明确定义该方法是有可能返回空值的,因此调用方必须做好相应处理,这样也就不会引发空指针异常。但是,也不可避免地需要编写更多代码,而且会产生很多垃圾对象,增加 GC 的压力,因此在使用时需要酌情考虑。

    Optional<String> opt;
    
    // 创建
    opt = Optional.empty();
    opt = Optional.of("text");
    opt = Optional.ofNullable(null);
    
    // 判断并读取
    if (opt.isPresent()) {
      opt.get();
    }
    
    // 默认值
    opt.orElse("default");
    opt.orElseGet(() -> "default");
    opt.orElseThrow(() -> new NullPointerException());
    
    // 相关操作
    opt.ifPresent(value -> {
      System.out.println(value);
    });
    opt.filter(value -> value.length() > 5);
    opt.map(value -> value.trim());
    opt.flatMap(value -> {
      String trimmed = value.trim();
      return trimmed.isEmpty() ? Optional.empty() : Optional.of(trimmed);
    });
    

    方法的链式调用很容易引发空指针异常,但如果返回值都用 Optional 包装起来,就可以用 flatMap 方法来实现安全的链式调用了:

    String zipCode = getUser()
        .flatMap(User::getAddress)
        .flatMap(Address::getZipCode)
        .orElse("");
    

    Java 8 Stream API 同样使用了 Optional 作为返回类型:

    stringList.stream().findFirst().orElse("default");
    stringList.stream()
        .max(Comparator.naturalOrder())
        .ifPresent(System.out::println);
    

    此外,Java 8 还针对基础类型提供了单独的 Optional 类,如 OptionalInt、OptionalDouble 等,在性能要求比较高的场景下很适用。

    其它 JVM 语言中的空指针异常

    Scala 语言中的 Option 类可以对标 Java 8 的 Optional。它有两个子类型,Some 表示有值,None 表示空。

    val opt: Option[String] = Some("text")
    opt.getOrElse("default")
    

    除了使用 Option#isEmpty 判断,还可以使用 Scala 的模式匹配:

    opt match {
      case Some(text) => println(text)
      case None => println("default")
    }
    

    Scala 的集合处理函数库非常强大,Option 则可直接作为集合进行操作,如 filer、map、以及列表解析(for-comprehension):

    opt.map(_.trim).filter(_.length > 0).map(_.toUpperCase).getOrElse("DEFAULT")
    val upper = for {
      text <- opt
      trimmed <- Some(text.trim())
      upper <- Some(trimmed) if trimmed.length > 0
    } yield upper
    upper.getOrElse("DEFAULT")
    

    Kotlin 使用了另一种方式,用户在定义变量时就需要明确区分 可空和不可空类型。当可空类型被使用时,就必须进行空值检测。

    var a: String = “text”
    a = null // 错误:无法将 null 赋值给非空 String 类型。

    val b: String? = “text”
    // 错误:操作可空类型时必须使用安全操作符(?.)或强制忽略(!!.)。
    println(b.length)

    val l: Int? = b?.length // 安全操作
    b!!.length // 强制忽略,可能引发空值异常

    Kotlin 的特性之一是与 Java 的可互操作性,但 Kotlin 编译器无法知晓 Java 类型是否为空,这就需要在 Java 代码中使用注解了,而 Kotlin 支持的 注解 也非常广泛。Spring Framework 5.0 起原生支持 Kotlin,其空值检测也是通过注解进行的,使得 Kotlin 可以安全地调用 Spring Framework 的所有 API。

    结论

    在以上这些方案中,我比较推荐使用注解来预防空指针异常,因为这种方式十分有效,对代码的侵入性也较小。所有的公共 API 都应该使用 @Nullable 和 @NonNull 进行注解,这样就能强制调用方对空指针异常进行预防,让我们的程序更为健壮。

    参考资料

    https://howtodoinjava.com/java/exception-handling/how-to-effectively-handle-nullpointerexception-in-java/
    http://jmri.sourceforge.net/help/en/html/doc/Technical/SpotBugs.shtml
    https://dzone.com/articles/features-to-avoid-null-reference-exceptions-java-a
    https://medium.com/@fatihcoskun/kotlin-nullable-types-vs-java-optional-988c50853692

    ———————————
    版权声明:本文为CSDN博主「薄荷脑」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/zjerryj/article/details/82817626

    展开全文
  • web应用存在的10大安全问题

    千次阅读 2018-11-04 22:00:27
    1 在web应用程序中是什么导致安全性问题呢?一般有以下几个原因 1、复杂应用系统代码量大、开发人员多、难免出现疏忽 2、系统屡次升级、人员频繁变更,导致代码不一致 3、历史遗留系统、试运行系统等多个Web系统...

     1 在web应用程序中是什么导致安全性问题呢?一般有以下几个原因

    1、复杂应用系统代码量大、开发人员多、难免出现疏忽
    2、系统屡次升级、人员频繁变更,导致代码不一致
    3、历史遗留系统、试运行系统等多个Web系统共同运行于同一台服务器上
    4、开发人员未经过安全编码培训或者公司根本就没有统一的安全编码规范
    5、测试人员经验不足或者没经过专业的安全评估测试就发布上线
    6、没有对用户的输入进行验证:
    1)永远不要信任用户的输入,要对用户的输入进行校验
    2)数字型的输入必须是合法的数字
    3)字符型的输入中对 编码符号要进行特殊处理
    4)验证所有的输入点,包括Get,Post,Cookie以及其他HTTP头

     

     2  web应用通常存在的10大安全问题

    1、SQL注入
    拼接的SQL字符串改变了设计者原来的意图,执行了如泄露、改变数据等操作,甚至控制数据库
    服务器, SQL Injection与Command Injection等攻击包括在内

    2、跨站脚本攻击(XSS或css)

    跨站脚本(Cross-Site Scripting)是指远程WEB页面的html代码可以插入具有恶意目的的数据,当
    浏览器下载该页面,嵌入其中的恶意脚本将被解释执行,从而对客户端用户造成伤害。简称CSS
    或XSS
    3、没有限制URL访问

    系统已经对URL的访问做了限制,但这种限制却实际并没有生效。攻击者能够很容易的就伪造
    请求直接访问未被授权的页面

    4、越权访问

    用户对系统的某个模块或功能没有权限,通过拼接URL或Cookie欺骗来访问该模块或功能

    5、泄露配置信息

    服务器返回的提示或错误信息中出现服务器版本信息泄露、程序出错泄露物理路径、程序查询
    出错返回SQL语句、过于详细的用户验证返回信息。

    6、不安全的加密存储

    常见的问题是不安全的密钥生成和储存、不轮换密钥,和使用弱算法。使用弱的或者不带salt 
    的哈希算法来保护密码也很普遍。外部攻击者因访问的局限性很难探测这种漏洞。他们通常
    必须首先破解其他东西以获得需要的访问。

    7、传输层保护不足

    在身份验证过程中没有使用SSL / TLS,因此暴露传输数据和会话ID,被攻击者截听,或使
    用过期或者配置不正确的证书。

    8、登录信息提示

    用户登录提示信息会给攻击者一些有用的信息,作为程序的开发人员应该做到对登录提示信
    息的模糊化,以防攻击者利用登录得知用户是否存在

    9、重复提交请求

    程序员在代码中没有对重复提交请求做限制,这样就会出现订单被多次下单,帖子被重
    复发布。恶意攻击者可能利用此漏洞对网站进行批量灌水,致使网站瘫痪

    10、网页脚本错误

    访问者所使用的浏览器不能完全支持页面里的脚本,形成“脚本错误”,也就是网站中的脚
    本没有被成功执行。遇到“脚本错误”时一般会弹出一个非常难看的脚本运行错误警告窗口

    展开全文
  • 在Android所有系统自带的控件当中,ListView这...遇到这个问题时,不少人在网上搜索找到了相应的解决方案,但是真正深入理解这个问题出现的原因并对症解决的人恐怕还并不是很多。那么今天我们就来具体深入分析一下ListV
  • 并发控制中存在问题及解决方案

    万次阅读 2018-10-17 21:59:03
    一、并发控制定义 在数据库中,并发控制是指在多个用户/进程/线程同时对数据库进行操作时,保证事务的一致性和隔离性,同时最大程度地并发。并发控制的目的是保证一...不存在任何问题 2、读-写 有隔离性问题,可...
  • 好长时间没写过博客啦,对不起CSDN给的‘恒’标签啦,嘿嘿现在项目前端框架在...但项目原因,暂时就是这俩东西结合使用,具体原因不讨论,只讨论结合存在问题,我相信不只我们项目遇到这种情况~~~首先现在要解决的主
  • 测试管理中可能存在问题及分析

    千次阅读 2019-01-02 12:30:00
    文中前两部分简要介绍了软件测试管理及测试的范围,方法及重要性,之后对当前国内中小型软件企业在测试及测试管理中可能存在问题进 行了简单的介绍与分析,最后介绍了一些较好的解决方法。 1、软件测试及测试管理...
  • 可以看出在这件事件中,滴滴存在很大的监控漏洞和沟通漏洞,以致于出现了最后的悲剧发生。 而这件事距离上一起郑州空姐遭滴滴顺风车司机杀害案,仅仅过去三个多月。 于是毫无意外的在每条新闻报道下,充满了对滴滴...
  • 人工智能存在问题是什么(一)

    千次阅读 2019-01-29 10:41:40
    但人工智能现在也是存在了很多的问题,具体问题都有哪些呢?下面我们就给大家介绍一下这个问题。 现阶段,人工智能存在着十个问题,下面我们就给大家详细的介绍一下这些问题。 首先给大家介绍一下人工智能存在...
  • FFMPEG计算PSNR存在问题及解决方法

    千次阅读 2017-07-19 10:04:59
    本篇聊一下FFMPEG计算两个离线文件之间的PSNR时存在的bug,以及该bug的根本原因,最后给出修复方法。
  • 但是,物联网很多技能仍然存在问题,因此未来一年内人们需要关注物联网的四个关键领域:物联网的硬件设计、低功耗远程通讯、人工智能集成物联网,以及物联网设备的平安。 物联网的硬件设计 从社会发展角度来看,...
  • 最新vue-cli 2.9.1的webpack存在问题

    万次阅读 2017-11-18 11:33:32
    会node的也可以直接做个api接口,开启node服务 然后饿了吗项目直接访问这个接口,当然这里会存在跨域问题和路由映射,不过webpack-dev-server 帮你们解决这个问题主要是设置参数问题 devServer.proxy 进行路由...
  • 产品研发中存在问题和缺陷

    千次阅读 2010-05-17 19:54:00
    1、缺乏市场分析 市场分析不足,没有真正的了解客户需求,对市场认识不足是新产品项目的主要原因。我们在旅游的分销系统开发中,就存在对市场认识不足的情况,现在我们这个产品几乎接近失败的边缘。 2、实施质量不...
  • 测试自动化普遍存在问题

    万次阅读 2006-06-15 23:55:00
    对测试工具能够发挥作用,大家都已经了解并认可了,但是很多引入自动化测试工具的软件公司并没有能够让测试自动化发挥应有的作用,其主要原因有以下几个方面:1. 不正确的观念或不现实的期望没有建立一个正确的软件...
  • 跨域问题出现原因和解决方案

    万次阅读 多人点赞 2017-06-09 11:09:38
    【出现原因】什么是跨域以及产生原因 跨域是指a页面想获取b页面资源,如果a、b页面的协议、域名、端口、子域名不同,或是a页面为ip地址,b页面为域名地址,所进行的访问行动都是跨域的,而浏览器为了安全问题一般...
  • json解析存在的精度丢失问题详解

    万次阅读 2017-04-22 21:30:24
    这个问题调查了很久。一直以为是jar包或者哪里转错了。自己动手实验了一下。发现是json js 和java数值范围不同引起的。{ “boolean”: true, “starttimeseconds”:9223372036854122112, “null”: null, ...
  • 机器学习过度拟合问题一些原因

    千次阅读 2016-05-06 20:45:12
    仔细想想确实在训练时存在一些问题,第一:输入变量多,由于缺乏对问题的根本认识,使用了很多无关变量,这个问题打算从其它途径先认识变量和问题的关系;第二:数据的噪声可能是比较大,没有考虑到关键的特征和信息...
  • 公司的项目底层,是使用的TCP,因为可靠,自动断线重连,在底层都实现了,但是我记得TCP也会有掉包的问题,所以这文章就诞生了——关于TCP掉包的问题,TCP是基于不可靠的网络实现可靠的传输,肯定也会存在掉包的情况...
  • 安装完正版的CATIA客户端后,会在登录的时候提示许可证不存在,这都是由什么原因导致的呢?1.网络原因首先需要检查安装的许可证服务器是否已经正常启动,有时在点击许可证服务时会提示无法连接,说明是许可证服务器...
  • 以下为电源适配器引起输出电压低的主要原因: 1、开关电源负载短路故障(尤其是 DC/DC 变换器短路或性能不良等) ,此时,首先断开开关电源电路的所有负载,检查是开关电源电路故障还是负载电路有故障。如果断开负载...
  • 首先,部分手机,尤指华为手机,特别是最近华为很多手机都开始升级上Android10,问题爆发尤其之多,在这主要讲一下跳转安装界面,然后报 解析包时出现问题 的几个原因问题解决方法。说明一下,我用到跳转安装的...
  • TCP/IP详解--TIME_WAIT状态存在原因

    千次阅读 2014-09-01 20:15:37
    1. 实际问题  初步查看发现,无法对外新建TCP连接时,线上服务器存在大量处于TIME_WAIT状态的TCP连接(最多的一次为单机10w+,其中引起报警的那个模块产生的TIME_WAIT约2w),导致其无法跟下游模块建立新TCP连接。 ...
  • session失效问题的可能原因

    千次阅读 2017-05-02 11:30:07
    最近写网页,发现session只要一分钟就会失效(取不出存在session里的值),设置了session的最大不活动时间为30分钟,但是依然过一分钟session就失效了,然后给session加了生死监听,确实要过30分钟,session上的监听...
  • word转pdf时存在的一些问题

    万次阅读 2017-06-08 22:45:32
    2、在EDAs上传PDF文档时,经常会出现格式有问题,上传不成功的现象,这个主要是PDF文档字体嵌入的问题  (1)打开生成的PDF文档,点击“文件”—>“文档属性”—>“字体”:右边显示的字体中,有的字体后面括号...
  • 我们上网浏览各种网站,使用浏览器的时候可能会遇到一些问题,为了解决这些问题而在网上四处的找答案,于是,为了方便大家,我总结了一些的问题原因及解决方法,可能不太全,以后添加。 一、浏览器无法访问网页 ...
  • 生成式对抗网络的基本原理 ...本节将从初始版本的GAN出发,通过学习GAN的原理,对比GAN与其他几种生成式模型的异同,以及分析原始GAN中存在问题,以获得对GAN的深度理解。 知识点 生成模型、自编码器(AutoEncod
  • 显卡占用率低的问题,终于找到原因解决了

    万次阅读 多人点赞 2020-01-07 12:16:17
    主要是自己一直想组装一台电脑,苦于多种原因一直没有机会,终于把自己的电脑组装好了,当时还开心的很长一段时间。 组装好了后,直接就下载了吃鸡,进入游戏后,总是感觉有卡顿,查看fps只有40左右,最高的时候也...
  • java线程安全问题产生的原因

    千次阅读 2018-03-31 20:47:26
    最近工作中遇到不少多线程问题,但自己一直对多线程的理解比较表层。没有深入探究。正是最近工作中遇到的问题,致使我深入的去了解多... 网上有不少介绍多线程产生的原因的。我大致看了一遍,感觉都介绍的太粗线...
  • 在python的练手小游戏项目中,项目中主要用到 pygame 模块包进行创作,项目的具体细节不在赘述。文章后面会贴出项目的有关介绍。现在就我在练习该项目时遇到的问题。项目开发环境:windows10 + python3.6问题1:小...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 802,607
精华内容 321,042
关键字:

存在问题的主要原因