这两天在研究openfire+spark+smack(asmack),自己搭建一个IM聊天系统。
asmack在2010年底就不更新了。遗留了很多的bug。
在从spark发送文件到android的时候。状态一直阻塞在 negotiating stream几秒之后。传输结束。返回状态为Error并且拿不到错误消息。折腾了几天。论坛翻了个痛。
参照好多大牛说改写org.jivesoftware.smackx.filetransfer.Socks5TransferNegotiator.discoverLocalIP()方法。尼玛我搞的源码的Socks5TransferNegotiator这个类里根本没有discoverLocalIP()方法!
最后在反复尝试下。我搞出了两种方法。
1.这种方法比较流氓。
大致的意思是,你丫收不到就继续收。收到为止。代码片段如下。
public static class RecFileTransferListener implements FileTransferListener {
@Override
public void fileTransferRequest(FileTransferRequest request) {
Log.i("info", "接收文件开始.....");
final IncomingFileTransfer inTransfer = request.accept();
final String fileName = request.getFileName();
long length = request.getFileSize();
Log.i("info", "文件大小:" + length + " " + request.getRequestor());
Log.i("info", "" + request.getMimeType());
try {
final File file = new File("/sdcard/" + fileName);
Log.i("info", file.getAbsolutePath());
new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
try {
inTransfer.recieveFile(file);
while (!inTransfer.getStatus().equals(Status.complete)) {
if (inTransfer.getStatus().equals(Status.error)) {
Log.e("error","ERROR!!! " + inTransfer.getError());
inTransfer.cancel();
inTransfer.recieveFile(file);
} else {
Log.i("info", "status:" + inTransfer.getStatus());
Log.i("info", "process:" + inTransfer.getProgress());
}
}
if (inTransfer.isDone()) {
Log.i("info", "Done+status:" + inTransfer.getStatus());
Log.i("info",
"Done+process:" + inTransfer.getProgress());
}
} catch (XMPPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
这种方法可以再第二次执行recieveFile的时候收到该文件。
2.修改asmack的源码。
我下载的已经是别人改过的。但是在这里也是不能用。只能自己看着改了。照猫画虎了。
源码来源http://www.eoeandroid.com/thread-186418-1-1.html
从recieveFile一步一步debug,最后发现在FaultTolerantNegotiator.createIncomingStream()方法执行时会报ExecutionException:No response from remote client
下面是改好的方法
public InputStream createIncomingStream(StreamInitiation initiation) throws XMPPException {
PacketCollector collector = connection.createPacketCollector(
getInitiationPacketFilter(initiation.getFrom(), initiation.getSessionID()));
System.out.println("From:"+initiation.getFrom());
System.out.println("SessionID:"+initiation.getSessionID());
connection.sendPacket(super.createInitiationAccept(initiation, getNamespaces()));
ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(2);
CompletionService<InputStream> service
= new ExecutorCompletionService<InputStream>(threadPoolExecutor);
List<Future<InputStream>> futures = new ArrayList<Future<InputStream>>();
InputStream stream = null;
XMPPException exception = null;
try {
futures.add(service.submit(new NegotiatorService(collector)));
futures.add(service.submit(new NegotiatorService(collector)));
int i = 0;
while (stream == null && i < futures.size()) {
Future<InputStream> future;
try {
i++;
// future = service.poll(10, TimeUnit.SECONDS);
future = service.take();
}
catch (InterruptedException e) {
continue;
}
if (future == null) {
continue;
}
try {
stream = future.get();
}
catch (InterruptedException e) {
/* Do Nothing */
}
catch (ExecutionException e) {
exception = new XMPPException(e.getCause());
}
}
}
finally {
for (Future<InputStream> future : futures) {
future.cancel(true);
}
collector.cancel();
threadPoolExecutor.shutdownNow();
}
if (stream == null) {
if (exception != null) {
throw exception;
}
else {
throw new XMPPException("File transfer negotiation failed.");
}
}
return stream;
}
将
future = service.poll(10, TimeUnit.SECONDS);
改为
future = service.take();
这两句区别在于poll取task有超时时间为10s
take没有设置超时时间,知道有下一个task返回为止。
另外还要修改另一个地方的代码。
org.jivesoftware.smack.PacketCollector的nextResult(long timeout)方法。将poll的时间增加10s
public Packet nextResult(long timeout) {
long endTime = System.currentTimeMillis() + timeout;
do {
try {
return resultQueue.poll(timeout+10000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) { /* ignore */ }
} while (System.currentTimeMillis() < endTime);
return null;
}
OK.这样再把他生成jar然后build进你的项目里。这个该死的negotiating stream就不会出现了。
具体的原因我也大搞不懂为什么这个改就OK。还希望看到得大牛指点一二。