前言
- 上一篇 Android端 - 通过Socket以及TCP协议和MFC端通信(Send篇); 中说到,接到一功能要求,Android 端实现在 WIFI 局域网的条件下和 PC 端通信;
- 上一篇实现了手机端 发送;本文将实现 手机端接收文件!
PC端
-
发送文件信息:
MD5$fileName$fileSize
; -
接收 Android 端发送来的接受验证;即手机端按照该文件本地是否存在,返回 “YES” 与否;
-
对 Android 端发送来的信息判断,如果是 “YES” 就继续发送文件;否则完成一次信息发送;
-
PS:这里由于 Android 端发送的 “YES” 始终不被 PC 端接收,故砍掉此鸡肋,改用发送结构体;
-
结构体如下:
//SendMD5andLogDlg.h : 头文件中 typedef struct { int nMsgCode; double pdDataX[2]; double pdDataY[2]; int nDataCnt; }ST_MSG;
-
取消 C++ 自动的字节对齐:
//SendMD5andLogDlg.h : 头文件中 #pragma once #pragma pack(push,1) //主要添加这一句! …… #pragma(pop)//末尾一天给添加这一句
Android端
-
开启线程循环监听端口;
try{ ss = new ServerSocket(); ss.setReuseAddress(true); ss.bind(new InetSocketAddress(port)); }catch(){…… } Thread receiveFileThread = new Thread(new Runnable() { @Override public void run() { while (true) { ReceiveFile(); } } }); receiveFileThread.start();
-
接收 PC 端发送来的文件信息,进行处理,读取到 MD5码、文件名、文件大小;这里要注意对编码进行验证,或者使用 “GBK”;这样可以 解决汉字乱码问题;
void ReceiveFile() { try { //2. 连接客户端对象;阻塞式方法,只有客户端连接了才会继续往下运行 while (true) { Socket receiveSocket = ss.accept(); //3.获取客户端发来的数据 InputStream receiveIPS = receiveSocket.getInputStream(); //确定 首次发送过来的文件 的编码集,解决汉字乱码问题; String code = TxtUtils.getTxtformat(receiveIPS); //4.开始 接收 发送文件请求信息 byte[] bytes = new byte[128]; receiveIPS.read(bytes); /** * 解析获取到的文件信息;并分离出 MD5、Name 以及文件大小; */ String bytesName = new String(bytes, code).trim(); MD5R = bytesName.substring(0, bytesName.indexOf("$")); isExistMD5(MD5R); if(isExistR){ Log.i(TAG, "ReceiveFile: 文件已存在"); break; } //去掉MD5 bytesName = bytesName.replaceAll(MD5R, ""); //返回一个新字符串 bytesName = bytesName.substring(1, bytesName.length()); fileNameR = bytesName.substring(0, bytesName.indexOf("$")); String fileSize = bytesName.replaceAll(fileNameR, ""); fileSize = fileSize.substring(1, fileSize.length()); receiveIPS = null; ……
-
向 PC 端发送结构体;
//TODO:3. 返回消息给发送端YES;PC端不是 C++,而是MFC框架,所以…… // 不要使用DataInputStream和DataOutputStream。用InputStream和OutputStream的方式发送“字节流” OutputStream PCStructOPS = receiveSocket.getOutputStream(); PCStructOPS.write(new PcStruct(2, 3, 4.1, 4.2, 4.3, 4.4).getBuf()); PCStructOPS.flush();
注:具体结构体 发送、接收逻辑见我的博客:Java和C++通过Socket传递结构体
-
循环接收文件信息;
/** * 5. 写入文件;确定接收后,正式接收文件 */ while (true) { //接受文件内容 //3. 获取客户端发送过来的数据 InputStream receiveDataIPS = receiveSocket.getInputStream(); //得到SD卡根目录 File sdCardDir = Environment.getExternalStorageDirectory(); //打开data目录,如不存在则生成 File buildDir = new File(sdCardDir, "/A2ATranfer/data"); if (!buildDir.exists()) buildDir.mkdirs(); String savePath = buildDir.getPath() + "/" + fileNameR; savePath = savePath.replaceAll(regEx, ""); //装载文件名的数组 byte[] buffer = new byte[1024]; int size = -1; //方式二 long received = 0L; FileOutputStream fileOut = new FileOutputStream(new File(savePath), false); while (true) { size = receiveDataIPS.read(buffer); if (size < 0) { break; } //从网络读取,写入到文件 fileOut.write(buffer, 0, size); fileOut.flush(); received += size; if (!(received < Long.parseLong(fileSize))) { break; } } fileOut = null; //重置接收文件判断,因为发送的第一次是数据信息,第二次才是数据内容。不接受第一次就没有文件名信息 //告诉发送端我已经接收完毕 MD5R = ""; break; }
注:
- 以下列出核心代码,对于大括号以及catch语句自行补全;
- 对于文件是否存在利用 MD5 码来进行校验,应将 MD5 存入本地数据库;我这里仅使用集合进行判断存储是不合适的,故没有上传代码;
注意
-
对于 Android 端,通过 Socket 发送和接收时,如果先发送,通过
Socket name = new Socket(ipAddress, port);
得到了 Socket ,接下来接收时只需要:InputStream inputStream = name.getInputStream();
-
而如果先接收,后需要发送时;通过 以下获得 Socket ;
ServerSocket ss = new ServerSocket(port); Socket receiveSocket = ss.accept(); InputStream receiveIPS = receiveSocket.getInputStream();
需要发送时只需要:
OutputStream PCStructOPS = receiveSocket.getOutputStream();
而不要再次new Socket(Ip,port);