點對點檔案傳輸,Android無網路傳輸檔案的原理
昨日,上海交通執法部門在虹橋機場、虹橋火車站等共14個執法點開展了代號為“天網2號”的網約車非法客運專項整治行動。當天行動累計查處利用網約平臺從事非法客運的案件37件,其中“滴滴”29件,“美團”6件,“神州”1件,“嘀嗒”1件。這些車輛及駕駛員均無營運資質,他們通過自己在網約平臺軟體上的註冊賬號接單,將乘客送至目的地,並收取車費。
明天就是清明小長假了,希望大家都能好好享受這幾天的假期時光,我們清明節後見!
本篇來自 葉應是葉 的投稿,分享了Android 實現無網路傳輸檔案,一起來看看!希望大家喜歡。
葉應是葉 的部落格地址:
https://www.jianshu.com/u/9df45b87cfdf
最近的專案需要實現一個Android手機之間無網路傳輸檔案的功能,就發現了Wifi P2P(Wifi點對點)這麼一個功能,最後也實現了通過Wifi 隔空傳輸檔案的功能,這裡我也來整理下程式碼,分享給大家。
Wifi P2P是在Android 4.0以及更高版本系統中加入的功能,通過Wifi P2P可以在不連線網路的情況下,直接與配對的裝置進行資料交換。相對於藍芽,Wifi P2P的搜尋速度和傳輸速度更快,傳輸距離更遠
實現的效果如下所示:
一般而言,開發步驟分為以下幾點:
在AndroidManifest中宣告相關許可權(網路和檔案讀寫許可權)
獲取WifiP2pManager,註冊相關廣播監聽Wifi直連的狀態變化
指定某一臺裝置為伺服器(用來接收檔案),建立群組並作為群主存在,在指定埠監聽客戶端的連線請求,等待客戶端發起連線請求以及檔案傳輸請求
客戶端(用來發送檔案)主動搜尋附近的裝置,加入到伺服器建立的群組,獲取伺服器的IP地址,向其發起檔案傳輸請求
校驗檔案完整性
宣告許可權
Wifi P2P技術並不訪問網路,但由於會使用到Java套接字,所以需要申請網路許可權。此外,由於是要實現檔案互傳,所以也需要申請SD卡讀寫許可權。
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
註冊廣播
與Wifi P2P相關的廣播有以下幾個:
WIFI_P2P_STATE_CHANGED_ACTION(用於指示Wifi P2P是否可用)
WIFI_P2P_PEERS_CHANGED_ACTION(對等節點列表發生了變化)
WIFI_P2P_CONNECTION_CHANGED_ACTION(Wifi P2P的連線狀態發生了改變)
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION(本裝置的裝置資訊發生了變化)
當接收到這幾個廣播時,我們都需要到WifiP2pManager(對等網路管理器)來進行相應的資訊請求,此外還需要用到Channel物件作為請求引數
mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mWifiP2pManager.initialize(this, getMainLooper(), this);
當收到WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION廣播時,可以判斷當前Wifi P2P是否可用
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
mDirectActionListener.wifiP2pEnabled(true);
} else {
mDirectActionListener.wifiP2pEnabled(false);
}
當收到WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION廣播時,意味裝置周圍的可用裝置列表發生了變化,可以通過requestPeers方法得到可用的裝置列表,之後就可以選擇當中的某一個裝置進行連線操作
mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {
@Override
public void onPeersAvailable(WifiP2pDeviceList peers) {
mDirectActionListener.onPeersAvailable(peers.getDeviceList());
}
});
當收到WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION廣播時,意味著Wifi P2P的連線狀態發生了變化,可能是連線到了某裝置,或者是與某裝置斷開了連線
NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) {
mWifiP2pManager.requestConnectionInfo(mChannel, new WifiP2pManager.ConnectionInfoListener() {
@Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
mDirectActionListener.onConnectionInfoAvailable(info);
}
});
Log.e(TAG, "已連線p2p裝置");
} else {
mDirectActionListener.onDisconnection();
Log.e(TAG, "與p2p裝置已斷開連線");
}
如果是與某裝置連線上了,則可以通過requestConnectionInfo方法獲取到連線資訊。
當收到WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION廣播時,則可以獲取到本裝置變化後的裝置資訊
(WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)
可以看出Wifi P2P的介面高度非同步化,到現在已經用到了三個系統的回撥函式,一個用於WifiP2pManager的初始化,兩個用於在廣播中非同步請求資料,為了簡化操作,此處統一使用一個自定義的回撥函式,方法含義與系統的回撥函式一致
public interface DirectActionListener extends WifiP2pManager.ChannelListener {
void wifiP2pEnabled(boolean enabled);
void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo);
void onDisconnection();
void onSelfDeviceAvailable(WifiP2pDevice wifiP2pDevice);
void onPeersAvailable(Collection<WifiP2pDevice> wifiP2pDeviceList);
}
所以,整個廣播接收器使用到的所有程式碼是:
/**
* 作者:chenZY
* 時間:2018/2/9 17:53
* 描述:
*/
public class DirectBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "DirectBroadcastReceiver";
private WifiP2pManager mWifiP2pManager;
private WifiP2pManager.Channel mChannel;
private DirectActionListener mDirectActionListener;
public DirectBroadcastReceiver(WifiP2pManager wifiP2pManager, WifiP2pManager.Channel channel, DirectActionListener directActionListener) {
mWifiP2pManager = wifiP2pManager;
mChannel = channel;
mDirectActionListener = directActionListener;
}
public static IntentFilter getIntentFilter() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
return intentFilter;
}
@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "接收到廣播: " + intent.getAction());
if (!TextUtils.isEmpty(intent.getAction())) {
switch (intent.getAction()) {
// 用於指示 Wifi P2P 是否可用
case WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION: {
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
mDirectActionListener.wifiP2pEnabled(true);
} else {
mDirectActionListener.wifiP2pEnabled(false);
List<WifiP2pDevice> wifiP2pDeviceList = new ArrayList<>();
mDirectActionListener.onPeersAvailable(wifiP2pDeviceList);
}
break;
}
// 對等節點列表發生了變化
case WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION: {
mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {
@Override
public void onPeersAvailable(WifiP2pDeviceList peers) {
mDirectActionListener.onPeersAvailable(peers.getDeviceList());
}
});
break;
}
// Wifi P2P 的連線狀態發生了改變
case WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION: {
NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) {
mWifiP2pManager.requestConnectionInfo(mChannel, new WifiP2pManager.ConnectionInfoListener() {
@Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
mDirectActionListener.onConnectionInfoAvailable(info);
}
});
Log.e(TAG, "已連線p2p裝置");
} else {
mDirectActionListener.onDisconnection();
Log.e(TAG, "與p2p裝置已斷開連線");
}
break;
}
//本裝置的裝置資訊發生了變化
case WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: {
mDirectActionListener.onSelfDeviceAvailable((WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
break;
}
}
}
}
}
伺服器端建立群組
假設當裝置甲搜尋到了裝置B,並與裝置乙連線到了一起,此時系統會自動建立一個群組(集團)並隨機指定一臺裝置為群主(GroupOwner)。此時,對於兩臺裝置來說,群主的IP地址是可知的(系統回撥函式中有提供),但客戶端的IP地址需要再來通過其他方法來主動獲取。例如,可以在裝置連線成功後,客戶端主動發起對伺服器端的插座連線請求,伺服器端在指定埠監聽客戶端的連線請求,當連線成功後,伺服器端就可以獲取到客戶端的IP地址了。此處為了簡化操作,直接指定某臺裝置作為伺服器端(群主),即直接指定某臺裝置用來接收檔案。因此,伺服器端要主動建立群組,並等待客戶端的連線。
wifiP2pManager.createGroup(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.e(TAG, "createGroup onSuccess");
dismissLoadingDialog();
showToast("onSuccess");
}
@Override
public void onFailure(int reason) {
Log.e(TAG, "createGroup onFailure: " + reason);
dismissLoadingDialog();
showToast("onFailure");
}
});
此處,使用IntentService在後臺監聽客戶端的Socket連線請求,並通過輸入輸出流來傳輸檔案。此處的程式碼比較簡單,就是在指定埠一直堵塞監聽客戶端的連線請求,獲取待傳輸的檔案資訊模型FileTransfer,之後就進行實際的資料傳輸
@Override
protected void onHandleIntent(Intent intent) {
clean();
File file = null;
try {
serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(PORT));
Socket client = serverSocket.accept();
Log.e(TAG, "客戶端IP地址 : " + client.getInetAddress().getHostAddress());
inputStream = client.getInputStream();
objectInputStream = new ObjectInputStream(inputStream);
FileTransfer fileTransfer = (FileTransfer) objectInputStream.readObject();
Log.e(TAG, "待接收的檔案: " + fileTransfer);
String name = new File(fileTransfer.getFilePath()).getName();
//將檔案儲存至指定位置
file = new File(Environment.getExternalStorageDirectory() + "/" + name);
fileOutputStream = new FileOutputStream(file);
byte buf[] = new byte[512];
int len;
long total = 0;
int progress;
while ((len = inputStream.read(buf)) != -1) {
fileOutputStream.write(buf, 0, len);
total += len;
progress = (int) ((total * 100) / fileTransfer.getFileLength());
Log.e(TAG, "檔案接收進度: " + progress);
if (progressChangListener != null) {
progressChangListener.onProgressChanged(fileTransfer, progress);
}
}
serverSocket.close();
inputStream.close();
objectInputStream.close();
fileOutputStream.close();
serverSocket = null;
inputStream = null;
objectInputStream = null;
fileOutputStream = null;
Log.e(TAG, "檔案接收成功,檔案的MD5碼是:" + Md5Util.getMd5(file));
} catch (Exception e) {
Log.e(TAG, "檔案接收 Exception: " + e.getMessage());
} finally {
clean();
if (progressChangListener != null) {
progressChangListener.onTransferFinished(file);
}
//再次啟動服務,等待客戶端下次連線
startService(new Intent(this, WifiServerService.class));
}
}
因為客戶端可能會多次發起連線請求,所以當此處理檔案傳輸完成後(不管成功或失敗),都需要重新startService,讓服務再次堵塞等待客戶端的連線請求。
FileTransfer包含三個欄位,MD5碼值用於校驗檔案的完整性,fileLength是為了用於計算檔案的傳輸進度。
public class FileTransfer implements
相關推薦
點對點檔案傳輸,Android無網路傳輸檔案的原理
今日科技快訊昨日,上海交通執法部門在虹橋機場、虹橋火車站等共14個執法點開展了代號為“天網2號”
比特幣交易所面臨倒閉,點對點、場外交易將盛行
上進 str 訂單 虛擬 交易所 服務 com 交易 比特
9月16日火幣網、OKCoin聲稱要關閉所有虛擬幣業務,關閉交易和關閉交易所是兩個概念。
sosobtc官網也發布通告:於19日晚間23點關閉網站的行情數據、聊天社交等信息服務,APP也將於3日內關閉相關服務。
【51NOD1766】樹上的最遠點對(線段樹,LCA,RMQ)
long exit div ssi put lac shu 最值 最遠點對 題意:n個點被n-1條邊連接成了一顆樹,給出a~b和c~d兩個區間,
表示點的標號請你求出兩個區間內各選一點之間的最大距離,即你需要求出max{dis(i,j) |a<=i<=b,c&l
【181027】聊天室程式,點對點,VC++程式原始碼
基於VC++的點對點聊天室程式,程式包括服務端和客戶端,伺服器程式是chatsrvr.exe,客戶端是ChatClient.exe. 伺服器先執行,客戶連線到伺服器執行的計算機的IP即可。在客戶端傳送訊息的時候,可選擇字型顏色、聊天物件、過濾、是否設定為悄悄話等,都是相對基礎點的功能,希望剛
區塊鏈C2C點對點系統搭建,區塊鏈點對點交易系統的兩種交易模式你知道嗎?
在平時的交易過程中由於法幣交易受國家監管限制,現在許多交易所都沒有法幣交易版塊,我們平時看到的許多大型的交易所上面寫的是法幣交易,但是卻不是真正的法幣交易,而是點對點交易模式,像比較常見的ZB交易平臺,上面寫著法幣交易,確實C2C點對點交易模式,那麼接下來源中瑞黃顧問(具體加vx:ruiec1688)就給大家
Spring Boot整合websocket實現群聊,點對點聊天,圖片傳送,音訊傳送
參考:基於https://blog.csdn.net/qq_38455201/article/details/80374712 基礎上進行新增圖片傳送和音訊傳送功能
單點圖片傳送:
單點音訊傳送:
音訊傳送相關js參考:https://github.
Altium軟體怎麼測量點對點的距離,怎麼測量邊緣與邊緣之間的距離
Altium軟體怎麼測量點對點的距離,怎麼測量邊緣與邊緣之間的距離
Altium提供了兩種方式進行測量,一種是點對點的測量,一種是邊緣和邊緣的距離測量,其操作命令分別是:
點對點:Reports-M
快速利用第三方平臺SDK,實現點對點語音通話
最近公司的一個APP專案需要一個加一個網際網路點對點語音功能,網上找了Linphone 研究了一個月發現這些開源庫很強大也很優秀,支援平臺廣泛 windows, mac,ios,android,linux,但是程式碼量和結構實在龐大,坑爹的專案經理要求一個月把這個功
區塊鏈支付系統開發,點對點支付系統開發
支付行業發展最快的領域是移動支付,但是現在最吸引大家眼球的當屬區塊鏈。現下,區塊鏈成為金融科技領域的大熱門,區塊鏈技術在各個行業領域有著廣泛的應用。那麼,“區塊鏈與支付”這個組合能不能友好的合作,是否能達到人們的預期,還要進一步驗證。跨境支付主要有銀行電匯、第三方支付和提現三種主要方式,但是均存在手續費高、流
SpringBoot整合WebSocket【基於STOMP協議】進行點對點[一對一]和廣播[一對多]實時推送,內附簡易聊天室demo
最近專案來了新需求,需要做一個實時推送的功能,伺服器主動推送訊息給客戶端,在網上經過一輪搜查之後,確定使用WebSocket來進行開發。以前經常聽說WebSocket的神奇之處,如今終於可以嘗試使用它了。1.淺談WebSocketWebSocket是在HTML5基礎上單個TC
C#完整的通訊程式碼(點對點,點對多,同步,非同步,UDP,TCP)
C# code
namespace UDPServer
{
class Program
{
static void Main(string[] args)
{
int recv;
byte[] data = new byte[1024];
//構建TCP 伺服器
//得到本機IP,設定TCP埠號
IPEnd
ActiveMQ的使用與遇到的相關坑(點對點,釋出與訂閱,resreq)
1、介紹
ActiveMQ是Apache出品,最流行的,能力強勁的開源訊息匯流排。ActiveMQ 是一個完全支援JMS1.1和J2EE 1.4規範的 JMS Provider實現,儘管JMS規範出臺已經是很久的事情了,但是JMS在當今的J2EE應用中間仍然扮演著特殊的地位
Android websocket長連線+點對點訂閱
專案中使用到了websocket長連線+點對點訂閱,部落格記錄下。
長連線通常使用的是名稱叫做STOMP的協議,具體跟伺服器端的開發人員確認即可。
直接貼乾貨:
module build.gradle新增依賴:
compile 'com.github.NaikS
使用ActiveMQ+MQTT實現Android點對點訊息通知
使用ActiveMQ+MQTT實現Android點對點訊息通知
[email protected]
2013-12-20
實現點對點訊息通知的關鍵問題
ActiveMQ使用MQTT協議,加上android上的paho包,即可簡單實現訊息通知功能,但是mqtt協議只
JMS消息隊列ActiveMQ(點對點模式)
jms activemq 消息隊列 生產者(producer)->消息隊列(message queue)package com.java1234.activemq;
import javax.jms.Connection;
import javax.jms.ConnectionFactor
境外“點對點|場外交易OTC新模式數字貨幣開發”強勢來襲
數字貨幣 點對點 場外交易 系統開發 境外“點對點|場外交易OTC新模式數字貨幣開發”強勢來襲
當下面臨著國家監管的政策,行情的變化,很多交易平臺紛紛關閉,傳統的撮合交易系統退出了歷史的舞臺,很多玩家現在出現了問題,自己的幣去哪交易呢?如過交易平臺關了就沒有市場進行交易了呀!針對這個問題出現
activeMQ點對點
ssa oca exceptio pac 開啟事務 ive mes 啟動 cal
摘要: ActiveMQ 點對點消息 Point-to-Point 是一對一
創建消息生產者
/**
* 點對點消息生產者
*
* @author Edward
*
*/
分析比特幣網絡:一種去中心化、點對點的網絡架構
比特幣 區塊鏈 比特幣采用了基於互聯網的點對點(P2P:peer-to-peer)分布式網絡架構。比特幣網絡可以認為是按照比特幣P2P協議運行的一系列節點的集合。本文來分析下比特幣網絡,了解它跟傳統中心化網絡的區別,以及比特幣網絡是如何發現相鄰節點的。中心化網絡為了更好的理解P2P網絡,我們先來看看傳
HTML5 WebSocket實現點對點聊天的示例代碼
HTML案例分析 HTML5講解 HTML5的websocket與Tomcat實現了多人聊天,那是最簡單也是最基本的,其中註意的就是開發環境,要滿足jdk1.7和tomcat8,當然了tom7的7.063也行,在網站上找到了用google關於websocket的點對點聊天,更好的是可以和大多數系統很好
15、網絡--實驗三(搭建點對點VXLAN網絡)
linux hostman docker network 先來搭建一個最簡單的vxlan網絡,兩個namespace構成一個vxlan網絡,每個vxlan網絡上有一個vnet,vnet通過它們的IP互相通信.1) 創建vnet_pair具體參考”實驗二”章節.http://blog.51cto