android 使用asmack库进行文件收发

网友 t8500071说asmack有更新了,去http://code.google.com/p/asmack/看了下,现在代码转到    https://github.com/Flowdalic/asmack  


所以大家可以直接去下官方的测试,下面的没啥用了。。


之前记录了部分的怎么用smack进行连接、登录、聊天等等,这边就接着说文件传输,看官方的文档,

http://www.igniterealtime.org/builds/smack/docs/latest/documentation/extensions/index.html

看完文档你会觉得好简单呐,不过要操作起来真的挺要命的,至少我挺纠结的。

先说步骤

1、创建一个文件传输管理的类

      // Create the file transfer manager
      FileTransferManager manager = new FileTransferManager(connection);
2、从这个管理类创建一个向  特定用户  发送文件的输出类

      // Create the outgoing file transfer
      OutgoingFileTransfer transfer = manager.createOutgoingFileTransfer("romeo@montague.net"); //这边用户要为 完整的jid,user@servername/resource
      // Send the file
      transfer.sendFile(new File("shakespeare_complete_works.txt"), "You won't believe this!");
3、接收文件即直接加个监听器

       // Create the listener
      manager.addFileTransferListener(new FileTransferListener() {
            public void fileTransferRequest(FileTransferRequest request) {
                  // Check to see if the request should be accepted
                  if(shouldAccept(request)) {
                        // Accept it
                        IncomingFileTransfer transfer = request.accept();
                        transfer.recieveFile(new File("shakespeare_complete_works.txt"));
                  } else {
                        // Reject it
                        request.reject();  // 拒绝接收文件。
                  }
            }
      });
4、查看文件收发的状态

while(!transfer.isDone()) {     //可以直接加到  transfer.sendFile 或者  transfer.recieveFile 后面。
            if(transfer.getStatus().equals(Status.ERROR)) {
                  System.out.println("ERROR!!! " + transfer.getError());
            } else {
                  System.out.println(transfer.getStatus());
                  System.out.println(transfer.getProgress());
            }
            sleep(1000);
      }

如果是smack在Pc运行的话,服务器配置没问题,一般就没问题了。<1>

我这边的库可以了,我会上传供大家测试哈。

在文件传输这个环节,服务器的配置挺还是很重要的,因为文件传输使用到了两种协议,IBB协议和S5B协议,协议介绍看这里

其中在文件传输过程中,由更顶层协议去裁判,是否传输文件,如果是则使用哪种协议进行传输,(如果S5B可用,默认S5B),我使用的这个库也是这样。我尝试过很多版本的asmack库,都不行,衰人一个啊。后面就还是慢慢来吧,看下源码好了。我说下我遇到情况。

出现错误且里面 有说到<streamhost jid="myid@mydomain.com/smack" host="127.0.0.1" port="7777"/>,就是asmack库里面的一个函数错了,直接返回127.0.0.1这个IP,修改org.jivesoftware.smackx.filetransfer.Socks5TransferNegotiator中的函数:

private String discoverLocalIP() throws UnknownHostException {
		try {
			for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
				NetworkInterface intf = en.nextElement();
				for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
					InetAddress inetAddress = enumIpAddr.nextElement();
					if (!inetAddress.isLoopbackAddress()) {
						return inetAddress.getHostAddress().toString();
					}
				}
			}
		} catch (SocketException ex) {
			Logger.error("Error retrieving the local IP", ex);
		}
		throw new UnknownHostException("Failed to retrieve local IP");
              //return InetAddress.getLocalHost().getHostAddress();   //注释掉原本的代码
    }
这样保证返回的android机子的ip不是127.0.0.1。

因为在S5B协议里面,有一个<streamhost host=""  jid="" port="" />的元素,这个是用于告诉对方本机可以用于建立文件传输的stream流的host,如果你发送了一个host为127.0.0.1的话,那对方在判断这个地址的时候,会误判为可以用(应该是这个地址是特殊地址,本地回路嘛),然后对方会回复一个result给你告诉你他那边确认OK,然后这个时候,不论是你还对方,都无法把stream流建立起来的。所以上面就是为了屏蔽127.0.0.1,获得真实的本地IP。


上面的解决办法是可以行的。不过还有一种方法就是直接不让你这个客户端找到本地ip,这样你这边就没有<streamhost host=""  jid="" port="" />这个东西了,你就会去向服务器请求,查询服务器的代理,一般会有一个proxy.server-name这样的一个代理,这个代理的ip來至哪里?看openfire服务器,你很容易可以发现,服务器的server-name就是你的计算机名字,在/etc/hosts里面添加你的当前PC的IP和计算机名,之后重启服务器,服务器就会将server-name绑定到当前的IP上,proxy.your-openfire-host这个代理的IP跟服务器的IP一样,这样客服端就可以找到proxy.server-name代理的IP,之后两个客服端就会建立一个用使用代理而建立起来的stream流,然后开始传输文件。


当然,上面的方法还是挺OK的,不过我还发现了一个方法,其实也就是在你不让客服端不发现的本地IP和proxy.server-name所对应的IP为NULL的时候,客户端会放弃使用S5B,而使用IBB,这个使用协议是默认的,名字翻译过来就是带内字节流,带内?带内我个人理解是把要发送的文件分割,然后放在packet里面进行传输,而不像S5B那样再建立一个stream流。如果你用IBB发送文件的时候,你打开DEBUG,你就可以在发送的packet里面看到一堆被格式化过的文字,那些就是被传输文件的数据啦。


我自己改的 asmack  :http://download.csdn.net/detail/shmcclmm/5046135

我修改的是 org.jivesoftware.smackx/bytestreams/Socks5BytestreamManager.java 这个文件








  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
要在Android Studio中实现蓝牙收发文件的功能,可以使用以下步骤: 1. 首先,确保手机是否支持蓝牙功能。可以使用以下代码检查蓝牙是否已打开: ```java if (mBluetoothAdapter == null) { Toast.makeText(getApplicationContext(), "无法打开手机蓝牙,请确认手机是否有蓝牙功能!", Toast.LENGTH_SHORT).show(); finish(); return; } ``` 2. 接下来,可以使用一个蓝牙来简化蓝牙操作。例如,你可以使用一个名为"Android Studio 的蓝牙串口通信"的依赖,它提供了方便的方法来实现蓝牙通信功能。 3. 在你的布局文件中添加一个按钮用于连接蓝牙设备: ```xml <Button android:id="@+id/connectButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="连接" /> ``` 4. 在你的Java代码中,为按钮添加点击事件处理程序,并在其中实现连接和断开蓝牙设备的逻辑: ```java final Button connectButton = findViewById(R.id.connectButton); connectButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mBluetoothAdapter.isEnabled() == false) { Toast.makeText(getApplicationContext(), "请先打开蓝牙", Toast.LENGTH_LONG).show(); return; } if (mBluetoothSocket == null) { // 如果未连接设备,则打开DevicesListActivity搜索设备 Intent serveIntent = new Intent(getApplicationContext(), DevicesListActivity.class); startActivityForResult(serveIntent, 1); // 设置返回宏定义 } else { // 关闭连接socket try { bRun = false; Thread.sleep(2000); is.close(); mBluetoothSocket.close(); mBluetoothSocket = null; connectButton.setText("连接"); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } }); ``` 以上是在Android Studio中实现蓝牙收发文件的基本步骤。你可以根据需要进一步完善和扩展这些功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值