【Android实战】Socket消息通信
这篇博客的内容是基于http://my.oschina.net/fengcunhan/blog/178155进行改造的。所以须要先看完这篇博客,然后再来看以下的内容。
Tcp消息的结束符“\r\n”,消息字段切割以“|”竖线。client提交数据以SS开头,服务端返回数据以RC开头。
向server端提交数据是类似get提交的方式 uid=2&content=hello
3、以发送心跳包的格式为例
备注:心跳包是防止tcp连接中断,每1分钟向server发送一次数据请求
向server发送:
列 |
内容 |
是否必须 |
说明 |
信息头 |
SS |
是 |
|
操作符 |
tcp.heartbeat |
是 |
server要运行的操作 |
内容长度 |
10 |
是 |
最后数据列的长度,为以后做数据校验预留 |
数据 |
uid:int:用户id |
|
|
server返回:
列 |
内容 |
说明 |
信息头 |
RC |
|
操作符 |
tcp.heartbeat |
server要运行的操作 |
时间 |
2015-11-04 12:00:00 |
|
数据 |
status:int:结果状态 msg:string:server返回消息 |
Json数据格式 |
实例:>> SS|tcp.heartbeat|7|uid=123\r\n
<< RC|tcp.heartbeat|2015-11-04 13:30:00|{
"status": 0,
"msg": "ok",
“key”:””
}\r\n
每次数据提交中,某些參数必选,某些參数可选
某些数据提交中。key可选。key是为了确认会话(没有收到响应的key。就进行消息重发),server端会返回key数据
key:string:每条消息的唯一标示,仅仅要不短时间内出现反复而且字符长度不要太长都能够,md5值,时间戳+随机数 等等,为了保证server端应答的唯一性
Ion。
假设你须要一个未被封装的Android的raw Socket。 HTTP client/server, WebSocket, and Socket.IO, AndroidAsync 正适合你。
/**
* 因为移动设备的网络的复杂性,常常会出现网络断开,假设没有心跳包的检測,
* client仅仅会在须要发送数据的时候才知道自己已经断线,会延误,甚至丢失server发送过来的数据。 * 所以须要提供心跳检測
*/
public class SocketService extends Service {
private static final String TAG = "SocketService";
private static final long HEART_BEAT_RATE = 30 * 1000;//眼下心跳检測频率为30s
private static final long RE_SEND_MSG = 5 * 1000;//重发消息间隔 public static final String HOST = "t.ing.baofeng.com";
public static final int PORT = 9099; public static final String MESSAGE_ACTION="com.storm.durian.message_ACTION";
public static final String HEART_BEAT_ACTION="com.storm.durian.heart_beat_ACTION";
public static final String RE_CONNECTION = "com.storm.durian.re_connection";//socket断了之后又一次连接及做之后的操作 public Map<String,String> map = new ConcurrentHashMap<String,String>();
private ReadThread mReadThread; private LocalBroadcastManager mLocalBroadcastManager; private WeakReference<Socket> mSocket; private String socketMsgStr = ""; // For heart Beat
private Handler mHandler = new Handler();
private Runnable heartBeatRunnable = new Runnable() { @Override
public void run() {
if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) {
Map<String, String> m = new HashMap<String, String>();
String key = String.valueOf(System.currentTimeMillis());
m.put("key",key);
boolean isSuccess = sendMsg(key,AsyncSocketUtils.spliceSendMessage(getApplicationContext(), m, UrlContainer.HEART_BEAT));//就发送一个\r\n过去 假设发送失败,就又一次初始化一个socket
if (!isSuccess) {
reConnectSocket(); }
LogHelper.e(TAG, "send a heart beat "+isSuccess);
}
mHandler.postDelayed(this, HEART_BEAT_RATE); }
}; /**
* 重连socket
*/
private void reConnectSocket() {
mHandler.removeCallbacks(heartBeatRunnable);
mHandler.removeCallbacks(reSendMsgRunnable);
mReadThread.release();
releaseLastSocket(mSocket);
new InitSocketThread().start();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(RE_CONNECTION);
mLocalBroadcastManager.sendBroadcast(intent);
}
}, 2000);
} private Runnable reSendMsgRunnable = new Runnable() {
@Override
public void run() {
if(map != null &&map.size()>0){
for (String key:map.keySet()){
sendMsg(key,map.get(key));
//重发一次
map.remove(key);
}
}
mHandler.postDelayed(this, RE_SEND_MSG);
}
}; private long sendTime = 0L;
private ISocketService.Stub iSocketService = new ISocketService.Stub() { @Override
public boolean sendMessage(String key,String message) throws RemoteException {
return sendMsg(key,message);
} @Override
public boolean keyAuthentication(String key) throws RemoteException {
return keyAuthen(key);
}
}; @Override
public IBinder onBind(Intent arg0) {
return iSocketService;
} @Override
public void onCreate() {
super.onCreate();
new InitSocketThread().start();
mLocalBroadcastManager=LocalBroadcastManager.getInstance(this); } @Override
public void onDestroy() { // TODO Auto-generated method stub
super.onDestroy();
if(map !=null) {
map.clear();
map = null;
}
LogHelper.e(TAG, "onDestroy");
mHandler.removeCallbacks(heartBeatRunnable);
mHandler.removeCallbacks(reSendMsgRunnable);
if(mReadThread != null){
mReadThread.release();
}
if(mSocket != null){
releaseLastSocket(mSocket);
}
} public boolean sendMsg(String key,String msg) {
if (null == mSocket || null == mSocket.get()) {
return false;
}
Socket soc = mSocket.get();
try {
if (!soc.isClosed() && !soc.isOutputShutdown()) {
OutputStream os = soc.getOutputStream();
String message = msg + "\r\n";
os.write(message.getBytes());
os.flush();
sendTime = System.currentTimeMillis();//每次发送成数据,就改一下最后成功发送的时间,节省心跳间隔时间
LogHelper.e(TAG,"SuS sendMsg------> "+msg);
} else {
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
map.put(key,msg);
return true;
} public boolean keyAuthen(String key){
if (map.containsKey(key)) {
map.remove(key);
return true;
}
return false;
} private void initSocket() {//初始化Socket
try {
Socket so = new Socket(HOST, PORT);
mSocket = new WeakReference<Socket>(so);
mReadThread = new ReadThread(so);
mReadThread.start();
mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);//初始化成功后,就准备发送心跳包
mHandler.postDelayed(reSendMsgRunnable,RE_SEND_MSG);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} private void releaseLastSocket(WeakReference<Socket> mSocket) {
try {
if (null != mSocket) {
Socket sk = mSocket.get();
if (sk != null && !sk.isClosed()) {
sk.close();
}
sk = null;
mSocket = null;
}
} catch (IOException e) {
e.printStackTrace();
}
} class InitSocketThread extends Thread {
@Override
public void run() {
super.run();
initSocket();
}
} // Thread to read content from Socket
class ReadThread extends Thread {
private WeakReference<Socket> mWeakSocket;
private boolean isStart = true; public ReadThread(Socket socket) {
mWeakSocket = new WeakReference<Socket>(socket);
} public void release() {
isStart = false;
if(mWeakSocket != null){
releaseLastSocket(mWeakSocket);
} } @Override
public void run() {
super.run();
Socket socket = mWeakSocket.get();
if (null != socket) {
try {
InputStream is = socket.getInputStream();
byte[] buffer = new byte[1024 * 4];
int length = 0;
while (!socket.isClosed() && !socket.isInputShutdown()
&& isStart && ((length = is.read(buffer)) != -1)) {
if (length > 0) {
String message = new String(Arrays.copyOf(buffer,
length));
//trim能够去掉末尾的\r\n
//每条消息以\r\n分开
//直接通过LogHelper打印message无显示,能够加trim或者replace \r\n
LogHelper.e(TAG, "原始message------> " + message.replace("\r\n","||||||"));
socketMsgStr = socketMsgStr + message;
if (!socketMsgStr.contains("\r\n")) {
LogHelper.e(TAG, "socketMsgStr without分隔符");
continue;
}
//返回的消息流有可能是拼接在一起的2条消息,所以须要处理
String[] a = socketMsgStr.split("\r\n");
for(int i = 0;i<a.length;i++){
Intent intent = new Intent(MESSAGE_ACTION);
if(a[i].charAt(a[i].length()-1)!='}'){
continue;
}
intent.putExtra("message", a[i]);
mLocalBroadcastManager.sendBroadcast(intent);
int rIndex = socketMsgStr.indexOf("\r\n");
if (rIndex + 2 == socketMsgStr.length()) {
socketMsgStr = "";
} else {
socketMsgStr = socketMsgStr.substring(socketMsgStr.indexOf("\r\n") + 2);
}
}
LogHelper.e(TAG, "截取之后的message------> " + socketMsgStr.trim()); }
}
} catch (Exception e) {//还会遇到SocketException
}
}
}
} }
附:假设哪位朋友有更好的Android Socket编程框架推荐或者优化方面的资源。欢迎共享。大家一起进步!
【Android实战】Socket消息通信的更多相关文章
- Android 使用Socket进行通信(Android)
一.服务器程序 服务器程序需要在PC上运行,该程序比较的简单,因此不需要建立Android项目,直接定义一个JAVA类,并且运行该类即可.它仅仅建立ServerSocket监听,并使用Socket获取 ...
- 基于android的Socket通信
一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户 ...
- Android 之 Socket 通信
Android 之 Socket 通信 联系一下 Socket 编程,之后需要将一个 JavaEE 项目移植到 Android,暂时现尝试写一个简单的 DEMO,理解一下 Socket Server ...
- Android线程消息通信(一)
Android在Java标准线程模型的基础上,提供了消息驱动机制,用于多线程之间的通信.基于消息驱动机制的线程通信模型陈伟线程消息通信.在标准线程模型中,线程执行完毕后便退出,而Android扩展了线 ...
- Android native进程间通信实例-socket本地通信篇之——基本通信功能
导读: 网上看了很多篇有关socket本地通信的示例,很多都是调通服务端和客户端通信功能后就没有下文了,不太实用,真正开发中遇到的问题以及程序稳定性部分没有涉及,代码健壮性不够,本系列(socket本 ...
- RabbitMQ实战:理解消息通信
RabbitMQ是一个开源的消息代理和队列服务器,可以通过基本协议在完全不同的应用之间共享数据,可以将作业排队以便让分布式服务进行处理. 本篇介绍下消息通信,首先介绍基础概念,将这些概念映射到AMQP ...
- NFC:Arduino、Android与PhoneGap近场通信
NFC:Arduino.Android与PhoneGap近场通信(第一本全面讲解NFC应用开发的技术著作移动智能设备近距离通信编程实战入门) [美]Tom Igoe(汤姆.伊戈),Don Colema ...
- Android BLE与终端通信(四)——实现服务器与客户端即时通讯功能
Android BLE与终端通信(四)--实现服务器与客户端即时通讯功能 前面几篇一直在讲一些基础,其实说实话,蓝牙主要为多的还是一些概念性的东西,当你把概念都熟悉了之后,你会很简单的就可以实现一些逻 ...
- Android BLE与终端通信(三)——客户端与服务端通信过程以及实现数据通信
Android BLE与终端通信(三)--客户端与服务端通信过程以及实现数据通信 前面的终究只是小知识点,上不了台面,也只能算是起到一个科普的作用,而同步到实际的开发上去,今天就来延续前两篇实现蓝牙主 ...
随机推荐
- pyftpdlib 搭建ftp环境
环境搭建: pythonwindows/linuxpip install pyftpdlib (安装失败请到这里下载:https://pypi.python.org/pypi/pyftpdlib/)一 ...
- perl脚本去除文件中重复数据
今天第一天写博客,写的不好请大家多多指教,废话不多说了,干货送上: ############################################################# #!/u ...
- HDU-5693 D Game 动态规划 两次动规
题目链接:https://cn.vjudge.net/problem/HDU-5693 题意 中文题 这个游戏是这样的,首先度度熊拥有一个公差集合{D},然后它依次写下N个数字排成一行.游戏规则很简单 ...
- 题解 洛谷 P1580 【yyy loves Easter_Egg I】
一言不合上代码: #include<cstdio> #include<cstring> ],bz[],dmz[]; int maohao,xf,ls,sss,lll,xxf,x ...
- 主程的晋升攻略(3):IP、DNS和CDN
有段时间我面试程序猿时,喜欢问这个问题:局域网IP有哪些IP段?由这个问题再追问NAT(网络地址转换). 为什么不是每一个设备一个公网IP? 先说个关于QQ的小故事,最早开发QQ时.小马哥他们也没想到 ...
- SPOJ 题目705 New Distinct Substrings(后缀数组,求不同的子串个数)
SUBST1 - New Distinct Substrings no tags Given a string, we need to find the total number of its di ...
- ufldl学习笔记与编程作业:Linear Regression(线性回归)
ufldl学习笔记与编程作业:Linear Regression(线性回归) ufldl出了新教程,感觉比之前的好.从基础讲起.系统清晰,又有编程实践. 在deep learning高质量群里面听一些 ...
- BZOJ1830: [AHOI2008]Y型项链 & BZOJ1789: [Ahoi2008]Necklace Y型项链
[传送门:BZOJ1830&BZOJ1789] 简要题意: 给你3个字符串,你每一次可以在一个字符串的末端删除一个字符或添加一个字符,你需要用尽量少的操作次数使得这3个字符串变成一样的. 题解 ...
- AES简单加密解密的方法实现
package com.mstf.aes; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyEx ...
- sql 的几种常用方法
第一个项目总结基类:database:主要是定义有关数据库的方法: 1.打开数据库 public static void Open() { ( "server=.\\sqlexpress;d ...