应用场景:

两台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快传文件以及消息返回的更多相关文章

  1. Android开发之SD卡上文件操作

    1. 得到存储设备的目录:/SDCARD(一般情况下) SDPATH=Environment.getExternalStorageDirectory()+"/"; 2. 判断SD卡 ...

  2. android开发之路10(文件的读写)

    1.安卓中文件的数据存储实例(将文件保存到手机自带存储空间中): ①MainActivity.java public class MainActivity extends Activity imple ...

  3. Android 开发之旅:深入分析布局文件&又是“Hello World!”

    http://www.cnblogs.com/skynet/archive/2010/05/20/1740277.html 引言 上篇可以说是一个分水岭,它标志着我们从Android应用程序理论进入实 ...

  4. Android开发之InstanceState详解

    Android开发之InstanceState详解   本文介绍Android中关于Activity的两个神秘方法:onSaveInstanceState() 和 onRestoreInstanceS ...

  5. Android开发之InstanceState详解(转)---利用其保存Activity状态

    Android开发之InstanceState详解   本文介绍Android中关于Activity的两个神秘方法:onSaveInstanceState() 和 onRestoreInstanceS ...

  6. 【Android UI】Android开发之View的几种布局方式及实践

    引言 通过前面两篇: Android 开发之旅:又见Hello World! Android 开发之旅:深入分析布局文件&又是“Hello World!” 我们对Android应用程序运行原理 ...

  7. Android开发之旅: Intents和Intent Filters(理论部分)

    引言 大部分移动设备平台上的应用程序都运行在他们自己的沙盒中.他们彼此之间互相隔离,并且严格限制应用程序与硬件和原始组件之间的交互. 我们知道交流是多么的重要,作为一个孤岛没有交流的东西,一定毫无意义 ...

  8. Android开发之Java必备基础

    Android开发之Java必备基础 Java类型系统 Java语言基础数据类型有两种:对象和基本类型(Primitives).Java通过强制使用静态类型来确保类型安全,要求每个变量在使用之前必须先 ...

  9. Android如何实现茄子快传

    Android如何实现茄子快传茄子快传是一款文件传输应用,相信大家都很熟悉这款应用,应该很多人用过用来文件的传输.它有两个核心的功能: 端到端的文件传输Web端的文件传输这两个核心的功能我们具体来分析 ...

随机推荐

  1. js 实现angylar.js view层和model层双绑定(改变view刷新 model,改变model自动刷新view)

    近段时间研究了下angular.js 觉得它内部实现的view和model层之间存在很微妙的关系,如下图 如上图说的,view的改变会update 数据层model, 数据层会update视图层vie ...

  2. 前端插件Emmet

    Sublime text安装 步骤一:首先你需要为sublime text安装Package Control组件: 按Ctrl+`调出sublime text的console 粘贴以下代码到底部命令行 ...

  3. JavaScript--模块化编程(笔记)

    一直对JS都是一知半解,最近遇到这方面问题,所以在网上学习了一下,现在还没有完全明白,先贴出笔记; 第一章 JavaScript模块化编程(一):模块的写法 一 原始写法 // 模块就是实现特定功能的 ...

  4. Activity生命周期-Android

    Activity常见的三种生命周期: 1.完整生命周期 oncreate-->onstart-->onresume-->onpause-->onstop-->ondest ...

  5. MarkFan的程序员客栈

    历史上的今天:2013-12-27 跨平台移动开发 App-Framework DEMO 演示

  6. Part 89 to 91 Talking about pass the parameters in thread

    Part 89   ParameterizedThreadStart delegate Use ParameterizedThreadStart delegate to pass data to th ...

  7. java中vector与hashtable操作详解

    众所周知,java中vector与hashtable是线程安全的,主要是java对两者的操作都加上了synchronized,也就是上锁了.因此 在vector与hashtable的操作是不会出现问题 ...

  8. cocos2dx注册场景 使用CCEditBox实现输入框

    我们在开始玩一个游戏时,通常要做的第一件事就是注册账号,下面就让我们来制作一个简单的注册场景,我所使用的cocos2dx版本为2.2.2 在这个场景中最主要的元素就是输入框和按钮,我从网上找了一些素材 ...

  9. iOS开发那些事-iOS应用本地化-文本信息本地化

    文本信息本地化在本地化工作中占有很大的比例.包括了:应用名称本地化.系统按钮和信息本地化,以及静态文本信息本地化. 系统按钮和信息本地化 还记得天气预报应用背后的“完成”按钮吗,它在中文环境下是“完成 ...

  10. Linux开机启动程序详解[转]

    Linux开机启动程序详解 我们假设大家已经熟悉其它操作系统的引导过程,了解硬件的自检引导步骤,就只从Linux操作系统的引导加载程序(对个人电脑而言通常是LILO)开始,介绍Linux开机引导的步骤 ...