文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2022-06-06 05:07

关注

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;

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;

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

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;
 }
 
 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();
  }
 }
 
 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();
  }
 }
 
 public void sendMsg(String message) throws IOException
 {
  ByteBuffer writeBuffer = ByteBuffer.wrap(message.getBytes("utf-8"));
  if (socketChannel == null)
  {
   throw new IOException();
  }
  socketChannel.write(writeBuffer);
 }
 
 public void sendMsg(byte[] bytes) throws IOException
 {
  ByteBuffer writeBuffer = ByteBuffer.wrap(bytes);
  if (socketChannel == null)
  {
   throw new IOException();
  }
  socketChannel.write(writeBuffer);
 }
 
 public synchronized Selector getSelector()
 {
  return this.selector;
 }
 
 public boolean isConnect()
 {
  boolean isConnect = false;
  if (this.isInitialized)
  {
   isConnect = this.socketChannel.isConnected();
  }
  return isConnect;
 }
 
 public boolean reConnect()
 {
  closeTCPSocket();
  try
  {
   initialize();
   isInitialized = true;
  } catch (IOException e)
  {
   isInitialized = false;
   e.printStackTrace();
  }
  catch (Exception e)
  {
   isInitialized = false;
   e.printStackTrace();
  }
  return isInitialized;
 }
 
 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;
 }
 
 public void closeTCPSocket()
 {
  try
  {
   if (socketChannel != null)
   {
    socketChannel.close();
   }
  } catch (IOException e)
  {
  }
  try
  {
   if (selector != null)
   {
    selector.close();
   }
  } catch (IOException e)
  {
  }
 }
 
 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

您可能感兴趣的文章:详解Android 基于TCP和UDP协议的Socket通信Android使用WebSocket实现多人游戏详解OkSocket与Android的简单使用Android开发之Socket通信传输简单示例android基于socket的局域网内服务器与客户端加密通信android socket聊天室功能实现SpringBoot webSocket实现发送广播、点对点消息和Android接收Android中Socket大文件断点上传示例android Socket实现简单聊天功能以及文件传输详解Android使用Socket对大文件进行加密传输Android Socket接口实现即时通讯实例代码Android完整Socket解决方案


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-服务器
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯