原文链接:http://blog.csdn.net/myatlantis/article/details/68067742
原文参考了以下博客和资料:
- Android如何实现茄子快传
- [Java TCP/IP Socket] — 单播、广播、组播
- java socket传多个文件的疑问
最近把测试丢过来的种种BUG解决后,终于有时间去研究研究Socket通信,再加上以前做的WiFi连接和热点开启,于是有了现在的这篇博文:创建热点发送文件,让另一台手机连接热点接收文件。
效果图:
两台设备是如何传输文件的:
- 发送端->创建WiFi热点
- 接收端->连接热点
- 发送端->发送文件列表
- 接收端->收到后展示文件列表,选择要接收的文件发送给发送端
- 发送端->发送所选文件
- 接收端->开始接收…
发送端->创建WiFi热点:
由于Android没有直接开启热点的API,所以我们这里采用反射。
/** * 开启便携热点 * @param context 上下文 * @param SSID 便携热点SSID * @param password 便携热点密码 * @return */public static boolean openAp(Context context, String SSID, String password) { if(TextUtils.isEmpty(SSID)) { return false; } WifiManager wifiManager = (WifiManager) context.getSystemService(context.WIFI_SERVICE); if (wifiManager.isWifiEnabled()) { wifiManager.setWifiEnabled(false); } WifiConfiguration wifiConfiguration = getApConfig(SSID, password); try { if(wifiManager.isWifiEnabled()) { wifiManager.setWifiEnabled(false); } if(isApOn(context)) { closeAp(context); } Method method = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class); method.invoke(wifiManager, wifiConfiguration, true); return true; } catch (Exception e) { e.printStackTrace(); } return false;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
接收端->连接热点:
连接热点前先开启WiFi广播监听事件,然后开启WiFi,扫描周围可用WiFi列表,拿到SSID再进行连接,最后在WiFi广播监听事件中比较已连接WIFI的SSID是否正确。
WiFi广播监听事件:
/** * 注册监听WiFi操作的系统广播 */private void registerWifiReceiver() { IntentFilter filter = new IntentFilter(); filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); registerReceiver(mWifiBroadcaseReceiver, filter);}/** * 反注册WiFi相关的系统广播 */private void unregisterWifiReceiver() { if (mWifiBroadcaseReceiver != null) { unregisterReceiver(mWifiBroadcaseReceiver); mWifiBroadcaseReceiver = null; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
WiFi广播接收器:
public abstract class WifiBroadcaseReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if(intent != null) { if(intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0); if(wifiState == WifiManager.WIFI_STATE_ENABLED) { onWifiEnabled(); } else if(wifiState == WifiManager.WIFI_STATE_DISABLED) { onWifiDisabled(); } } else if(intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { WifiMgr wifiMgr = new WifiMgr(context); List<ScanResult> scanResults = wifiMgr.getScanResults(); if(wifiMgr.isWifiEnabled() && scanResults != null && scanResults.size() > 0) { onScanResultsAvailable(scanResults); } } else if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); if (info != null) { if (info.getState().equals(NetworkInfo.State.CONNECTED)) { WifiMgr wifiMgr = new WifiMgr(context); String connectedSSID = wifiMgr.getConnectedSSID(); onWifiConnected(connectedSSID); } else if (info.getState().equals(NetworkInfo.State.DISCONNECTED)) { onWifiDisconnected(); } } } } } public abstract void onWifiEnabled(); public abstract void onWifiDisabled(); public abstract void onScanResultsAvailable(List<ScanResult> scanResults); public abstract void onWifiConnected(String connectedSSID); public abstract void onWifiDisconnected();}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
打开和关闭WiFi:
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);/** * 打开WiFi */public void openWifi() { if (!mWifiManager.isWifiEnabled()) { mWifiManager.setWifiEnabled(true); }}/** * 关闭WiFi */public void closeWifi() { if (mWifiManager.isWifiEnabled()) { mWifiManager.setWifiEnabled(false); }/** * 当前WiFi是否开启 */public boolean isWifiEnabled() { return mWifiManager.isWifiEnabled();}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
扫描周围可用WiFi列表:
/** * 扫描周围可用WiFi * @return */public boolean startScan() { if(isWifiEnabled()) { return mWifiManager.startScan(); } return false;}
拿到WiFi扫描结果并且连接热点,当接收端连接成功后,会发一个UDP广播告知局域网内设备连接热点成功:
/** * WiFi广播接收器 */private WifiBroadcaseReceiver mWifiBroadcaseReceiver = new WifiBroadcaseReceiver() { @Override public void onWifiEnabled() { mWifiMgr.startScan(); } @Override public void onWifiDisabled() { mSelectedSSID = ""; mScanResults.clear(); setupWifiAdapter(); } @Override public void onScanResultsAvailable(List<ScanResult> scanResults) { mScanResults.clear(); mScanResults.addAll(scanResults); setupWifiAdapter(); } @Override public void onWifiConnected(String connectedSSID) { if (connectedSSID.equals(mSelectedSSID) && !mIsSendInitOrder) { mHandler.sendEmptyMessage(MSG_FILE_RECEIVER_INIT_SUCCESS); mIsSendInitOrder = true; } else { LogUtils.e("连接到错误WiFi,正在断开重连..."); mWifiMgr.disconnectWifi(connectedSSID); mWifiMgr.startScan(); } } @Override public void onWifiDisconnected() { }};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
发送端->发送文件列表:
当发送端收到初始化完毕指令时,将用UDP广播发送文件列表。
/** * 等待接收端发送初始化完成指令,向其发送文件列表 * @param serverPort * @throws Exception */private void receiveInitSuccessOrder(int serverPort) throws Exception { int tryCount = 0; String localIpAddress = ApMgr.getHotspotLocalIpAddress(getContext()); while (localIpAddress.equals(Consts.DEFAULT_UNKNOW_IP) && tryCount < Consts.DEFAULT_TRY_COUNT) { Thread.sleep(1000); localIpAddress = ApMgr.getHotspotLocalIpAddress(getContext()); tryCount ++; } /** 这里使用UDP发送和接收指令 */ mDatagramSocket = new DatagramSocket(serverPort); while (true) { byte[] receiveData = new byte[1024]; DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); mDatagramSocket.receive(receivePacket); String response = new String(receivePacket.getData()).trim(); if(isNotEmptyString(response)) { LogUtils.e("接收到的消息 -------->>>" + response); if(response.equals(Consts.MSG_FILE_RECEIVER_INIT_SUCCESS)) { mHandler.sendEmptyMessage(MSG_FILE_RECEIVER_INIT_SUCCESS); InetAddress inetAddress = receivePacket.getAddress(); int port = receivePacket.getPort(); sendFileInfoListToFileReceiverWithUdp(inetAddress, port); } else if(response.equals(Consts.MSG_START_SEND)) { initSenderServer(); } else { parseFileInfo(response); } } }}/** * 通过UDP发送文件列表给接收端 * @param ipAddress IP地址 * @param serverPort 端口号 */private void sendFileInfoListToFileReceiverWithUdp(InetAddress ipAddress, int serverPort) { if(!isEmptyList(mAllFileInfos)) { String jsonStr = FileInfo.toJsonStr(mAllFileInfos); DatagramPacket sendFileInfoPacket = new DatagramPacket(jsonStr.getBytes(), jsonStr.getBytes().length, ipAddress, serverPort); try { mDatagramSocket.send(sendFileInfoPacket); LogUtils.i("发送消息 --------->>>" + jsonStr + "=== Success!"); mHandler.obtainMessage(MSG_SET_STATUS, "成功发送文件列表...").sendToTarget(); } catch (IOException e) { e.printStackTrace(); LogUtils.i("发送消息 --------->>>" + jsonStr + "=== 失败!"); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
接收端->选择文件,并告知发送端开始发送:
收到文件列表后,接收端会将文件列表展示在RecyclerView控件,通过选择需要接收的文件,点击“开始发送”按钮,将发送“开始发送”指令到发送端,开启端口进行文件接收。
/** * 设置接收文件列表适配器 */private void setupReceiveFilesAdapter() { List<Map.Entry<String, FileInfo>> fileInfos = AppContext.getAppContext().getReceiverFileInfoMap(); Collections.sort(fileInfos, Consts.DEFAULT_COMPARATOR); mReceiveFilesAdapter = new CommonAdapter<Map.Entry<String, FileInfo>>(getContext(), R.layout.item_files_selector, fileInfos) { @Override protected void convert(ViewHolder holder, Map.Entry<String, FileInfo> fileInfoMap, int position) { final FileInfo fileInfo = fileInfoMap.getValue(); holder.setText(R.id.tv_item_files_selector_file_path, fileInfo.getFilePath()); holder.setText(R.id.tv_item_files_selector_size, FileUtils.FormetFileSize(fileInfo.getSize())); if(fileInfo.getProgress() >= 100) { holder.setText(R.id.tv_item_files_selector_status, "接收完毕"); } else if(fileInfo.getProgress() == 0) { holder.setText(R.id.tv_item_files_selector_status, "准备接收"); } else if(fileInfo.getProgress() < 100) { holder.setText(R.id.tv_item_files_selector_status, "正在接收"); } else { holder.setText(R.id.tv_item_files_selector_status, "接收失败"); } ProgressBar progressBar = holder.getView(R.id.pb_item_files_selector); progressBar.setProgress(fileInfo.getProgress()); CheckBox checkBox = holder.getView(R.id.cb_item_files_selector); checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if(isChecked) { mSendFileInfos.add(fileInfo); } else { mSendFileInfos.remove(fileInfo); } btnSendFileList.setEnabled(mSendFileInfos.size() > 0); } }); } }; mReceiveFilesRecyclerView.setAdapter(mReceiveFilesAdapter); mReceiveFilesRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); mReceiveFilesRecyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL));}/** * 发送选中的文件列表给发送端 */private void sendFileListToFileSender() { new Thread() { @Override public void run() { try { String serverIp = mWifiMgr.getIpAddressFromHotspot(); if(mDatagramSocket == null) { mDatagramSocket = new DatagramSocket(null); mDatagramSocket.setReuseAddress(true); mDatagramSocket.bind(new InetSocketAddress(Consts.DEFAULT_SERVER_UDP_PORT)); } InetAddress ipAddress = InetAddress.getByName(serverIp); String jsonStr = FileInfo.toJsonStr(mSendFileInfos); DatagramPacket sendPacket = new DatagramPacket(jsonStr.getBytes(), jsonStr.getBytes().length, ipAddress, Consts.DEFAULT_SERVER_UDP_PORT); mDatagramSocket.send(sendPacket); LogUtils.i("发送消息 ------->>>" + jsonStr); byte[] sendData = Consts.MSG_START_SEND.getBytes(BaseTransfer.UTF_8); DatagramPacket sendPacket2 = new DatagramPacket(sendData, sendData.length, ipAddress, Consts.DEFAULT_SERVER_UDP_PORT); mDatagramSocket.send(sendPacket2); LogUtils.i("发送消息 ------->>>" + sendData); } catch (Exception e) { e.printStackTrace(); } } }.start();}/** * ServerSocket启动线程 */private class ReceiveServerRunnable implements Runnable { @Override public void run() { try { String serverIp = mWifiMgr.getIpAddressFromHotspot(); List<Map.Entry<String, FileInfo>> fileInfoList = AppContext.getAppContext().getReceiverFileInfoMap(); Collections.sort(fileInfoList, Consts.DEFAULT_COMPARATOR); for(final Map.Entry<String, FileInfo> fileInfoMap : fileInfoList) { final int position = fileInfoList.indexOf(fileInfoMap); mClientSocket = new Socket(serverIp, Consts.DEFAULT_FILE_RECEIVE_SERVER_PORT); FileReceiver fileReceiver = new FileReceiver(mClientSocket, fileInfoMap.getValue()); fileReceiver.setOnReceiveListener(new FileReceiver.OnReceiveListener() { @Override public void onStart() { mHandler.obtainMessage(MSG_SET_STATUS, "开始接收"+ FileUtils.getFileName(fileInfoMap.getValue().getFilePath())).sendToTarget(); } @Override public void onProgress(FileInfo fileInfo, long progress, long total) { int i_progress = (int) (progress * 100 / total); LogUtils.e("正在接收:" + fileInfo.getFilePath() + "\n当前进度:" + i_progress); Message msg = new Message(); msg.what = MSG_UPDATE_PROGRESS; msg.arg1 = position; msg.arg2 = i_progress; mHandler.sendMessage(msg); } @Override public void onSuccess(FileInfo fileInfo) { mHandler.obtainMessage(MSG_SET_STATUS, "文件:" + FileUtils.getFileName(fileInfo.getFilePath()) + "接收成功").sendToTarget(); fileInfo.setResult(FileInfo.FLAG_SUCCESS); AppContext.getAppContext().updateReceiverFileInfo(fileInfo); Message msg = new Message(); msg.what = MSG_UPDATE_PROGRESS; msg.arg1 = position; msg.arg2 = 100; mHandler.sendMessage(msg); } @Override public void onFailure(Throwable throwable, FileInfo fileInfo) { if(fileInfo != null) { mHandler.obtainMessage(MSG_SET_STATUS, "文件:" + FileUtils.getFileName(fileInfo.getFilePath()) + "接收失败").sendToTarget(); fileInfo.setResult(FileInfo.FLAG_FAILURE); AppContext.getAppContext().updateReceiverFileInfo(fileInfo); Message msg = new Message(); msg.what = MSG_UPDATE_PROGRESS; msg.arg1 = position; msg.arg2 = -1; mHandler.sendMessage(msg); } } }); mFileReceiverList.add(fileReceiver); AppContext.getAppContext().MAIN_EXECUTOR.execute(fileReceiver); } } catch (Exception e) { e.printStackTrace(); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
文件接收线程:
public class FileReceiver extends BaseTransfer implements Runnable { /** * 接收文件的Socket的输入输出流 */ private Socket mSocket; private InputStream mInputStream; /** * 待接收的文件数据 */ private FileInfo mFileInfo; /** * 用来控制线程暂停、恢复 */ private final Object LOCK = new Object(); private boolean mIsPaused = false; /** * 设置未执行线程的不执行标识 */ private boolean mIsStop; /** * 该线程是否执行完毕 */ private boolean mIsFinish; /** * 文件接收监听事件 */ private OnReceiveListener mOnReceiveListener; public FileReceiver(Socket socket, FileInfo fileInfo) { mSocket = socket; mFileInfo = fileInfo; } /** * 设置接收监听事件 * @param onReceiveListener */ public void setOnReceiveListener(OnReceiveListener onReceiveListener) { mOnReceiveListener = onReceiveListener; } @Override public void run() { if(mIsStop) { return; } try { if(mOnReceiveListener != null) { mOnReceiveListener.onStart(); } init(); } catch (Exception e) { e.printStackTrace(); LogUtils.i("FileReceiver init() ------->>> occur expection"); if(mOnReceiveListener != null) { mOnReceiveListener.onFailure(e, mFileInfo); } } try { parseBody(); } catch (Exception e) { e.printStackTrace(); LogUtils.i("FileReceiver parseBody() ------->>> occur expection"); if(mOnReceiveListener != null) { mOnReceiveListener.onFailure(e, mFileInfo); } } try { finishTransfer(); } catch (Exception e) { e.printStackTrace(); LogUtils.i("FileReceiver finishTransfer() ------->>> occur expection"); if(mOnReceiveListener != null) { mOnReceiveListener.onFailure(e, mFileInfo); } } } @Override public void init() throws Exception { if(mSocket != null) { mInputStream = mSocket.getInputStream(); } } @Override public void parseBody() throws Exception { if(mFileInfo == null) { return; } long fileSize = mFileInfo.getSize(); OutputStream fos = new FileOutputStream(FileUtils.gerateLocalFile(mFileInfo.getFilePath())); byte[] bytes = new byte[BYTE_SIZE_DATA]; long total = 0; int len = 0; long sTime = System.currentTimeMillis(); long eTime = 0; while ((len = mInputStream.read(bytes)) != -1) { synchronized (LOCK) { if(mIsPaused) { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } fos.write(bytes, 0, len); total = total + len; eTime = System.currentTimeMillis(); if(eTime - sTime > 200) { sTime = eTime; if(mOnReceiveListener != null) { mOnReceiveListener.onProgress(mFileInfo, total, fileSize); } } } } if(mOnReceiveListener != null) { mOnReceiveListener.onSuccess(mFileInfo); } mIsFinish = true; } @Override public void finishTransfer() throws Exception { if(mInputStream != null) { try { mInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if(mSocket != null && mSocket.isConnected()) { try { mSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 暂停接收线程 */ public void pause() { synchronized (LOCK) { mIsPaused = true; LOCK.notifyAll(); } } /** * 恢复接收线程 */ public void resume() { synchronized (LOCK) { mIsPaused = false; LOCK.notifyAll(); } } /** * 设置当前的接收任务不执行 */ public void stop() { mIsStop = true; } /** * 文件是否在接收中 * @return */ public boolean isRunning() { return !mIsFinish; } /** * 文件接收监听事件 */ public interface OnReceiveListener { void onStart(); void onProgress(FileInfo fileInfo, long progress, long total); void onSuccess(FileInfo fileInfo); void onFailure(Throwable throwable, FileInfo fileInfo); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
发送端->发送所选文件:
收到接收端发来的文件列表和“开始发送”指令后,发送端将会把所选文件逐个发送给接收端。
/** * 初始化发送端服务,开始发送文件 */private void initSenderServer() { mSenderServerRunnable = new SenderServerRunnable(); new Thread(mSenderServerRunnable).start();}/** * 文件发送线程 */private class SenderServerRunnable implements Runnable { private ServerSocket mServerSocket; @Override public void run() { try { List<Map.Entry<String, FileInfo>> fileInfoList = AppContext.getAppContext().getSendFileInfoMap(); Collections.sort(fileInfoList, Consts.DEFAULT_COMPARATOR); mServerSocket = new ServerSocket(Consts.DEFAULT_FILE_RECEIVE_SERVER_PORT); for(final Map.Entry<String, FileInfo> fileInfoMap : fileInfoList) { final FileInfo fileInfo = fileInfoMap.getValue(); Socket socket = mServerSocket.accept(); FileSender fileSender = new FileSender(socket, fileInfo); fileSender.setOnSendListener(new FileSender.OnSendListener() { @Override public void onStart() { mHandler.obtainMessage(MSG_SET_STATUS, "开始发送"+ FileUtils.getFileName(fileInfo.getFilePath())).sendToTarget(); } @Override public void onProgress(long progress, long total) { int i_progress = (int) (progress * 100 / total); LogUtils.e("正在发送:" + fileInfo.getFilePath() + "\n当前进度:" + i_progress); Message msg = new Message(); msg.what = MSG_UPDATE_PROGRESS; msg.arg1 = fileInfo.getPosition(); msg.arg2 = i_progress; mHandler.sendMessage(msg); } @Override public void onSuccess(FileInfo fileInfo) { mHandler.obtainMessage(MSG_SET_STATUS, "文件:" + FileUtils.getFileName(fileInfo.getFilePath()) + "发送成功").sendToTarget(); fileInfo.setResult(FileInfo.FLAG_SUCCESS); AppContext.getAppContext().updateSendFileInfo(fileInfo); Message msg = new Message(); msg.what = MSG_UPDATE_PROGRESS; msg.arg1 = fileInfo.getPosition(); msg.arg2 = 100; mHandler.sendMessage(msg); } @Override public void onFailure(Throwable throwable, FileInfo fileInfo) { mHandler.obtainMessage(MSG_SET_STATUS, "文件:" + FileUtils.getFileName(fileInfo.getFilePath()) + "发送失败").sendToTarget(); fileInfo.setResult(FileInfo.FLAG_FAILURE); AppContext.getAppContext().updateSendFileInfo(fileInfo); Message msg = new Message(); msg.what = MSG_UPDATE_PROGRESS; msg.arg1 = fileInfo.getPosition(); msg.arg2 = -1; mHandler.sendMessage(msg); } }); mFileSenderList.add(fileSender); AppContext.FILE_SENDER_EXECUTOR.execute(fileSender); } } catch (IOException e) { e.printStackTrace(); } } /** * 关闭Socket连接 */ public void closeServerSocket() { if(mServerSocket != null) { try { mServerSocket.close(); mServerSocket = null; } catch (IOException e) { e.printStackTrace(); } } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
文件发送线程:
public class FileSender extends BaseTransfer implements Runnable { /** * 待发送的文件数据 */ private FileInfo mFileInfo; /** * 传送文件的Socket输入输出流 */ private Socket mSocket; private OutputStream mOutputStream; /** * 用来控制线程暂停、恢复 */ private final Object LOCK = new Object(); private boolean mIsPause; /** * 该线程是否执行完毕 */ private boolean mIsFinish; /** * 设置未执行线程的不执行标识 */ private boolean mIsStop; /** * 文件传送监听事件 */ private OnSendListener mOnSendListener; public FileSender(Socket socket, FileInfo fileInfo) { mSocket = socket; mFileInfo = fileInfo; } /** * 设置发送监听事件 * @param onSendListener */ public void setOnSendListener(OnSendListener onSendListener) { mOnSendListener = onSendListener; } @Override public void run() { if(mIsStop) { return; } try { if(mOnSendListener != null) { mOnSendListener.onStart(); } init(); } catch (Exception e) { e.printStackTrace(); LogUtils.i("FileSender init() ------->>> occur expection"); if(mOnSendListener != null) { mOnSendListener.onFailure(e, mFileInfo); } } try { parseBody(); } catch (Exception e) { e.printStackTrace(); LogUtils.i("FileSender parseBody() ------->>> occur expection"); if(mOnSendListener != null) { mOnSendListener.onFailure(e, mFileInfo); } } try { finishTransfer(); } catch (Exception e) { e.printStackTrace(); LogUtils.i("FileSender finishTransfer() ------->>> occur expection"); if(mOnSendListener != null) { mOnSendListener.onFailure(e, mFileInfo); } } } @Override public void init() throws Exception { mSocket.setSoTimeout(30 * 1000); OutputStream os = mSocket.getOutputStream(); mOutputStream = new BufferedOutputStream(os); } @Override public void parseBody() throws Exception { long fileSize = mFileInfo.getSize(); File file = new File(mFileInfo.getFilePath()); InputStream fis = new FileInputStream(file); int len = 0; long total = 0; byte[] bytes = new byte[BYTE_SIZE_DATA]; long sTime = System.currentTimeMillis(); long eTime = 0; while ((len = fis.read(bytes)) != -1) { synchronized (LOCK) { if(mIsPause) { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } mOutputStream.write(bytes, 0, len); total += len; eTime = System.currentTimeMillis(); if(eTime - sTime > 200) { sTime = eTime; if(mOnSendListener != null) { mOnSendListener.onProgress(total, fileSize); } } } } mOutputStream.flush(); mOutputStream.close(); if(mOnSendListener != null) { mOnSendListener.onSuccess(mFileInfo); } mIsFinish = true; } @Override public void finishTransfer() throws Exception { if(mOutputStream != null) { try { mOutputStream.close(); } catch (IOException e) { } } if(mSocket != null && mSocket.isConnected()) { try { mSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 暂停发送线程 */ public void pause() { synchronized (LOCK) { mIsPause = true; LOCK.notifyAll(); } } /** * 恢复发送线程 */ public void resume() { synchronized (LOCK) { mIsPause = false; LOCK.notifyAll(); } } /** * 设置当前的发送任务不执行 */ public void stop() { mIsStop = true; } /** * 文件是否在发送中 * @return */ public boolean isRunning() { return !mIsFinish; } public interface OnSendListener { void onStart(); void onProgress(long progress, long total); void onSuccess(FileInfo fileInfo); void onFailure(Throwable throwable, FileInfo fileInfo); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
因为懒,以上列出的只是部分核心代码,选择文件的功能也没去做,草草地在Activity中写死了几个文件去上传,具体代码可去Github下载运行,参见SendFilesActivity类,哈哈!
Github源码:https://github.com/WhoIsAA/SocketDemo
总结:
貌似第一次在博客中贴那么长的代码,关于Socket的知识还要学许多许多,而我懂的也只不过是入门的皮毛,以上Demo参考了以下大神博文及资料:
- Android如何实现茄子快传
- [Java TCP/IP Socket] — 单播、广播、组播
- java socket传多个文件的疑问
0 0