通过TCP实现OTA的点对点上传,实现进度的监听
来源:互联网 发布:淘宝为什么比京东便宜 编辑:程序博客网 时间:2024/06/02 06:41
通过TCP实现OTA的点对点上传,实现进度的监听
其实这个功能时比较简单的,但是有点逻辑性,也是工作中碰到的,本文只讲概念代码,并不会去具体实现,不过我相信你看完之后会知道如何去做的,相信我
假设我现在一个手机端,一个设备端,而我们现在做的是手机端,设备端我们暂时不管,那我们通过OTA是怎么样的流程?
- 1.检测内存卡上是否存在update.zip
- 2.进行加密效验(比如MD5,CRC32)
- 3.TCP(端口8080)发送CMD_UPDATE_LODING:校验码
- 4.设备端回应CMD_UPDATE_LODING:0 | -1
- 5.TCP(端口9090)发送文件
- 6.设备端返回CMD_ACK_OTA_Upload_Success | CMD_ACK_OTA_Upload_Fault
- 7.TCP(端口8080)发送CMD_OTA_Update
这就是一个比较完整的看逻辑了,那好,我们就用伪代码来实现一遍,首先是创建8080的TCP端口连接
/** * TCP连接 */ private void connect() { Log.i(TAG, "connect"); new Thread() { @Override public void run() { try { mSocket = new Socket("ip", 8080); mReader = mSocket.getInputStream(); mWriter = mSocket.getOutputStream(); revMsg(); mWriter.flush(); } catch (IOException e) { Log.e(TAG, "connect:" + e.toString()); } } }.start(); }
这里为了发送和接收方便,我们单独封装两个个方法
/** * 发送指令 * * @param msg */ private void sendMsg(final String msg) { new Thread() { @Override public void run() { try { Log.i(TAG, "send:" + msg); mWriter.write(msg.getBytes("utf-8")); mWriter.flush(); } catch (Exception e) { Log.e(TAG, "sendMsg:" + e.toString()); } } }.start(); } /** * 接收 */ private void revMsg() { new Thread() { @Override public void run() { try { while (true) { byte[] mbyte = new byte[1024]; int temp = mReader.read(mbyte); String result = new String(mbyte, 0, temp); Log.i(TAG, "result:" + result); } } catch (Exception e) { Log.e(TAG, "revMsg:" + e.toString()); } } }.start(); }
专门用来发送和接收,并且我们实现一个MD5Utils
public class MD5Utils { /** * MD5加密文件 * @param file * @return * @throws FileNotFoundException */ public static String getMd5ByFile(File file) throws FileNotFoundException { String value = null; FileInputStream in = new FileInputStream(file); try { MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length()); MessageDigest md5 = MessageDigest.getInstance("MD5"); md5.update(byteBuffer); BigInteger bi = new BigInteger(1, md5.digest()); value = bi.toString(16); } catch (Exception e) { e.printStackTrace(); } finally { if (null != in) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } return value; }}
OK,前面的工作都做完了,那我们就来实现逻辑了,在点击事件里检测了
@Override public void onClick(View v) { switch (v.getId()) { case R.id.btnOta: //1.检查是否存在update.zip File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/update.zip"); if (file.exists()) { } else { Toast.makeText(this, "未检测到固件", Toast.LENGTH_SHORT).show(); } break; } }
可以,在这里我们把第一步实现了,然后第二步如果不耗时的话可以和第三步一起,我之前就碰到一个15MB的File进行CRC32的时候就耗时了,所以假设不耗时,我们可以直接发送CMD_UPDATE_LODING:校验码,如代码
@Override public void onClick(View v) { switch (v.getId()) { case R.id.btnOta: //1.检查是否存在update.zip File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/update.zip"); if (file.exists()) { try { sendMsg("CMD_UPDATE_LODING:" + MD5Utils.getMd5ByFile(file)); } catch (FileNotFoundException e) { Log.e(TAG, "MD5 Error" + e.toString()); } } else { Toast.makeText(this, "未检测到固件", Toast.LENGTH_SHORT).show(); } break; } }
这里算是发出去了,那我们在接收的地方可以这样去操作
/** * 接收 */ private void revMsg() { new Thread() { @Override public void run() { try { while (true) { byte[] mbyte = new byte[1024]; int temp = mReader.read(mbyte); String result = new String(mbyte, 0, temp); Log.i(TAG, "result:" + result); if (result.startsWith("CMD_UPDATE_LODING")) { String[] mStr = result.split(":"); switch (mStr[1]) { case "0": mHandler.sendEmptyMessage(UPDATE_OK); break; case "-1": mHandler.sendEmptyMessage(UPDATE_OK); break; } } } } catch (Exception e) { Log.e(TAG, "revMsg:" + e.toString()); } } }.start(); }
这里如果他返回0,说明他准备好了
private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case UPDATE_OK: connectFile(); break; case UPDATE_NO: Toast.makeText(MainActivity.this, "OTA未准备好", Toast.LENGTH_SHORT).show(); break; } } };
是0,那我就可以开始推送File了,推送File要要考虑的就是进度,所以我专门写了一个方法来监听进度
/** * 上传文件 */ private void connectFile() { new Thread() { @Override public void run() { try { Log.i(TAG, "connectFile"); mSocketFile = new Socket("ip", 9090); mReaderFile = mSocketFile.getInputStream(); mWriterFile = mSocketFile.getOutputStream(); File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/update.zip"); FileInputStream fin = new FileInputStream(file); OutputStream out = mSocketFile.getOutputStream(); long fileLength = file.length(); byte[] buf = new byte[2048]; int len = 0; int progress = 0; int progressAll = 0; while ((len = fin.read(buf)) != -1) { out.write(buf, 0, len); progress += len; progressAll = progress * 100 / (int) fileLength; System.out.println("progressAll"+ progressAll); } mSocketFile.shutdownInput(); mWriterFile.flush(); fin.close(); mSocketFile.close(); } catch (IOException e) { Log.e(TAG, "connectFile:" + e.toString()); } } }.start(); }
这个方法要仔细看,我在这里新开了一个端口9090,然后进行文件的上传,其中我还在计算当前的进度为 progress += len,去乘以100/总大小fileLength就是我们当前的进度了,OK,这个时候他返回的是什么呢?这个时候设备端返回CMD_ACK_OTA_Upload_Success | CMD_ACK_OTA_Upload_Fault,我们又回到了接收的地方
} else if (result.equals("CMD_ACK_OTA_Upload_Success")) { mHandler.sendEmptyMessage(UPLOAD_SUCCESS); } else if (result.equals("CMD_ACK_OTA_Upload_Fault")) { mHandler.sendEmptyMessage(UPLOAD_FAULT); }
我在接收的地方判断了结果,然后继续回到handler里面
case UPLOAD_SUCCESS: sendMsg("CMD_OTA_Update"); break;case UPLOAD_FAULT: Toast.makeText(MainActivity.this, "文件效验失败", Toast.LENGTH_SHORT).show(); break;
这里更容易,如果成功我就发送CMD_OTA_Update,失败我就提示失败,就是这么简单,到此流程就完全走了一遍了,虽然是伪代码,不过逻辑还是痛顺畅的,送上完整的伪代码
package com.liuguilin.ota_tcp_sample;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.Toast;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;/** * - 1.检测内存卡上是否存在update.zip * - 2.进行加密效验(比如MD5,CRC32) * - 3.TCP(端口8080)发送CMD_UPDATE_LODING:校验码 * - 4.设备端回应CMD_UPDATE_LODING:0 | -1 * - 5.TCP(端口9090)发送文件 * - 6.设备端返回CMD_ACK_OTA_Upload_Success | CMD_ACK_OTA_Upload_Fault * - 7.TCP(端口8080)发送CMD_OTA_Update */public class MainActivity extends AppCompatActivity implements View.OnClickListener { public static final String TAG = MainActivity.class.getSimpleName(); public static final int UPDATE_OK = 1001; public static final int UPDATE_NO = 1002; public static final int UPLOAD_SUCCESS = 1003; public static final int UPLOAD_FAULT = 1004; //tcp 8080 private Socket mSocket; private InputStream mReader; private OutputStream mWriter; //tcp 9090 private Socket mSocketFile; private InputStream mReaderFile; private OutputStream mWriterFile; private Button btnOta; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case UPDATE_OK: connectFile(); break; case UPDATE_NO: Toast.makeText(MainActivity.this, "OTA未准备好", Toast.LENGTH_SHORT).show(); break; case UPLOAD_SUCCESS: sendMsg("CMD_OTA_Update"); break; case UPLOAD_FAULT: Toast.makeText(MainActivity.this, "文件效验失败", Toast.LENGTH_SHORT).show(); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //开始连接 connect(); btnOta = (Button) findViewById(R.id.btnOta); btnOta.setOnClickListener(this); } /** * TCP连接 */ private void connect() { Log.i(TAG, "connect"); new Thread() { @Override public void run() { try { mSocket = new Socket("ip", 8080); mReader = mSocket.getInputStream(); mWriter = mSocket.getOutputStream(); revMsg(); mWriter.flush(); } catch (IOException e) { Log.e(TAG, "connect:" + e.toString()); } } }.start(); } /** * 发送指令 * * @param msg */ private void sendMsg(final String msg) { new Thread() { @Override public void run() { try { Log.i(TAG, "send:" + msg); mWriter.write(msg.getBytes("utf-8")); mWriter.flush(); } catch (Exception e) { Log.e(TAG, "sendMsg:" + e.toString()); } } }.start(); } /** * 接收 */ private void revMsg() { new Thread() { @Override public void run() { try { while (true) { byte[] mbyte = new byte[1024]; int temp = mReader.read(mbyte); String result = new String(mbyte, 0, temp); Log.i(TAG, "result:" + result); if (result.startsWith("CMD_UPDATE_LODING")) { String[] mStr = result.split(":"); switch (mStr[1]) { case "0": mHandler.sendEmptyMessage(UPDATE_OK); break; case "-1": mHandler.sendEmptyMessage(UPDATE_OK); break; } } else if (result.equals("CMD_ACK_OTA_Upload_Success")) { mHandler.sendEmptyMessage(UPLOAD_SUCCESS); } else if (result.equals("CMD_ACK_OTA_Upload_Fault")) { mHandler.sendEmptyMessage(UPLOAD_FAULT); } } } catch (Exception e) { Log.e(TAG, "revMsg:" + e.toString()); } } }.start(); } /** * 上传文件 */ private void connectFile() { new Thread() { @Override public void run() { try { Log.i(TAG, "connectFile"); mSocketFile = new Socket("ip", 9090); mReaderFile = mSocketFile.getInputStream(); mWriterFile = mSocketFile.getOutputStream(); File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/update.zip"); FileInputStream fin = new FileInputStream(file); OutputStream out = mSocketFile.getOutputStream(); long fileLength = file.length(); byte[] buf = new byte[2048]; int len = 0; int progress = 0; int progressAll = 0; while ((len = fin.read(buf)) != -1) { out.write(buf, 0, len); progress += len; progressAll = progress * 100 / (int) fileLength; System.out.println("progressAll" + progressAll); } mSocketFile.shutdownInput(); mWriterFile.flush(); fin.close(); mSocketFile.close(); } catch (IOException e) { Log.e(TAG, "connectFile:" + e.toString()); } } }.start(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btnOta: //1.检查是否存在update.zip File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/update.zip"); if (file.exists()) { try { sendMsg("CMD_UPDATE_LODING:" + MD5Utils.getMd5ByFile(file)); } catch (FileNotFoundException e) { Log.e(TAG, "MD5 Error" + e.toString()); } } else { Toast.makeText(this, "未检测到固件", Toast.LENGTH_SHORT).show(); } break; } }}
有兴趣的可以加群:555974449
Sample下载地址:正在上传
- 通过TCP实现OTA的点对点上传,实现进度的监听
- tcp调试工具的实现点对点的
- OKHttp上传图片实现,进度监听
- [VC++]点对点(P2P)多线程断点续传的实现(TCP/IP)
- ASIProgressDelegate:实现定制的上传进度显示
- PHP文件上传进度的实现原理
- 上传进度实现的2中方式
- Android带进度反馈的上传实现
- 多文件上传进度的实现-springmvc
- iOS通过OTA方式分发应用的实现
- iOS通过OTA方式分发应用的实现
- iOS通过OTA方式分发应用的实现
- Spring MVC 监听文件上传进度,实现上传进度条
- ajax实现文件上传并且监听上传进度
- 使用OkHttp实现下载的进度监听和断点续传
- VB开发的上传实例,实现上传进度
- 点对点多线程断点续传的实现
- 点对点多线程断点续传的实现
- 利用window.performance.timing检测页面加载速度
- Android中无法引用drawable中的图片
- Exception in thread "main" java.lang.UnsupportedClassVersionError: org/apache/catalina/startup/Boots
- NandFlash的驱动程序设计
- Jenkins的安装与Android项目构建
- 通过TCP实现OTA的点对点上传,实现进度的监听
- MATLAB画高斯曲线
- Go语言学习笔记 -- 内建函数
- swit 闭包的基本使用
- 103. Binary Tree Zigzag Level Order Traversal
- (三)树
- 清华EMBA课程系列思考之十七(2) -- 公司治理
- 使用ThreadingMixIn实现多线程套接字服务器--《Python网络编程攻略》
- 深入理解Java虚拟机JVM高级特性与最佳实践阅读总结——第三章垃圾收集器与内存分配策略