在嵌入式单板环境下,c给java虚拟机使用UDP发包,超过140包/s时,就会丢包,严重影响业务。
使用队列处理,主要解决以下问题,
1、不同事件类型放在一个队列,因为有些事件的发包频率不快,但是比较重要。
2、适用于有多个client给一个server在同一端口高频发不同类型的包。
3、不断从队列中取消息并进行处理。
程序开始运行之前先初始化消息处理线程,使其一直阻塞在等待入队元素状态:
private class PushDispatcher extends Thread {
private boolean isDone = false;
public void shutdown() {
isDone = true;
}
public PushDispatcher() {
this.setDaemon(true);
log.track(LoggerI.SYSDEBUG,"SDK event PushDispatcher start ");
}
@Override
public void run() {
while (!isDone) {
JSONObject pushData = eventCache.fetchPush();向队列一直请求元素,队列为空则一直阻塞。
/**处理接收到的事件推送*/
JSONObject format = pushData.getJSONObject("format");
JSONArray bundleName = pushData.getJSONArray("bundlename");
String event = pushData.getString("Event");
for (int i = 0; i < bundleName.length(); i++)
{
String name = bundleName.getString(i);
udpMonitor.eventsend(name, format.toString(), event);这里向第三方插件发送消息
}
}
log.track(LoggerI.SYSDEBUG,"SDK event PushDispatcher offline ");
}
}
队列实现:
public class EventCache {
此队列是单独的消息直接入队
private List<JSONObject> pushs = new LinkedList<JSONObject>();
此队列是两种消息入队列
private List<MsgObject> msgPushs = new LinkedList<MsgObject>();
public void msgPutPush(MsgObject obj) throws Exception
{
锁定队列,之后向入队,通知队列中已经有元素,激活队列的wait。
synchronized (msgPushs)
{
msgPushs.add(obj);
msgPushs.notify();
}
}
public MsgObject msgFetchPush()
{
MsgObject getMsgPushs = null;
synchronized(msgPushs)
{
锁定队列,队列为空,死等待,notify通知之后,出队首元素。
if(msgPushs.isEmpty())
{
try
{
msgPushs.wait();
getMsgPushs = msgPushs.remove(0);
}
catch (InterruptedException e)
{
log.error("fetch msgPush error, " + e);
}
}
}
log.debug("out fetch msgPush : " + getMsgPushs.toString());
return getMsgPushs;
//pushs出队入队类似
}
}
服务端分发消息:
while (true)
{
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
server.receive(packet);// 此方法在接收到数据报之前会一直阻塞
// 读取数据
String info = new String(data, 0, packet.getLength());
log.track(LoggerI.SYSDEBUG,"Client message:" + info);
JSONObject dataJson = new JSONObject(info);
String event = dataJson.getString("Event");
log.debug("Message head:" + event);
if (event.equals("1"))
{
}
else if (event.equals("2"))
{
}
else if (event.equals("3p"))
{
++countP;
log.debug("msg 3p counter countP:" + countP);
MsgObject msgObject = new MsgObject();
msgObject.setInfo(info);
msgObject.setType(2);
msgObject.setUdpPacket(packet);
try
{
permissionEventDispatcher.recvPush(msgObject);
}
catch (Exception e)
{
// TODO Auto-generated catch block
//e.printStackTrace();
log.error("3p msg push error " + e );
}
}
else if (event.equals("4m"))
{
++countM;
log.debug("msg 4m counter countM:" + countM);
MsgObject msgObject = new MsgObject();
msgObject.setInfo(info);
msgObject.setType(1);
msgObject.setUdpPacket(packet);
try
{
permissionEventDispatcher.recvPush(msgObject);
}
catch (Exception e)
{
// TODO Auto-generated catch block
//e.printStackTrace();
log.error("4m msg push error " + e );
}
}
else
{
JSONObject format = dataJson.getJSONObject("format");
/**由于事件处理性能受限(140包每秒),更改实现方式为:
* 先将事件入队列,之后由指定线程处理事件上报
*/
try
{
++countA;
log.debug("msg NOTIFY counter countA:" + countA);
eventDispatcher.recvPush(info);
}
catch (Exception e)
{
// TODO Auto-generated catch block
//e.printStackTrace();
log.error("NOTIFY msg push error " + e );
}
}
}
}
3p和4m的消息类型放在一个队列。用type区分
public class MsgObject
{
private int type ;
private String info;
private DatagramPacket udpPacket;
}
两个消息类型分发消息实现:
private class PushDispatcher extends Thread {
private boolean isDone = false;
public void shutdown() {
isDone = true;
}
public PushDispatcher() {
this.setDaemon(true);
log.track(LoggerI.SYSDEBUG,"SDK event PushDispatcher start ");
}
@Override
public void run() {
while (!isDone) {
MsgObject msgObject = eventCache.msgFetchPush();
/**处理接收到的事件推送*/
if(1 == msgObject.getType())
{
//do your things
}
else if (2 == msgObject.getType())
{
//do your things
}
}
log.track(LoggerI.SYSDEBUG,"SDK event PushDispatcher offline ");
}
}