公司内网UDP传文件,整体使用的是旧io的 DataGramSocket .
1. 发送方使用MappedByteBuffer不停发,
2. 接收方写个死循环接收包,每受到一个包直接调用写方法(同样用MappedByteBuffer写文件),写完后继续收包.目前遇到的情况是,除去校验,(可以看出以上方法没有任何校验机制),接收方接收文件占cpu很高,双核的机器一般 cpu 在 45%左右 没秒 9M ,公司的烂电脑奔四1.7 cpu 90%以上每秒 1M-2M 左右. 曾经试过接收方使用缓存,缓存满了新起线程写,但烂电脑速度依旧. 不太明白瓶颈到底在哪里,难道使用NIO的UDP传输会有改善么???
代码如下 :  public void run() {
try {
while (true) {
byte[] buff = new byte[fpSize];
final DatagramPacket dp = new DatagramPacket(buff, buff.length);
senderSocket.receive(dp);
// 命令 判断包的类型
int command = 9;
long fileSessionId = 0;
try {
command = dp.getData()[0];
fileSessionId = ByteOperatorUtil.getLong(buff, 1);
} catch (RuntimeException e) {
e.printStackTrace();
}
switch (command) {
case 1:
// 接收方接收发送方的文件分片包
if (UdpFileTransfer.getInstance().getUdpWatchers()
.containsKey(fileSessionId)) {
FileWatcherUdp watcher = UdpFileTransfer.getInstance()
.getUdpWatchers().get(fileSessionId);
boolean isFinished = watcher.writeFile(dp);        // 写文件
FileEvent fe = new FileEvent(watcher);
if (isFinished) {
// //文件传输结束,接收方移除FileReceiverUdp
// UdpFileTransfer.getInstance().getUdpWatchers().remove(
// fileSessionId);
watcher.getFileListener().fileFinished(fe);
} else {
watcher.getFileListener().fileInProgress(fe);
}
} else {
log.info("收到未知的文件传输包,或者该文件已经被拒绝接收");
}
break;
case 2:

break;
case 3:

break;
case 4:
System.out.println("4 start");
// 文件传输前,接收方收到发送方的打洞请求包
buff[0] = 5;
ByteOperatorUtil.putLong(buff, 1, fileSessionId);
DatagramPacket d = new DatagramPacket(buff, buff.length, dp
.getAddress(), dp.getPort());
for (int i = 0; i < 10; i++) {
senderSocket.send(d);
}
break;
case 5:
System.out.println("5 start");
// 发送方收到打洞回复确认包
if (UdpFileTransfer.getInstance().getUdpWatchers()
.containsKey(fileSessionId)) {
UdpFileTransfer.getInstance().getUdpWatchers().get(
fileSessionId).setFileTransferStatus(
FileWatcherUdp.STATUS_CONNECTED);
}
break;
default:
break;
}
}
} catch (Exception e) {
log.error("UDP 包监听出错", e);
e.printStackTrace();
}
} // 写文件
public boolean writeFile(DatagramPacket dp) throws FileNotFoundException {
// 如果第一次受到packet,那么开始启动window监听
if (wml == null) {
startTime = System.currentTimeMillis();
wml = new WindowModifyListener();
wml.start();
}
byte[] buff = dp.getData();
int index = ByteOperatorUtil.getInt(buff, 9);
int id = ByteOperatorUtil.getInt(buff, 25);
if (replyId < id) {
replyId = id;
}
// 存入当前一系列请求的map中
//receiveMap.get(replyId).add(index);
// 如果不在窗口之内,那么抛弃
if ((!window.contains(index)) && index <= maxSize) {
return false;
}
if (this.index < index) {
this.index = index;
}
long offset = ByteOperatorUtil.getLong(buff, 13);
int len = ByteOperatorUtil.getInt(buff, 21);
writeSingleFile(buff, index, offset, len, 29);
inProgressEvent();
long finishSize = 0L;
finishSize = completeSize;
if (finishSize >= fileSize) {
long finishTime = System.currentTimeMillis();
fileTransferStatus = FileWatcher.STATUS_RECEIVER_FINISH;
log.info("文件已经成功接收  停止监听线程");
long time = finishTime - startTime;
if (time == 0L)
time = 1L;
log.info("传输速度 " + fileSize / time);
finishEvent();
try {
clean(out);
} catch (Exception e) {
e.printStackTrace();
}
out.clear();
// 停止监听线程
wml.interrupt();
return true;
}
return false;
} /**
 * 写普通文件
 *
 * @param buff
 * @param index
 * @param offset
 * @param len
 * @throws FileNotFoundException
 */
private void writeSingleFile(byte[] buff, int index, Long offset, int len,
int dataOffset) throws FileNotFoundException {
try {
if (raf == null) {
raf = new RandomAccessFile(file, "rw");
}
out = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, offset,len);
out.put(buff, dataOffset, len);
completeSize += len;
window.remove(index);
logList.add(index);
windowTimeStamp = System.currentTimeMillis();
} catch (IOException e) {
log.error("UDP 写文件出错", e);
e.printStackTrace();
}
}

解决方案 »

  1.   

    高手帮忙啊.............. 给个思路也行,但一定要是UDP传输
      

  2.   

    用性能分析的软件跟踪一下
    如 Jprofiler
    看看是什么对象新建的多估计都是IO对象新建的太多
      

  3.   

    空循环的话也是很费cpu的...你看看是不是在空循环的时候加个sleep()....我很怀疑是这个问题.
      

  4.   

    楼上的 , Udp receive 是堵塞的啊.... 没有包循环就停了么,为什么还要加sleep呢???
      

  5.   

    恩 网上看到发送udp包 最好sleep(10),为了不把缓存耗尽,有这个说法么???
      

  6.   

    要不你试试看JVM参数给多一些内存, 类似 -Xms512M -Xmx1024M -XX:PermSize=128M -XX:MaxPermSize=512M 毕竟Java不如C++那么方便可以自己管理内存, 默认的JVM内存参数也许不够大, 造成频繁回收导致CPU占用率过高. 你可以试试看一些不用的对象 XXX = null; 看看会否提高一些内存回收效率