详解Android 通过Socket 和服务器通讯(附demo)

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

 @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();
    }// 发送完消息后,线程进入等待状态
   }
  }

 }
}

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

 @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)
  {
  }
 }

}

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

代码下载:demo

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android Socket服务端与客户端用字符串的方式互相传递图片的方法

    发送图片: 首先找到具体传递的图片: <span style="font-family: comic sans ms,sans-serif; font-size: 16px;">private Bitmap getimage(String srcPath) { BitmapFactory.Options newOpts = new BitmapFactory.Options(); // 开始读入图片,此时把options.inJustDecodeBounds 设回true了

  • 简单学习Android Socket的使用方法

    这方面的知识不是孤立的,其中有关于,Socket编程,多线程的操作,以及I/O流的操作.当然,实现方法不止一种,这只是其中一种,给同是新手一点点思路.如果有什么推荐的话,欢迎指点! 先给大家看一下应用程序的界面,基本就能知道大致的功能了. activity_main.java <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schem

  • Android Socket通信详解

    一.Socket通信简介  Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是"请求-响应方式",即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据.而Socket通信则是在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求. 那么,什么是socket?Socket又称套接字,在程序内部提供了与外界通信的端口,即端口通信.通过

  • Android中Socket的应用分析

    本文实例分析了Android中Socket的应用.分享给大家供大家参考,具体如下: Android 提供的常用的网络编程包括针对TCP/IP协议的Socket通信.Socket是一种跨平台的编程方式,可以在异构语言之间进行通信. Socket程序的开发原理,是要实现服务器端和客户端. 服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生

  • Android中使用socket通信实现消息推送的方法详解

    原理 最近用socket写了一个消息推送的demo,在这里和大家分享一下. 主要实现了:一台手机向另外一台手机发送消息,这两台手机可以随时自由发送文本消息进行通信,类似我们常用的QQ. 效果图: 原理:手机通过socket发送消息到服务器,服务器每接收到一条消息之后,都会把这条消息放进一个messageList里面,服务器会不停地检测messageList是否含有消息,如果有的话就会根据messageList里面item的数据,推送到相应的另一端手机上面. 下面简单画了一个图来说明这个原理: 演

  • Android开发中Socket通信的基本实现方法讲解

    一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是"请求-响应方式",即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据.而Socket通信则是在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求. 那么,什么是socket?Socket又称套接字,在程序内部提供了与外界通信的端口,即端口通信.通过建

  • Android编程之客户端通过socket与服务器通信的方法

    本文实例讲述了Android编程之客户端通过socket与服务器通信的方法.分享给大家供大家参考,具体如下: 下面是一个demo,Android客户端通过socket与服务器通信. 由于Android里面可以完全使用java.io.*包和java.net.*包,那么,实际上,逻辑部分与J2SE没有区别.只是UI代码不一样. Android客户端通过socket与服务器通信分为下面5步: (1)通过IP地址和端口实例化Socket,请求连接服务器: 复制代码 代码如下: socket = new

  • Android通过SOCKET下载文件的方法

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

  • Android中Socket通信的实现方法概述

    本文实例简述了Android中Socket通信的实现方法,具体内容如下: 一.socket通信概述 通俗的来说套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元.它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口. 应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题.多个TCP连接或多个应用程序进程可能需要通过同一个TCP

  • Android聊天工具基于socket实现

    特简单, 没有数据库, 还没有处理各种异常. 登录:输入用户名点击的登录即可. 发送消息: 特定格式->toUser:message 1. 服务器:保存在线用户 public class Online { private static Online mOnline = null; private LinkedHashMap<String, Socket> mOnlines = new LinkedHashMap<String, Socket>(); private Onlin

  • Android使用socket创建简单TCP连接的方法

    本文实例讲述了Android使用socket创建简单TCP连接的方法.分享给大家供大家参考,具体如下: 不管是在Java还是Android编程中,通信都是及其重要的一部分.有连接的socket编程,重要性自然毋庸置疑. 这里以一个简单的demo演示一个最基本的socket编程. 先写服务端.服务端是Java代码.笔者懒得装eclipse等编程软件,就是直接notepad编程,dos运行的.服务端一般是新建一个绑定端口的serversocket,监听客户端请求(死循环监听).当接收到客户端消息时,

  • python服务器与android客户端socket通信实例

    本文实例讲述了python服务器与android客户端socket通信的方法.分享给大家供大家参考.具体实现方法如下: 首先,服务器端使用python完成,下面为python代码: 复制代码 代码如下: #server.py  import socket  def getipaddrs(hostname):#只是为了显示IP,仅仅测试一下      result = socket.getaddrinfo(hostname, None, 0, socket.SOCK_STREAM)      re

  • android开发socket编程之udp发送实例分析

    本文实例讲述了android开发socket编程之udp发送实现方法.分享给大家供大家参考.具体分析如下: 需要实现的功能:采用udp下的socket编程,当按下确认键,模拟器发送文本框数据,pc机上的网络调试助手接收 一.环境: win7 + eclipse + sdk 二.代码: package test.soket; //import com.test_button.R; import java.io.DataOutputStream; import java.io.IOException

随机推荐