android开发之socket快传文件以及消息返回
应用场景:
两台android机器:一台自建wifi热点,另一台搜索到,连接该wifi热点。之后再通过socket传递消息,文件等,当服务器端接收到消息之后会返回对应的应答消息;
注意点:接收到消息之后不能直接拔dos关闭了,这样会造成socket关闭;
socket关闭只需要一端关闭即可;
这里发送没有使用缓存发送,每一次writeInt的时候度会直接发送出去,,因此可以不需要flush();
每一次的发送端的 write 和 接收端的read 必须对应,否则异常出错!
服务器端socket代码:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import com.carspeak.client.entity.NetTransEntity;
import com.carspeak.terminal.utils.AppUtils;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log; /**
* 服务器端完整socket接收代码(接收客户端的图片)
* @author huqiang
*
*/
public class SocketService implements Runnable{
private static final String TAG = "SocketService"; private ServerSocket serviceSocket;
private boolean SCAN_FLAG = false; // 接收扫描标识
private boolean REV_FLAG = false; // 接收标识 private static String mfilePath = null; // 存放接收文件的路径 private static Context mContext;
private static SocketService instance; // 唯一实例
private Thread mThread;
private boolean IS_THREAD_STOP = false; // 是否线程开始标志 private static Handler mHandler;
public SocketService()
{
try
{
serviceSocket = new ServerSocket(4700);
Log.d(TAG, "建立监听服务器ServerSocket成功");
} catch (IOException e)
{
Log.d(TAG, "建立监听服务器ServerSocket失败");
e.printStackTrace();
}
mThread = new Thread(this);
} /**
* <p>
* 获取TcpService实例
* <p>
* 单例模式,返回唯一实例
*/
public static SocketService getInstance(Context context,Handler handler,String filepath)
{
mContext = context;
mHandler = handler;
mfilePath = filepath;
if (instance == null)
{
instance = new SocketService();
}
return instance;
} public void setSavePath(String fileSavePath)
{
Log.d(TAG, "设置存储路径成功,路径为" + fileSavePath);
this.mfilePath = fileSavePath;
// REV_FLAG=true;
} public SocketService(Context context)
{
this();
mContext = context;
} private void scan_recv()
{
try
{
Socket socket = serviceSocket.accept(); // 接收UDP数据报
// socket.setSoTimeout(10*1000); // 设置掉线时间
Log.d(TAG, "客户端连接成功");
//通过子线程来循环读取socket的消息
ListenClientSocket ls = new ListenClientSocket(socket);
ls.start(); } catch (IOException e)
{
e.printStackTrace();
Log.d(TAG, "客户端连接失败");
SCAN_FLAG = false;
}
} @Override
public void run()
{
Log.d(TAG, "TCP_Service线程开启");
while (!IS_THREAD_STOP)
{
if (SCAN_FLAG)
{
scan_recv();
}
}
} public void release()
{
if (null != serviceSocket && !serviceSocket.isClosed())
try
{
serviceSocket.close();
serviceSocket = null;
Log.d(TAG, "关闭socket成功");
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
while (SCAN_FLAG == true)
;// 直到SCAN_FLAG为false的时候退出循环
SCAN_FLAG = false;
IS_THREAD_STOP = true;
} public void startReceive()
{
SCAN_FLAG = true; // 使能扫描接收标识
if (!mThread.isAlive())
mThread.start(); // 开启线程
} public void stopReceive()
{
while (SCAN_FLAG == true)
;
SCAN_FLAG = false; // 失能扫描接收标识
} /**
* 监听客户端发送的消息
* @author huqiang
*
*/
class ListenClientSocket implements Runnable
{
private boolean IsListening = false;
private Socket clientSocket;
private Thread thread;
public ListenClientSocket(Socket s)
{
this.clientSocket = s;
this.thread = new Thread(this);
}
@Override
public void run() {
while(clientSocket!=null&&!clientSocket.isClosed()&&IsListening)
{
readMessage(this.clientSocket);
}
}
public void start()
{
IsListening = true;
thread.start();
}
public void release()
{
IsListening = false;
if(!clientSocket.isClosed())
{
try {
clientSocket.close();
clientSocket = null;
} catch (IOException e) {
e.printStackTrace();
} }
}
public void readMessage(Socket socket)
{
NetTransEntity entity = new NetTransEntity();
try
{
//分批次接收socket
InputStream in = socket.getInputStream();
DataInputStream dis = new DataInputStream(in);
entity.RequestCode = dis.readInt();
entity.params = dis.readUTF();
switch(entity.RequestCode)
{
case 100://
case 500://请求升级
Log.v(TAG, "请求图片");
entity.fileLength = dis.readLong();
Log.v(TAG, "接收到文件长度:"+entity.fileLength);
if(entity.RequestCode==100)
{
entity.params = "screen.png";
}
FileOutputStream fos =new FileOutputStream(new File(mfilePath,entity.params)); byte[] sendBytes =new byte[1024];
int transLen =0;
Log.v(TAG, "----开始接收文件<" + entity.params +">,文件大小为<" + entity.fileLength +">----");
while(true){
int read =0;
read = dis.read(sendBytes);
Log.v(TAG, "read="+read);
if(read == -1)
break;
transLen += read;
Log.v(TAG, "接收文件进度" +100 * transLen/entity.fileLength +"%...");
fos.write(sendBytes,0, read);
fos.flush();
}
Log.v(TAG, "----接收文件<" + entity.params +">成功-------1");
entity.filePath = mfilePath + entity.params; //将下载下来的文件名字赋值给entity.filePath
Log.v(TAG, "----接收文件<" + entity.params +">成功-------2");
break;
case 101://请求终止投影
case 102://请求待机(超时自动待机)
case 103://请求高速自动待机
break;
case 501://请求固件版本信息
break;
default://其他请求
break;
}
// dis.close();//会造成关闭socket
// socket.shutdownInput();
//发送返回消息
Log.v(TAG, "----开始发送返回消息-------");
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
Log.v(TAG, "发送返回消息 1");
dos.writeInt(200);
dos.flush();
Log.v(TAG, "发送返回消息 2");
switch(entity.RequestCode)
{
case 501: //请求固件版本信息
//返回版本号
Log.v(TAG, "发送返回消息-返回版本号");
String versionCode = AppUtils.getVersionCode(mContext)+"";
dos.writeUTF(versionCode);
dos.flush();
break;
case 100:
case 101:
case 102:
case 103:
default:
dos.writeUTF("success");
dos.flush();
break;
}
// dos.close();
// socket.close();
}
catch(Exception ex)
{
Log.e(TAG, "Exception:"+ex.getMessage()); }
finally
{
Message msg = new Message();
msg.what = 1; //说明有socket消息
msg.obj = entity;
mHandler.sendMessage(msg);
release();
}
} }
}
对应的客户端socket代码:
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket; import com.carspeak.client.config.SPConfig;
import com.carspeak.client.entity.CusMessage;
import com.carspeak.client.entity.NetTransEntity;
import com.carspeak.client.util.SPUtils;
import com.carspeak.client.util.WifiUtils; import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log; /**
* 连接到终端设备
*
* @author huqiang
*
*/
public class ClientService implements Runnable{ // AppConfig app;
// String filePath;
NetTransEntity mEntity;
String ServerIP;
WifiUtils mWifiUtils;
private final int SERVER_PORT = 4700; //服务器端口
private final int TIME_OUT = 6*1000; //SOCKET超时时间
private Context mContext;
private Handler mHandler;
public ClientService(Context context,Handler handler,NetTransEntity entity) {
// app = (AppConfig) context.getApplicationContext();
// this.filePath = filePath;
this.mEntity = entity;
mContext = context;
this.mHandler = handler;
mWifiUtils = WifiUtils.getInstance(context);
ServerIP = (mWifiUtils.getServerIPAddress()==null)?"192.168.43.1":mWifiUtils.getServerIPAddress();
} /**
* 向终端发送数据
* @param path
* @throws IOException
* @throws Exception
*/
private void sendMessage(NetTransEntity entity) throws IOException, Exception {
// 1.连接服务器
Socket socket = new Socket();
Log.v("ConnectTerminalServer", "开始准备socket连接,ServerIP=" + ServerIP+ ";SERVER_PORT=" + SERVER_PORT + ";TIME_OUT=" + TIME_OUT+";当前连接状态:getSSID"+mWifiUtils.getSSID());
socket.connect(new InetSocketAddress(ServerIP, SERVER_PORT), TIME_OUT); DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); Log.v("ClientService", "开始写入请求码:"+entity.RequestCode);
dos.writeInt(entity.RequestCode); //写入请求码
// dos.flush();
switch(entity.RequestCode)
{
case 100://请求图片
case 500://请求固件升级,发送apk文件
File file = new File(entity.filePath);
Log.v("ClientService", "开始写入文件名 file.getName()="+file.getName());
dos.writeUTF(file.getName()); //第二次写入参数信息
dos.flush();
Log.v("ClientService", "开始写入文件长度 file.length()="+file.length());
dos.writeLong(file.length()); //第三次写入文件的长度
dos.flush();
//第四次写入文件
//传输文件
FileInputStream fis =new FileInputStream(file);
byte[] sendBytes =new byte[1024];
int length =0;
while((length = fis.read(sendBytes,0, sendBytes.length)) >0){
dos.write(sendBytes,0, length);
dos.flush();
}
fis.close();
break;
case 101://请求终止
case 102://请求待机(超时自动待机)
case 103://请求高速自动待机
Log.v("ClientService", "开始写入参数="+(entity.params==null?"params is null":entity.params));
dos.writeUTF(entity.params==null?" ":entity.params);
dos.flush();
break;
case 501://请求固件版本信息
dos.writeUTF(" ");
dos.flush();
break;
default://其他请求
break;
} Log.v("ClientService", "即将关闭dos");
// dos.close(); //注意这里dos关闭会造成socket关闭,应该使用shutdownOutput
socket.shutdownOutput();
Log.v("ClientService", "shutdownOutput");
/****************接收返回参数******************/
DataInputStream dis = new DataInputStream(socket.getInputStream());
CusMessage cms = new CusMessage();
Log.v("ClientService", "接收消息 1 dis="+dis);
cms.code = dis.readInt();
Log.v("ClientService", "接收消息 2");
cms.message = dis.readUTF();
Log.v("ClientService", "接收到终端返回消息,code="+cms.code + ";message="+cms.message);
switch(entity.RequestCode)
{
case 501: //请求固件版本信息
if(cms.code==200)
{
int terminalVersionCode = Integer.parseInt(cms.message);
SPUtils.put(mContext, SPConfig.TerminalVersionCode, -1);
Message msg = new Message();
msg.what = 501;
msg.obj = terminalVersionCode;
mHandler.sendMessage(msg);
Log.v("ClientService", "接收到终端的消息返回,版本号:"+terminalVersionCode);
}
break;
case 100:
case 101:
case 102:
case 103:
default:
break;
}
dos.close();
dis.close();
socket.close();
} @Override
public void run() {
try
{
sendMessage(this.mEntity);
}
catch(IOException ex){
Log.v("ConnectTerminalServer", ex.getMessage());
}
catch (Exception ex) {
Log.v("ConnectTerminalServer", ex.getMessage());
}
} }
android开发之socket快传文件以及消息返回的更多相关文章
- Android开发之SD卡上文件操作
1. 得到存储设备的目录:/SDCARD(一般情况下) SDPATH=Environment.getExternalStorageDirectory()+"/"; 2. 判断SD卡 ...
- android开发之路10(文件的读写)
1.安卓中文件的数据存储实例(将文件保存到手机自带存储空间中): ①MainActivity.java public class MainActivity extends Activity imple ...
- Android 开发之旅:深入分析布局文件&又是“Hello World!”
http://www.cnblogs.com/skynet/archive/2010/05/20/1740277.html 引言 上篇可以说是一个分水岭,它标志着我们从Android应用程序理论进入实 ...
- Android开发之InstanceState详解
Android开发之InstanceState详解 本文介绍Android中关于Activity的两个神秘方法:onSaveInstanceState() 和 onRestoreInstanceS ...
- Android开发之InstanceState详解(转)---利用其保存Activity状态
Android开发之InstanceState详解 本文介绍Android中关于Activity的两个神秘方法:onSaveInstanceState() 和 onRestoreInstanceS ...
- 【Android UI】Android开发之View的几种布局方式及实践
引言 通过前面两篇: Android 开发之旅:又见Hello World! Android 开发之旅:深入分析布局文件&又是“Hello World!” 我们对Android应用程序运行原理 ...
- Android开发之旅: Intents和Intent Filters(理论部分)
引言 大部分移动设备平台上的应用程序都运行在他们自己的沙盒中.他们彼此之间互相隔离,并且严格限制应用程序与硬件和原始组件之间的交互. 我们知道交流是多么的重要,作为一个孤岛没有交流的东西,一定毫无意义 ...
- Android开发之Java必备基础
Android开发之Java必备基础 Java类型系统 Java语言基础数据类型有两种:对象和基本类型(Primitives).Java通过强制使用静态类型来确保类型安全,要求每个变量在使用之前必须先 ...
- Android如何实现茄子快传
Android如何实现茄子快传茄子快传是一款文件传输应用,相信大家都很熟悉这款应用,应该很多人用过用来文件的传输.它有两个核心的功能: 端到端的文件传输Web端的文件传输这两个核心的功能我们具体来分析 ...
随机推荐
- js 实现angylar.js view层和model层双绑定(改变view刷新 model,改变model自动刷新view)
近段时间研究了下angular.js 觉得它内部实现的view和model层之间存在很微妙的关系,如下图 如上图说的,view的改变会update 数据层model, 数据层会update视图层vie ...
- 前端插件Emmet
Sublime text安装 步骤一:首先你需要为sublime text安装Package Control组件: 按Ctrl+`调出sublime text的console 粘贴以下代码到底部命令行 ...
- JavaScript--模块化编程(笔记)
一直对JS都是一知半解,最近遇到这方面问题,所以在网上学习了一下,现在还没有完全明白,先贴出笔记; 第一章 JavaScript模块化编程(一):模块的写法 一 原始写法 // 模块就是实现特定功能的 ...
- Activity生命周期-Android
Activity常见的三种生命周期: 1.完整生命周期 oncreate-->onstart-->onresume-->onpause-->onstop-->ondest ...
- MarkFan的程序员客栈
历史上的今天:2013-12-27 跨平台移动开发 App-Framework DEMO 演示
- Part 89 to 91 Talking about pass the parameters in thread
Part 89 ParameterizedThreadStart delegate Use ParameterizedThreadStart delegate to pass data to th ...
- java中vector与hashtable操作详解
众所周知,java中vector与hashtable是线程安全的,主要是java对两者的操作都加上了synchronized,也就是上锁了.因此 在vector与hashtable的操作是不会出现问题 ...
- cocos2dx注册场景 使用CCEditBox实现输入框
我们在开始玩一个游戏时,通常要做的第一件事就是注册账号,下面就让我们来制作一个简单的注册场景,我所使用的cocos2dx版本为2.2.2 在这个场景中最主要的元素就是输入框和按钮,我从网上找了一些素材 ...
- iOS开发那些事-iOS应用本地化-文本信息本地化
文本信息本地化在本地化工作中占有很大的比例.包括了:应用名称本地化.系统按钮和信息本地化,以及静态文本信息本地化. 系统按钮和信息本地化 还记得天气预报应用背后的“完成”按钮吗,它在中文环境下是“完成 ...
- Linux开机启动程序详解[转]
Linux开机启动程序详解 我们假设大家已经熟悉其它操作系统的引导过程,了解硬件的自检引导步骤,就只从Linux操作系统的引导加载程序(对个人电脑而言通常是LILO)开始,介绍Linux开机引导的步骤 ...