UDP传输工具类(server/client)

来源:互联网 发布:objective c编程之道 编辑:程序博客网 时间:2024/06/07 02:05

UDP不适合传输大数据,所以传输要尽量小。

UDP传输中可能会丢包,如果需要可能多次发送同一个包 保证包能安全到达;接收端可以对收到的包进行CRC校验,已确定是否收到同样的包。


package org.sl.udp.beans;import java.net.DatagramPacket;/** * 处理udp请求的接口 * @author shanl * */ public interface IUdpRequestHandler{/** * 解析请求数据包 * @param requestPack */void parse(DatagramPacket requestPack);}

package org.sl.udp.beans;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.PrintStream;import java.util.Arrays;import java.util.Map;import java.util.Properties;import java.util.Set;/** * 传输包格式<br/> * 具备头校验功能。 * @author shanl * */public class PacketFormat {/**请求头,主要用于校验*/public static final byte[] REQUEST_HEADER = {'S','H','A','N'};private Properties prop = null;/** * 构造一个用于发送请求的包结构 */public PacketFormat(){this.prop = new Properties();}/** * 解析并从请求中加载数据 * @param buff 数据包 * @param offset 偏移量 * @param len 长度 * @return true:解析成功,false:解析失败 */public boolean parse(byte[] buff, int offset, int len){boolean done = false;ByteArrayInputStream dataCache = null;ObjectInputStream objectIn = null;ByteArrayInputStream propCache = null;try {dataCache = new ByteArrayInputStream(buff, offset, len);byte[] d_header = new byte[REQUEST_HEADER.length];dataCache.read(d_header);//校验请求头if(!Arrays.equals(d_header, REQUEST_HEADER)){return false;}objectIn = new ObjectInputStream(dataCache);//得到数据长度short dataLen = objectIn.readShort();byte[] propBys = new byte[dataLen];objectIn.read(propBys);propCache = new ByteArrayInputStream(propBys);//加载数据this.prop.load(propCache);done = true;} catch (Exception e) {done = false;}finally{try{if(null!=propCache)propCache.close();}catch(Exception ex){}try{if(null!=objectIn)objectIn.close();}catch(Exception ex){}try{if(null!=dataCache)dataCache.close();}catch(Exception ex){}}return done;} /** * 设置数据 * @param key * @param value */public void setProperty(String key, String value){this.prop.setProperty(key, value);}/** * 取数据 * @param key * @return */public String getProperty(String key){return this.prop.getProperty(key,"");}/** * 返回keyset * @return */public Set<Object> keySet(){return this.prop.keySet();}/** * 将内容转换为byte数组 * @return */public byte[] toBytes(){byte[] dataCacheBys = null;ByteArrayOutputStream dataCache = null;ObjectOutputStream dataOut = null;StringBuilder propContent = new StringBuilder();byte[] propBys = null;Set<Map.Entry<Object, Object>>items = this.prop.entrySet();for(Map.Entry<Object, Object> i: items){propContent.append((String)i.getKey());propContent.append("=");propContent.append((String)i.getValue());propContent.append("\n");}propBys = propContent.toString().getBytes();try{dataCache = new ByteArrayOutputStream();dataCache.write(REQUEST_HEADER);dataOut = new ObjectOutputStream(dataCache);//写入数据长度dataOut.writeShort(propBys.length);//写入数据dataOut.write(propBys, 0, propBys.length);dataOut.flush();dataCacheBys = dataCache.toByteArray();}catch(Exception ex){throw new RuntimeException(ex);}finally{try{if(null!=dataOut) dataOut.close();}catch(Exception ex){}try{if(null!=dataCache) dataCache.close();}catch(Exception ex){}}return dataCacheBys;}/** * 得到请求数据 * @param buff 数据缓存,缓存大小>=128 * @param offset 偏移量 * @return 包长度=请求头长度+2+数据 */public int getBytes(byte[] buff, int offset){int len = 0;//ByteArrayOutputStream propCache = null;ByteArrayOutputStream dataCache = null;ObjectOutputStream dataOut = null;StringBuilder propContent = new StringBuilder();byte[] propBys = null;//try{//propCache = new ByteArrayOutputStream(buff.length-REQUEST_HEADER.length-2);//this.prop.list(new PrintStream(propCache));//propBys = propCache.toByteArray();//}catch(Exception ex){//throw new RuntimeException(ex); //}finally{//try{//if(null!=propCache)propCache.close();//}catch(Exception ex){}//}//这段代码与上面这段功能相同,但Properties的list()会写入额外的字节Set<Map.Entry<Object, Object>>items = this.prop.entrySet();for(Map.Entry<Object, Object> i: items){propContent.append((String)i.getKey());propContent.append("=");propContent.append((String)i.getValue());propContent.append("\n");}propBys = propContent.toString().getBytes();try{//写入头dataCache = new ByteArrayOutputStream(buff.length);dataCache.write(REQUEST_HEADER);len+=REQUEST_HEADER.length;dataOut = new ObjectOutputStream(dataCache);//写入数据长度dataOut.writeShort(propBys.length);len+=2;//写入数据dataOut.write(propBys, 0, propBys.length);dataOut.flush();byte[] dataCacheBys = dataCache.toByteArray();System.arraycopy(dataCacheBys, 0, buff, offset, dataCacheBys.length);len+=dataCacheBys.length;}catch(Exception ex){throw new RuntimeException(ex);}finally{try{if(null!=dataOut) dataOut.close();}catch(Exception ex){}try{if(null!=dataCache) dataCache.close();}catch(Exception ex){}}return len;}                /**     * 返回crc32校验码     * @return     */    long crc32(){        CRC32 crc32 = new CRC32();        crc32.update(toBytes());        return crc32.getValue();    } }


package org.sl.udp.client;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.SocketException;import java.util.Random;import java.util.concurrent.BlockingDeque;import java.util.concurrent.LinkedBlockingDeque;/** * UDP发送请求服务 * @author shanl * */public class UDPSenderService{private BlockingDeque<RequestObject> requestPool = null;private long intervalTime = 200L;private DatagramSocket udpSender = null;private boolean shutdown = true;private Object lockObj = new Object();public UDPSenderService(){requestPool = new LinkedBlockingDeque<RequestObject>();}/** *  * @param poolSize 请求缓冲池上限   * @param intervalTime 间隔时间 */public UDPSenderService(int poolSize,int intervalTime){requestPool = new LinkedBlockingDeque<RequestObject>(poolSize);this.intervalTime = intervalTime;}/** * 过程 */void process() {do{long now = System.currentTimeMillis();try{synchronized(lockObj){lockObj.wait(intervalTime);if(!requestPool.isEmpty()){send(now);}}} catch (Exception e) {e.printStackTrace();}}while(!shutdown);}//int c=0;private void send(long time) throws IOException{RequestObject ro = null;try {for(int i =0; i<10; i++){ro = requestPool.poll();//ro = requestPool.take();//ro = requestPool.pollFirst();if(null!=ro){if(ro.getTime() <= time){//System.out.println(c++);udpSender.send(ro.getDataPacket());}else{requestPool.put(ro);//requestPool.offerLast(ro);}}else{break;}}} catch (Exception e) {e.printStackTrace();}}/** * 重复多送发送一个udp请求 * @param request 请求包 * @param repeatCount 重复次数 * @param interval 重复发送请求包间隔 */public void addRepeatingRequest(DatagramPacket request, int repeatCount, long interval){addImmediateRequest(request);//timingRequest(System.currentTimeMillis(), request);byte[] reqData = new byte[request.getLength()-request.getOffset()];System.arraycopy(request.getData(), request.getOffset(), reqData, request.getOffset(), request.getLength());  long now = System.currentTimeMillis();DatagramPacket dpClone = null;for(long i=0,nextTime=interval; i<repeatCount; i++, nextTime+=interval){dpClone = new DatagramPacket(reqData, request.getOffset(), request.getLength());dpClone.setSocketAddress(request.getSocketAddress());addTimingRequest(now+nextTime, dpClone);}}/** * 添加一个定时的请求,在一个近似的时间执行发送.<br/> * 如果这个请求为过期的请求,则会在下一个时间被执行. * @param time * @param request */public void addTimingRequest(long time, DatagramPacket request){try {//requestPool.offerLast(new RequestObject(time, request), 300, TimeUnit.MILLISECONDS);requestPool.put(new RequestObject(time, request));//requestPool.offerLast(new RequestObject(time, request));} catch (Exception e) {e.printStackTrace();}synchronized(lockObj){lockObj.notify();}//try {//Thread.sleep(1);//} catch (InterruptedException e) {//}}/** * 立即发送一个请求 * @param request */public void addImmediateRequest(DatagramPacket request){try{udpSender.send(request);}catch(Exception ex){ex.printStackTrace();}}/** * 启动服务 */public void start(){if(this.shutdown){try {if(null==udpSender){udpSender = new DatagramSocket();}} catch (SocketException e1) {e1.printStackTrace();return;}try {Thread t = new Thread(new ProcessService(),"UDPSenderService-"+new Random().nextInt(999));t.start();} catch (Exception e) {throw new RuntimeException(e.getMessage());}this.shutdown = false;}}/** * 中止服务 */public void shutdown(){this.shutdown = true;try{Thread.sleep(1000*10);}catch(Exception ex){}try{this.udpSender.disconnect();}catch(Exception ex){}try{this.udpSender.close();}catch(Exception ex){}}public void setDatagramSocket(DatagramSocket sender){this.udpSender = sender;}private class ProcessService implements Runnable{public void run(){process();}}static class RequestObject {private Long time;private DatagramPacket dataPacket = null;public RequestObject(DatagramPacket dataPacket){this.time = System.currentTimeMillis();}public RequestObject(Long time,DatagramPacket dataPacket){this.time = time;this.dataPacket = dataPacket;}public Long getTime(){return time;}public DatagramPacket getDataPacket(){return dataPacket;}}}


package org.sl.udp.server;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetSocketAddress;import org.sl.udp.beans.IUdpRequestHandler;/** * udp接收器 * @author shanl * */public class UDPReceptor implements Runnable{private String hostname = "localhost";private int port = 7777;private int recePacketSize = 512;private IUdpRequestHandler requestHandler = null;/** * 过程 */public void run() {DatagramSocket udpRece = null;DatagramPacket dataPack = null;byte[] buff = null;try{udpRece = new DatagramSocket(new InetSocketAddress(this.hostname, this.port));udpRece.setReceiveBufferSize(this.recePacketSize);for(;;){buff = new byte[this.recePacketSize];dataPack = new DatagramPacket(buff, this.recePacketSize);udpRece.receive(dataPack);if(null!=requestHandler) requestHandler.parse(dataPack);}}catch(Exception ex){ex.printStackTrace();}}/** * 注入请求处理 * @param requestHandler 请求处理 */public void setRequestHandler(IUdpRequestHandler requestHandler){this.requestHandler = requestHandler;}/** * 设置接收包大小 * @param udpPacketSize */public void setRecePacketSize(int udpPacketSize){this.recePacketSize = udpPacketSize;}public void setHostname(String hostname){this.hostname = hostname;}public void setPort(int port){this.port = port;}}


package org.sl.udp.demo;import java.net.DatagramPacket;import java.util.Set;import java.util.concurrent.ExecutorService;import org.sl.udp.beans.PacketFormat;import org.sl.udp.beans.IUdpRequestHandler;public class DemoMultiThreadUDPRequestHandlerImpl  implements IUdpRequestHandler{private ExecutorService threadPool = null;public void parse(DatagramPacket requestPack) {threadPool.execute(new HandlerService(requestPack));}public void setThreadPool(ExecutorService threadPool){this.threadPool = threadPool;}private static class HandlerService extends Thread{private DatagramPacket requestPack = null;public HandlerService(DatagramPacket requestPack){this.requestPack = requestPack; }public void run(){try{PacketFormat reqPack = new PacketFormat();if(!reqPack.parse(requestPack.getData(),requestPack.getOffset(), requestPack.getLength())){return;}Set<Object> keyset = reqPack.keySet();System.out.println("value:"+reqPack.getProperty("value"));System.out.println("====time:"+System.currentTimeMillis());for(Object key: keyset){System.out.println(key+":"+reqPack.getProperty((String)key) );}}catch(Exception ex){ex.printStackTrace();}}}}


package org.sl.udp.demo;import java.net.DatagramPacket;import java.util.Set;import org.sl.udp.beans.PacketFormat;import org.sl.udp.beans.IUdpRequestHandler;public class DemoUDPRequestHandlerImpl implements IUdpRequestHandler{private DatagramPacket requestPack = null;public void parse(DatagramPacket requestPack) {this.requestPack = requestPack;process();}private void process() {try{PacketFormat reqPack = new PacketFormat();if(!reqPack.parse(requestPack.getData(),requestPack.getOffset(), requestPack.getLength())){return;}Set<Object> keyset = reqPack.keySet();synchronized(UDPReceptorDemo.iset){UDPReceptorDemo.iset.add(Integer.parseInt(reqPack.getProperty("value")));}//System.out.println("value:"+reqPack.getProperty("value"));//System.out.println("====time:"+System.currentTimeMillis());//for(Object key: keyset){//System.out.println(key+":"+reqPack.getProperty((String)key) );//}}catch(Exception ex){ex.printStackTrace();}}}


package org.sl.udp.demo;import java.util.HashSet;import java.util.Set;import java.util.concurrent.Executors;import org.sl.udp.beans.IUdpRequestHandler;import org.sl.udp.server.UDPReceptor;public class UDPReceptorDemo {public static void main(String[] args){//t1();t2();t3();}public static Set<Integer> iset = new HashSet<Integer>(10000);static void t3(){for(;;){System.out.println(iset.size());try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}static void t2(){System.err.println("启动udp监听,端口7777...");IUdpRequestHandler handlerImpl = new DemoUDPRequestHandlerImpl();UDPReceptor rece = new UDPReceptor();rece.setRequestHandler(handlerImpl);rece.setHostname("192.168.2.23");rece.setPort(7777);Thread t = new Thread(rece,"udpRece_port7777");t.start();}/** * 已普通实例启动 */static void t1(){System.err.println("启动udp监听,端口7777...");DemoMultiThreadUDPRequestHandlerImpl handlerImpl = new DemoMultiThreadUDPRequestHandlerImpl();handlerImpl.setThreadPool(Executors.newFixedThreadPool(5));UDPReceptor rece = new UDPReceptor();rece.setRequestHandler(handlerImpl);rece.setHostname("192.168.2.23");rece.setPort(7777);rece.run();}}


package org.sl.udp.demo;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetSocketAddress;import java.net.SocketException;import java.util.Random;import org.sl.udp.beans.PacketFormat;import org.sl.udp.client.UDPSenderService;public class UDPSenderServiceDemo {public static void main(String[] args){//t1();//t2();//t3();t4();}static void t4(){UDPSenderService udpSenderService = new UDPSenderService();udpSenderService.start();System.err.println("启动udp发送服务");Random rand = new Random();byte[] buff = null;long time = System.currentTimeMillis();DatagramPacket req = null;PacketFormat pf = null;for(int i=0,endi=300; i<endi; i++){//time = (rand.nextInt(100)+1)*100L+System.currentTimeMillis();pf = new PacketFormat();pf.setProperty("msg", "test");pf.setProperty("msg", "test");pf.setProperty("type", "cpu");pf.setProperty("value", ""+i);buff = new byte[512];;int packLen = pf.getBytes(buff, 0);req = new DatagramPacket(buff,0,packLen);//System.out.println("value:"+pf.getProperty("value"));req.setSocketAddress(new InetSocketAddress("192.168.2.23", 7777) );//有一定几率丢包//for(int n=0; n<3; n++){//udpSenderService.addImmediateRequest(req);//}//多次重发保证可靠性//udpSenderService.addRepeatingRequest(req, 2, 1L);//有一定几率丢包udpSenderService.addTimingRequest(time, req);//try {//if(i%10==0){//Thread.sleep(3);//rand.setSeed(time);//}//} catch (Exception e) {//}}try{Thread.sleep(1000*60);}catch(Exception ex){}udpSenderService.shutdown();System.err.println("udp服务关闭.");}static void t3(){UDPSenderService udpSenderService = new UDPSenderService();udpSenderService.start();System.err.println("启动udp发送服务");Random rand = new Random();byte[] buff = new byte[512];;long time = 0;for(int i=0,endi=3*100*100; i<endi; i++){PacketFormat pf = new PacketFormat();pf.setProperty("msg", "test");pf.setProperty("msg", "test");pf.setProperty("type", "cpu");pf.setProperty("value", "33.05");int packLen = pf.getBytes(buff, 0);DatagramPacket data = new DatagramPacket(buff,0,packLen);data.setSocketAddress(new InetSocketAddress("192.168.2.23", 7777) );time = (rand.nextInt(4)+1)*1000L+System.currentTimeMillis();//udpSenderService.timingRequest(time, data);udpSenderService.addTimingRequest(time, data);try {if(i%50==0){Thread.sleep(1);rand.setSeed(time);}} catch (Exception e) {}}try{Thread.sleep(1000*10);}catch(Exception ex){}udpSenderService.shutdown();System.err.println("udp服务关闭.");}static void t2(){UDPSenderService udpSenderService = new UDPSenderService();try {//InetSocketAddress serviceAddress = new InetSocketAddress("localhost", 7777);//DatagramSocket udpSocket = new DatagramSocket(serviceAddress);//udpSenderService.setDatagramSocket(udpSocket);udpSenderService.start();System.err.println("启动udp发送服务");} catch (Exception e) {e.printStackTrace();}Random rand = new Random();byte[] buff = "test".getBytes();long time = 0;for(int i=0,endi=3; i<endi; i++){DatagramPacket data = new DatagramPacket(buff,0,buff.length);data.setSocketAddress(new InetSocketAddress("192.168.2.23", 7777) );//int c = (rand.nextInt(2)+1)*50;//time = (rand.nextInt(15)+1)*100L+System.currentTimeMillis();//time = System.currentTimeMillis();time = (rand.nextInt(4)+1)*1000L+System.currentTimeMillis();//System.out.println(time);//for(int j=0,endj=(rand.nextInt(2)+1)*50; j<endj; j++){//udpSenderService.addRequest(time, data);//}//System.out.println("time:"+time);udpSenderService.addTimingRequest(time, data);try {if(i%50==0){//Thread.sleep(1);rand.setSeed(time);}} catch (Exception e) {}}try{Thread.sleep(1000*10);}catch(Exception ex){}udpSenderService.shutdown();System.err.println("udp服务关闭.");}static void t1(){UDPSenderService udpSenderService = new UDPSenderService();try {InetSocketAddress serviceAddress = new InetSocketAddress("localhost", 7777);DatagramSocket udpSocket = new DatagramSocket(serviceAddress);udpSenderService.setDatagramSocket(udpSocket);udpSenderService.start();System.err.println("启动udp监听,服务端口7777...");} catch (SocketException e) {e.printStackTrace();}Random rand = new Random();for(int i=0; i<1000; i++){PacketFormat pack = new PacketFormat();pack.setProperty("msg", "test");byte[] buff = new byte[128];int packLen = pack.getBytes(buff, 0);DatagramPacket data = new DatagramPacket(buff,0,packLen);udpSenderService.addTimingRequest(System.currentTimeMillis()+rand.nextInt(300)+1000, data);try {Thread.sleep(10);} catch (InterruptedException e) {}}try{Thread.sleep(1000*60*2);udpSenderService.shutdown();System.err.println("udp服务关闭.");}catch(Exception ex){}}}


原创粉丝点击