udp重发java实现
最近在处理框架通讯方面的问题,通过积累的开发经验,其实在很多情况(尤其是实时大数据量),udp是占有很多优势的;不需要连接,只管发送,理论上要快很多;
另外在穿墙上占有很大优势;
但是最大的一个问题就是丢包;
很多时候我们会结合我们的业务来进行发送与回执,这样的方式应该是最好的;但是也意味着每次都得重来一次;因此花费了一些时间来写这个重发逻辑;当然目前仅是测试;
封装了一个udp重发;其实组播也可以直接使用,只是我还没有完成封装,原理一样,只不过组播封装重发,会浪费网络资源,只要一个节点(把一个接收位置看作一个节点)没有收到其中一个包,就需要发送端发送,所有节点都会接收(并不影响数据完整,在接收端已经封装了接收方式,不会造成数据重复);不说组播了,回到udp重发;
大体结构:

1.每一次发送都视为session;
1》judpclient为封装的发送端,发送数据时,会自动分包,按照udp65535大小(可以设置);每次发送分配一个发送端session(同时产生id),每次发送分包时,都会依次产生
一个初始化序列号,按照初始序列号,每包设置一个id,按照此发送打包数据发送
2》同时会发送一个ack发送确认包,防止数据包只有一个被丢包;
3》发送后等待数据返回
4》judpclient关闭只是逻辑关闭
2.接收端
接收端按照来源IP,端口产生一个接收端session,然后接收数据,组织数据,检查丢包,发送丢包ack;
接收端设计了serversession及buffer,所以不用担心数据重发造成数据重复的问题,该结构读取方式已经直接避免了
3.辅助应用
因为是辅助,无法判断judpclient使用情况,所以利用java特点,在回收对象时设置逻辑关闭;同时控制时间,来判断通讯真实关闭(因为发送端还要监听等待重发)
4.共享session
最开始的设计是不共享的,但是在测试时发现,在极端时候,因为发送端占有端口监听需要时间,重新初始化judpclient对象,会导致端口占用完,无法再分配;所以
最后采用了共享的方式,让多个judpclient实际使用一个真正的udp底层通讯;每个judpclient产生一个id,来判断数据接收时往哪里发送,触发哪个对象的方法;
5.缓存问题解决方式
数据重发就意味着发送的数据需要缓存下来,准备重新发送;这样如果发送大量数据,发送端就可能“爆满”,所以要减少内存使用;
处理方式:做一个简单的数据量统计(不精确,也不需要精确),当这个量达到一定值后,就把数据由内存转移到磁盘中;
我自己设计了一个文件保存方式(做了一个文件持久化层),来按照一定方式保存,也实现了文件删除,修改(修改没有必要);
里面主要是有个索引维护;同时使用了内存数据库表(如果不实现文件修改是没有必要的,通过异步方式保证文件索引准确,又不影响使用效率)
最开始我没有使用文件,而是查找了数据库(paldb,fastdb,mapdb等等),但是效果不尽人意,通过磁盘,其实一般磁盘读取在30M/s,而数据库是做不到的;因此我直接采用了文件读取方式;我并不是要做一个文件数据库,所以在实现文件修改时,任然使用了第三方数据库h2,简单直接,索引使用足够了,而且是异步;在数据重发这里,文件修正是没有必要的,实现该功能只是想让模块更加完整而已;
文件保存,也是通过一个简单的计数,每次10M左右的数据一起写入文件;
当接收端数据接收完成后,会回复一个接收完成ack包,发送端解析信息后,会把接收完成的一次会话数据都删除掉;
使用数据库保存的最初代码我并没有删除,只是没有使用而已;
6.遗留问题(需要优化)
通过重新构造,其实最大问题在于我无法控制judpclient的使用,这样会造成很多线程启动,在监听数据返回的信息(丢包,完成),这样造成大量线程存在,虽然应用了线程池,根据现在的测试,发送端cpu 15-35%都是有可能的;阻塞的线程也很多,一旦彻底完成发送,同时退出的线程同样多,但是感觉这样也没有影响测试使用(可能是我的java水平不过关,有的测试结果我感觉很怪);所以需要缩减线程以及阻塞集合;
7.共享session分配
专门有个管理池分配,其实就是定一个最大个数,使用完了就再产生一个,同时监视是否共享session关闭情况
8.其它辅助实现
使用了guava的缓存及eventbus;
数据发送打包与解析配套(接收端也可以正常使用)
9.源码
eclipse编译;现在已经上传git;
地址:https://github.com/jinyuttt/jyudp.git
我也会上传到csdn,不过可能超过大小;
udp重发java实现的更多相关文章
- udp重发
最近在处理框架通讯方面的问题,通过积累的开发经验,其实在很多情况(尤其是实时大数据量),udp是占有很多优势的:不需要连接,只管发送,理论上要快很多; 另外在穿墙上占有很大优势: 但是最大的一个问题就 ...
- JMeter 压测Server Agent无法监控资源问题,PerfMon Metrics Collector报Waiting for sample,Error loading results file - see file log, Can't accept UDP connections java.net.BindException: Address already in use 各种疑难杂症
如何安装插件此博主已经说得很详细了. https://www.cnblogs.com/saryli/p/6596647.html 但是需注意几点: 1.修改默认端口,这样可以避免掉一个问题.Serve ...
- Can't accept UDP connections java.net.BindException: Address already in use_解决方案
一.问题描述 在Linux服务器(CentOS7系统)中配置并启动JMeter远程监控服务器资源所需的ServerAgent目录下的 startAgent.sh 文件时,系统出现异常提示,如下: [r ...
- UDP 多播 Java
1.服务端 public class UdpMulticastServer { /** * @param args */ public static void main(String[] args) ...
- UDP 广播 Java
1.服务端 public class UdpBroadcastServer { /** * @param args */ public static void main(String[] args) ...
- UDP通信 Java
public class UdpServerTest { /** * @param args * @throws SocketException */ public static void main( ...
- java基础知识回顾之java Socket学习(一)--UDP协议编程
UDP传输:面向无连接的协议,不可靠,只是把应用程序传给IP层的数据报包发送出去,不保证发送出去的数据报包能到达目的地.不用再客户端和服务器端建立连接,没有超时重发等机制,传输速度快是它的优点.就像寄 ...
- 【Java TCP/IP Socket】UDP Socket(含代码)
UDP的Java支持 UDP协议提供的服务不同于TCP协议的端到端服务,它是面向非连接的,属不可靠协议,UDP套接字在使用前不需要进行连接.实际上,UDP协议只实现了两个功能: 1)在IP协议的基础上 ...
- TCP/UDP套接字 java socket编程实例
网络协议七层结构: 什么是Socket? socket(套接字)是两个程序之间通过双向信道进行数据交换的端,可以理解为接口.使用socket编程也称为网络编程,socket只是接口并不是网络通信协议. ...
随机推荐
- Java基础01-JVM内存分析
JVM java虚拟机 java编译后的class文件就是在java虚拟机上运行的 1.栈区(stacksegment)存放函数的参数值,局部变量的值等,在超过这个变量的作用域时就会被系统自动释放掉存 ...
- LoadScene场景异步加载
LoadScene场景异步加载 using UnityEngine; using System.Collections; using UnityEngine.SceneManagement; usin ...
- Linux 安装 webmin
下载webmin的rpm包 yum install webmin-rpm systemctl start webmin 即可
- 学习JVM-GC原理
1. 前言 Java和C++之间显著的一个区别就是对内存的管理.和C++把内存管理的权利赋予给开发人员的方式不同,Java拥有一套自动的内存回收系统(Garbage Collection,GC)简称G ...
- dapper.net框架使用随笔
一.简单介绍 Dapper是轻量级的ORM工具,代码就SqlMapper.cs一个文件,对于习惯使用原生的sql语句用户是个好选择,具有以下特性. 1.类似 ado.net 的写法,灵活拼接sql 2 ...
- bundle绑定资源表
1.注册绑定资源表 在application_Start函数中: (注意不要加拓展名,否则压缩时出问题) BundleTable.Bundles.Add(new ScriptBundle(" ...
- JavaScript 函数 (function)
//声明(有参数.有返回值) function fun() { var name = '小黑'; ) { name = arguments[]; //接受参数 } alert(name); retur ...
- 谈谈Quartz中遇到的深坑
最近在项目开发的时候,根据业务需求,需要配置为自定义Quartz任务(即:用户可以自定义任务执行时间) 但是在即将写完的时候遇到一个非常头疼的问题: 一个redisTemplate 与 workOrd ...
- jQuery的表单验证
jQuery的表单验证 直接上代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...
- ansible软件相关模块丶计划任务,剧本
软件相关模块 yum rpm 和yum 的区别 rpm:redhat package manager yum可以解决依赖关系 yum 源配置 [epel] name=Extra Packages fo ...