Extends:(http://www.cnblogs.com/likwo/p/3641135.html

Android 通过Socket 和服务器通讯,是一种比较常用的通讯方式,时间比较紧,说下大致的思路,希望能帮到使用socket 进行通信的人

(1)开启一个线程发送消息    SocketOutputThread

      消息是放在队列里的,当有消息后,进入队列,线程唤醒,发送消息,并反馈发送是否成功的回调

(2)开启一个线程接受服务器消息 SocketInputThread

       为了防止一直收数据,浪费电池的电,采用NIO的方式读socket的数据,这个是本文的关键

(3)开启一个线程,做心跳,防止socket连接终断 , SocketHeartThread 

(4)构建 SocketThreadManager对以上三个thread进行管理

(5)构建 TCPClient 发送socket消息

     在NIO的方式实现TCP,特别是在接收服务器的数据,不用写个线程定时去读了。

主要代码如下,详细代码在附件里。

package com.example.socketblockdemo;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import android.os.Bundle;
import android.os.Handler;
import android.os.Message; /**
* 客户端写消息线程
*
* @author way
*
*/
public class SocketOutputThread extends Thread
{
private boolean isStart = true;
private static String tag = "socketOutputThread";
private List<MsgEntity> sendMsgList; public SocketOutputThread( )
{ sendMsgList = new CopyOnWriteArrayList<MsgEntity>();
} public void setStart(boolean isStart)
{
this.isStart = isStart;
synchronized (this)
{
notify();
}
} // 使用socket发送消息
public boolean sendMsg(byte[] msg) throws Exception
{ if (msg == null)
{
CLog.e(tag, "sendMsg is null");
return false;
} try
{
TCPClient.instance().sendMsg(msg); } catch (Exception e)
{
throw (e);
} return true;
} // 使用socket发送消息
public void addMsgToSendList(MsgEntity msg)
{ synchronized (this)
{
this.sendMsgList.add(msg);
notify();
}
} @Override
public void run()
{
while (isStart)
{
// 锁发送list
synchronized (sendMsgList)
{
// 发送消息
for (MsgEntity msg : sendMsgList)
{ Handler handler = msg.getHandler();
try
{
sendMsg(msg.getBytes());
sendMsgList.remove(msg);
// 成功消息,通过hander回传
if (handler != null)
{
Message message = new Message();
message.obj = msg.getBytes();
message.what =1;
handler.sendMessage(message);
// handler.sendEmptyMessage(1);
} } catch (Exception e)
{
e.printStackTrace();
CLog.e(tag, e.toString());
// 错误消息,通过hander回传
if (handler != null)
{
Message message = new Message();
message.obj = msg.getBytes();
message.what = 0;;
handler.sendMessage(message); }
}
}
} synchronized (this)
{
try
{
wait(); } catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}// 发送完消息后,线程进入等待状态
}
} }
}
package com.example.socketblockdemo;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset; import android.content.Intent;
import android.text.TextUtils; /**
* 客户端读消息线程
*
* @author way
*
*/
public class SocketInputThread extends Thread
{
private boolean isStart = true; private static String tag = "socket"; // private MessageListener messageListener;// 消息监听接口对象 public SocketInputThread()
{
} public void setStart(boolean isStart)
{
this.isStart = isStart;
} @Override
public void run()
{
while (isStart)
{
// 手机能联网,读socket数据
if (NetManager.instance().isNetworkConnected())
{ if (!TCPClient.instance().isConnect())
{
CLog.e(tag, "TCPClient connet server is fail read thread sleep second" +Const.SOCKET_SLEEP_SECOND ); try
{
sleep(Const.SOCKET_SLEEP_SECOND * 1000);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
} readSocket(); // 如果连接服务器失败,服务器连接失败,sleep固定的时间,能联网,就不需要sleep CLog.e("socket","TCPClient.instance().isConnect() " + TCPClient.instance().isConnect() ); }
}
} public void readSocket()
{
Selector selector = TCPClient.instance().getSelector();
if (selector == null)
{
return;
}
try
{
// 如果没有数据过来,一直柱塞
while (selector.select() > 0)
{
for (SelectionKey sk : selector.selectedKeys())
{
// 如果该SelectionKey对应的Channel中有可读的数据
if (sk.isReadable())
{
// 使用NIO读取Channel中的数据
SocketChannel sc = (SocketChannel) sk.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
try
{
sc.read(buffer);
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
// continue;
}
buffer.flip();
String receivedString = "";
// 打印收到的数据
try
{
receivedString = Charset.forName("UTF-8")
.newDecoder().decode(buffer).toString(); CLog.e(tag, receivedString); Intent i = new Intent(Const.BC); i.putExtra("response", receivedString); MainActivity.s_context.sendBroadcast(i ); } catch (CharacterCodingException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
buffer.clear();
buffer = null; try
{
// 为下一次读取作准备
sk.interestOps(SelectionKey.OP_READ);
// 删除正在处理的SelectionKey
selector.selectedKeys().remove(sk); } catch (CancelledKeyException e)
{
e.printStackTrace();
} }
}
}
// selector.close();
// TCPClient.instance().repareRead(); } catch (IOException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ClosedSelectorException e2)
{
}
} }
package com.example.socketblockdemo;

import java.io.IOException;

import android.text.TextUtils;

class SocketHeartThread extends Thread
{
boolean isStop = false;
boolean mIsConnectSocketSuccess = false;
static SocketHeartThread s_instance; private TCPClient mTcpClient = null; static final String tag = "SocketHeartThread"; public static synchronized SocketHeartThread instance()
{
if (s_instance == null)
{
s_instance = new SocketHeartThread();
}
return s_instance;
} public SocketHeartThread()
{
TCPClient.instance();
// 连接服务器
// mIsConnectSocketSuccess = connect(); } public void stopThread()
{
isStop = true;
} /**
* 连接socket到服务器, 并发送初始化的Socket信息
*
* @return
*/ private boolean reConnect()
{
return TCPClient.instance().reConnect();
} public void run()
{
isStop = false;
while (!isStop)
{
// 发送一个心跳包看服务器是否正常
boolean canConnectToServer = TCPClient.instance().canConnectToServer(); if(canConnectToServer == false){
reConnect();
}
try
{
Thread.sleep(Const.SOCKET_HEART_SECOND * 1000); } catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
package com.example.socketblockdemo;

import android.os.Handler;
import android.text.TextUtils; public class SocketThreadManager
{ private static SocketThreadManager s_SocketManager = null; private SocketInputThread mInputThread = null; private SocketOutputThread mOutThread = null; private SocketHeartThread mHeartThread = null; // 获取单例
public static SocketThreadManager sharedInstance()
{
if (s_SocketManager == null)
{
s_SocketManager = new SocketThreadManager();
s_SocketManager.startThreads();
}
return s_SocketManager;
} // 单例,不允许在外部构建对象
private SocketThreadManager()
{
mHeartThread = new SocketHeartThread();
mInputThread = new SocketInputThread();
mOutThread = new SocketOutputThread();
} /**
* 启动线程
*/ private void startThreads()
{
mHeartThread.start();
mInputThread.start();
mInputThread.setStart(true);
mOutThread.start();
mInputThread.setStart(true);
// mDnsthread.start();
} /**
* stop线程
*/
public void stopThreads()
{
mHeartThread.stopThread();
mInputThread.setStart(false);
mOutThread.setStart(false);
} public static void releaseInstance()
{
if (s_SocketManager != null)
{
s_SocketManager.stopThreads();
s_SocketManager = null;
}
} public void sendMsg(byte [] buffer, Handler handler)
{
MsgEntity entity = new MsgEntity(buffer, handler);
mOutThread.addMsgToSendList(entity);
} }
package com.example.socketblockdemo;

import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel; /**
* NIO TCP 客户端
*
*/
public class TCPClient
{
// 信道选择器
private Selector selector; // 与服务器通信的信道
SocketChannel socketChannel; // 要连接的服务器Ip地址
private String hostIp; // 要连接的远程服务器在监听的端口
private int hostListenningPort; private static TCPClient s_Tcp = null; public boolean isInitialized = false; public static synchronized TCPClient instance()
{
if (s_Tcp == null)
{ s_Tcp = new TCPClient(Const.SOCKET_SERVER,
Const.SOCKET_PORT);
}
return s_Tcp;
} /**
* 构造函数
*
* @param HostIp
* @param HostListenningPort
* @throws IOException
*/
public TCPClient(String HostIp, int HostListenningPort)
{
this.hostIp = HostIp;
this.hostListenningPort = HostListenningPort; try
{
initialize();
this.isInitialized = true;
} catch (IOException e)
{
this.isInitialized = false;
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e)
{
this.isInitialized = false;
e.printStackTrace();
}
} /**
* 初始化
*
* @throws IOException
*/
public void initialize() throws IOException
{
boolean done = false; try
{
// 打开监听信道并设置为非阻塞模式
socketChannel = SocketChannel.open(new InetSocketAddress(hostIp,
hostListenningPort));
if (socketChannel != null)
{
socketChannel.socket().setTcpNoDelay(false);
socketChannel.socket().setKeepAlive(true);
// 设置 读socket的timeout时间
socketChannel.socket().setSoTimeout(
Const.SOCKET_READ_TIMOUT);
socketChannel.configureBlocking(false); // 打开并注册选择器到信道
selector = Selector.open();
if (selector != null)
{
socketChannel.register(selector, SelectionKey.OP_READ);
done = true;
}
}
} finally
{
if (!done && selector != null)
{
selector.close();
}
if (!done)
{
socketChannel.close();
}
}
} static void blockUntil(SelectionKey key, long timeout) throws IOException
{ int nkeys = 0;
if (timeout > 0)
{
nkeys = key.selector().select(timeout); } else if (timeout == 0)
{
nkeys = key.selector().selectNow();
} if (nkeys == 0)
{
throw new SocketTimeoutException();
}
} /**
* 发送字符串到服务器
*
* @param message
* @throws IOException
*/
public void sendMsg(String message) throws IOException
{
ByteBuffer writeBuffer = ByteBuffer.wrap(message.getBytes("utf-8")); if (socketChannel == null)
{
throw new IOException();
}
socketChannel.write(writeBuffer);
} /**
* 发送数据
*
* @param bytes
* @throws IOException
*/
public void sendMsg(byte[] bytes) throws IOException
{
ByteBuffer writeBuffer = ByteBuffer.wrap(bytes); if (socketChannel == null)
{
throw new IOException();
}
socketChannel.write(writeBuffer);
} /**
*
* @return
*/
public synchronized Selector getSelector()
{
return this.selector;
} /**
* Socket连接是否是正常的
*
* @return
*/
public boolean isConnect()
{
boolean isConnect = false;
if (this.isInitialized)
{
isConnect = this.socketChannel.isConnected();
}
return isConnect;
} /**
* 关闭socket 重新连接
*
* @return
*/
public boolean reConnect()
{
closeTCPSocket(); try
{
initialize();
isInitialized = true;
} catch (IOException e)
{
isInitialized = false;
e.printStackTrace();
}
catch (Exception e)
{
isInitialized = false;
e.printStackTrace();
}
return isInitialized;
} /**
* 服务器是否关闭,通过发送一个socket信息
*
* @return
*/
public boolean canConnectToServer()
{
try
{
if (socketChannel != null)
{
socketChannel.socket().sendUrgentData(0xff);
}
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
catch (Exception e){
e.printStackTrace();
return false;
}
return true;
} /**
* 关闭socket
*/
public void closeTCPSocket()
{
try
{
if (socketChannel != null)
{
socketChannel.close();
} } catch (IOException e)
{ }
try
{
if (selector != null)
{
selector.close();
}
} catch (IOException e)
{
}
} /**
* 每次读完数据后,需要重新注册selector,读取数据
*/
public synchronized void repareRead()
{
if (socketChannel != null)
{
try
{
selector = Selector.open();
socketChannel.register(selector, SelectionKey.OP_READ);
} catch (ClosedChannelException e)
{
e.printStackTrace(); } catch (IOException e)
{
e.printStackTrace();
}
}
}
}
如何使用

 // 发送消息,失败或者成功的handler
SocketThreadManager.sharedInstance().sendMsg(str.getBytes(), handler);
代码下载 http://files.cnblogs.com/likwo/SocketBlockDemo.zip

Android 通过Socket 和服务器通讯的更多相关文章

  1. Android连接socket服务器上传下载多个文件

    android连接socket服务器上传下载多个文件1.socket服务端SocketServer.java public class SocketServer { ;// 端口号,必须与客户端一致 ...

  2. Android端简易蓝牙聊天通讯App(原创)

    欢迎转载,但请注明出处!谢谢.http://www.cnblogs.com/weizhxa/p/5792775.html 最近公司在做一个蓝牙串口通讯的App,有一个固定的蓝牙设备,需要实现手机连接相 ...

  3. Android 基于Socket的聊天应用(二)

    很久没写BLOG了,之前在写Android聊天室的时候答应过要写一个客户(好友)之间的聊天demo,Android 基于Socket的聊天室已经实现了通过Socket广播形式的通信功能. 以下是我写的 ...

  4. Android 之 Socket 通信

    Android 之 Socket 通信 联系一下 Socket 编程,之后需要将一个 JavaEE 项目移植到 Android,暂时现尝试写一个简单的 DEMO,理解一下 Socket Server ...

  5. 基于android的Socket通信

    一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户 ...

  6. Linux 下 简单客户端服务器通讯模型(TCP)

    原文:Linux 下 简单客户端服务器通讯模型(TCP) 服务器端:server.c #include<stdio.h> #include<stdlib.h> #include ...

  7. C# Socket的TCP通讯

    Socket的TCP通讯 一. socket的通讯原理 服务器端的步骤如下. (1)建立服务器端的Socket,开始侦听整个网络中的连接请求. (2)当检测到来自客户端的连接请求时,向客户端发送收到连 ...

  8. Android 通过SOCKET下载文件的方法

    本文实例讲述了Android通过SOCKET下载文件的方法.分享给大家供大家参考,具体如下: 服务端代码 import java.io.BufferedInputStream; import java ...

  9. Android USB Host与HID通讯

    前端时间捣鼓一个HID的硬件, 需要和android通信, 网上搜索了一圈,收获不小. 比较好的文章是:      Android USB Host与HID通讯 Android Service创建US ...

随机推荐

  1. 关于在Android中Activity页面跳转的方法

    一.无返回结果的页面跳转 1.创建两个类FActivity.java和SActivity.java 2.创建两个layout目录下的factivity.xml和sactivity.xml 3.在And ...

  2. csv导入mysql提示错误[Error Code] 1290 - The MySQL server is running with the --secure-file-priv option

    解决方法: 1.进入mysql查看secure_file_prive的值 mysql>SHOW VARIABLES LIKE "secure_file_priv"; secu ...

  3. (转)SDL1.2到2.0的迁移指南

    里面有些单词不好翻译所以放在开头,以备查验. BLock Image Transfer, a computer graphics operation in which two bitmap patte ...

  4. css -- 背景图片自适应屏幕大小

    由于<body>标签的图片不能够拉伸, 解决办法: 1.图片不够大,又background属性不能拉伸图片: 2.只能用个div,把其z-index值设为负,并使这个div大小为整个bod ...

  5. html -- 实体

  6. par函数col参数-控制颜色

    col参数用来控制颜色,其实有一些列的颜色相关的参数,都是以col 开头 col : 控制图片中点,文字以及绘图边框的颜色,代码示例: par(col = "red") plot( ...

  7. is_file,is_dir,file_exists

    is_file()和file_exists()效率比较,结果当文件存在时,is_file函数比file_exists函数速度快14倍,当文件不存在时,两者速度相当.同理,当文件目录存在时,is_dir ...

  8. 使用Java程序片段动态生成表格

    <% String[] bookName = { "javaweb典型模块大全", "java从入门到放弃", "C语言程序设计" } ...

  9. NGUI之scroll view的制作和踩坑总结

    之前也看了不少童鞋谢了关于NGUI的scroll view的制作下面我写下自己的制作过程以及心得,希望对童鞋们有所帮助.1.首先建立一个960*640的背景参考http://game.ceeger.c ...

  10. ChemDraw Std 14如何标记同位素

    ChemDraw软件是一款专业高效的化学绘图工具,能够绘制各种复杂的结构方程式,在基础化学.有机化学.材料化学等领域得到广泛应用.而ChemDraw Std 14 作为ChemDraw 的最新版本,增 ...