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

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

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

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

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

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

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

(5)构建 TCPClient 发送socket消息

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

DEMO 截图

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

SocketOutPutThread 类

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();}}@Overridepublic void run(){while (isStart){// 锁发送listsynchronized (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 blocke.printStackTrace();}// 发送完消息后,线程进入等待状态}}}
}

SocketInputThread

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;}@Overridepublic 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 blocke.printStackTrace();}}readSocket();// 如果连接服务器失败,服务器连接失败,sleep固定的时间,能联网,就不需要sleepCLog.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 blocke.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 blocke.printStackTrace();}buffer.clear();buffer = null;try{// 为下一次读取作准备sk.interestOps(SelectionKey.OP_READ);// 删除正在处理的SelectionKeyselector.selectedKeys().remove(sk);} catch (CancelledKeyException e){e.printStackTrace();}}}}// selector.close();// TCPClient.instance().repareRead();} catch (IOException e1){// TODO Auto-generated catch blocke1.printStackTrace();} catch (ClosedSelectorException e2){}}}

SocketHeartHread 心跳类

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);}}

TCPClient ,采用NIO的方式构建

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 blocke.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 blocke.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();}}}
}

如何使用

// 发送消息,失败或者成功的handlerSocketThreadManager.sharedInstance().sendMsg(str.getBytes(), handler);

代码下载 http://files.cnblogs.com/likwo/SocketBlockDemo.zip

Android 通过Socket 和服务器通讯相关推荐

  1. android socket 代理服务器,Android 使用Socket进行服务器通信

    ·使用Socket进行简单服务器通信 简单服务器端: public class ServerThread implements Runnable{ Socket s=null; BufferedRea ...

  2. Android客户端与PC服务器通过socket进行交互实例

    一直以来对Android socket通信都很模糊,今天终于研究了一个网上的例子,自己又修改了下,算是对Android socket通信有点了解了. 下面是具体的代码,说明都在注释中了.需要注意的是, ...

  3. unity android服务器端,【深圳Unity3D培训】 Android客户端与PC服务器实现Socket通信

    [深圳Unity3D培训] Android客户端与PC服务器实现Socket通信 Android终端连续扫描AP信息并发送给服务器端的完成.起首基于TCP协定在Android终端和PC两头之间构成收集 ...

  4. python安卓开发实例_python服务器与android客户端socket通信实例

    本文实例讲述了python服务器与android客户端socket通信的方法.分享给大家供大家参考.具体实现方法如下: 首先,服务器端使用python完成,下面为python代码: #server.p ...

  5. android 手机 与 python服务器_python服务器与android客户端socket通信实例

    本文实例讲述了python服务器与android客户端socket通信的方法.分享给大家供大家参考.具体实现方法如下: 首先,服务器端使用python完成,下面为python代码: #server.p ...

  6. Android客户端与PC服务器实现Socket通信

    Android终端持续扫描AP信息并发送给服务器端的实现.首先基于TCP协议在Android终端和PC两端之间形成网络虚拟链路.使用ServerSocket创建TCP服务器端,然后在Android客户 ...

  7. 远程PLC监控调试,PLC通用中转服务器,多客户端tcp中转 服务器源代码,socket多线程并发通讯

    远程PLC监控调试,PLC通用中转服务器,多客户端tcp中转 服务器源代码,socket多线程并发通讯, 对接多路plc串口WIFI模块实现远程调试程序.支持各种串口服务器以及tcp以太网转发器硬件.

  8. 远程PLC监控调试,PLC通用中转服务器,多客户端tcp中转服务器源代码,socket多线程并发通讯,对接多路plc串口WIFI模块实现远程调试程序

    远程PLC监控调试,PLC通用中转服务器,多客户端tcp中转服务器源代码,socket多线程并发通讯,对接多路plc串口WIFI模块实现远程调试程序. 支持各种串口服务器以及tcp以太网转发器硬件. ...

  9. Android客户端与本地服务器Socket通信

      现代生活中,我们的移动设备离不开网络,我们的APP也经常需要连接到网络,所以现在,在这里完成一个简单的Socket通信程序,实现Android客户端与本地的服务器通信.   关于网络通信的知识,互 ...

最新文章

  1. CSS选择器和参考手册
  2. 基于脑电图的情绪识别BCI应用于DOC患者
  3. 170万奖金扶持 华为云究竟在下一盘怎样的棋?
  4. java+++多数据源配置,Spring Cloud + Mybatis 多数据源配置
  5. java ab性能测试,服务器JAVA性能测试——SPECjbb2005
  6. php 随机数据库,PHP实现随机一句功能
  7. SWMM面板基础认识
  8. Excel单元格引用方式
  9. 红米6.0系统如何无root激活xposed框架的教程
  10. GB/T28181之国标编码一览表,需要自取
  11. 【Web前端】一文带你吃透HTML(完整篇)
  12. 洛谷P4568 [JLOI2011] 飞行路线 题解
  13. 教你如何上传代码到GitHub
  14. k8s之HPA(Pod水平自动伸缩)
  15. 微信小程序使用 iconfont 彩色图标(mini-program-iconfont-cli)
  16. 什么高大填空四个字动人_照样子填空填四字成语什么什么什么地想
  17. 2、软件测试生命周期以及流程
  18. 丘比特 脱单攻略之女神倒追
  19. 创建koa2项目步骤
  20. 【软考软件评测师】2017年下案例分析历年真题

热门文章

  1. View内容保存为图片
  2. [RMAN]表空间的恢复
  3. Go设计模式之Factory
  4. PC端稳定性测试探索
  5. win764bit下Eclipse连接ubuntu中hadoop2.6经验总结
  6. 易语言 钩子 (钩子HOOK与APIHOOK是不一样的)
  7. 1122. 数组的相对排序
  8. 7-5 全量复制和部分复制
  9. Linux内核用户权限的实现,Linux内核设计与实现(6)---系统调用
  10. python 批量重命名文件_Python批量重命名文件的方法