最近项目中,有使用Socket与后端进行通信,然后简单的了解了下Socket使用,大致流程是配置服务端的Ip、端口号,连接,监听数据和发送数据,数据的读取和发送都是以流的形式实现的,然后自己将项目中的代码写了简单的管理类,测试下代码。下面是demo的两个界面,连接和发送接收界面

这里使用了一个Tcp调试助手,模拟服务端发送和接收数据,通讯模式选择TcpService ,本地端口随意定义一个,保持和demo填写的端口号一致,demo里面的ip是你主机的ip地址,cmd下ipconfig查看

代码

一、初始化

public TcpManager initSocket(final String ip, final String port) {this.ip=ip;this.port=port;/* 开启读写线程*/threadStatus =true;new ReadThread().start();if (socket == null && connectThread == null) {connectThread = new Thread(new Runnable() {@Overridepublic void run() {socket = new Socket();try {/*超时时间为2秒*/socket.connect(new InetSocketAddress(ip, Integer.valueOf(port)), 2000);/*连接成功的话  发送心跳包*/if (socket.isConnected()) {inputStream = socket.getInputStream();dis = new DataInputStream(inputStream);/*因为Toast是要运行在主线程的  这里是子线程  所以需要到主线程哪里去显示toast*/Log.e(TAG, "服务连接成功");/*发送连接成功的消息*/if(onSocketStatusListener!=null)onSocketStatusListener.onConnectSuccess();/*发送心跳数据*/sendBeatData();}} catch (IOException e) {e.printStackTrace();if (e instanceof SocketTimeoutException) {Log.e(TAG,"连接超时,正在重连");releaseSocket();} else if (e instanceof NoRouteToHostException) {Log.e(TAG,"该地址不存在,请检查");} else if (e instanceof ConnectException) {Log.e(TAG,"连接异常或被拒绝,请检查");}}}});/*启动连接线程*/connectThread.start();}return this;}

二、发送数据

public void sendData(final String data) {if (socket != null && socket.isConnected()) {/*发送指令*/new Thread(new Runnable() {@Overridepublic void run() {try {outputStream = socket.getOutputStream();if (outputStream != null) {outputStream.write((data).getBytes("UTF-8"));outputStream.flush();}} catch (IOException e) {e.printStackTrace();}}}).start();} else {Log.e(TAG,"socket连接错误,请重试");}}

三、读取数据

private class ReadThread extends Thread {@Overridepublic void run() {super.run();//判断进程是否在运行,更安全的结束进程while (threadStatus) {if (inputStream != null) {try {rcvLength = dis.read(buff);if (rcvLength > 0) {rcvMsg = new String(buff, 0, rcvLength, "GBK");//接收到数据,切换主线程,显示数据handler.post(new Runnable() {@Overridepublic void run() {if(onReceiveDataListener!=null){onReceiveDataListener.onReceiveData(rcvMsg);}}});}} catch (Exception e) {Log.e(TAG,"接收总控数据异常");}}}}}

四、全部代码

package com.yufs.testsocket.tcp;import android.os.Handler;
import android.os.Looper;
import android.util.Log;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.NoRouteToHostException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Timer;
import java.util.TimerTask;public class TcpManager {private static final String TAG = TcpManager.class.getSimpleName();/*socket*/private Socket socket;/*连接线程*/private Thread connectThread;/* 发送输出流*/private OutputStream outputStream;/* 读写输入流*/private InputStream inputStream;private DataInputStream dis;/* 线程状态,安全结束线程*/private  boolean threadStatus =false;/* 读取保存进数组*/byte buff[]  = new byte[1024*1024*2];private String ip;private String port;private Handler handler = new Handler(Looper.getMainLooper());/*默认重连*/private boolean isReConnect = true;/*倒计时Timer发送心跳包*/private Timer timer;private TimerTask task;/* 心跳周期(s)*/private int heartCycle = 30;/*接收数据长度*/private int rcvLength;/*接收数据*/private String rcvMsg;private TcpManager(){}private static TcpManager instance;public static synchronized TcpManager getInstance(){if(instance==null){synchronized (TcpManager.class){instance=new TcpManager();}}return instance;}public TcpManager initSocket(final String ip, final String port) {this.ip=ip;this.port=port;/* 开启读写线程*/threadStatus =true;new ReadThread().start();if (socket == null && connectThread == null) {connectThread = new Thread(new Runnable() {@Overridepublic void run() {socket = new Socket();try {/*超时时间为2秒*/socket.connect(new InetSocketAddress(ip, Integer.valueOf(port)), 2000);/*连接成功的话  发送心跳包*/if (socket.isConnected()) {inputStream = socket.getInputStream();dis = new DataInputStream(inputStream);/*因为Toast是要运行在主线程的  这里是子线程  所以需要到主线程哪里去显示toast*/Log.e(TAG, "服务连接成功");/*发送连接成功的消息*/if(onSocketStatusListener!=null)onSocketStatusListener.onConnectSuccess();/*发送心跳数据*/sendBeatData();}} catch (IOException e) {e.printStackTrace();if (e instanceof SocketTimeoutException) {Log.e(TAG,"连接超时,正在重连");releaseSocket();} else if (e instanceof NoRouteToHostException) {Log.e(TAG,"该地址不存在,请检查");} else if (e instanceof ConnectException) {Log.e(TAG,"连接异常或被拒绝,请检查");}}}});/*启动连接线程*/connectThread.start();}return this;}/*发送数据*/public void sendData(final String data) {if (socket != null && socket.isConnected()) {/*发送指令*/new Thread(new Runnable() {@Overridepublic void run() {try {outputStream = socket.getOutputStream();if (outputStream != null) {outputStream.write((data).getBytes("UTF-8"));outputStream.flush();}} catch (IOException e) {e.printStackTrace();}}}).start();} else {Log.e(TAG,"socket连接错误,请重试");}}/*定时发送数据*/private void sendBeatData() {if (timer == null) {timer = new Timer();}if (task == null) {task = new TimerTask() {@Overridepublic void run() {try {outputStream = socket.getOutputStream();Log.i(TAG,"发送心跳包");/*这里的编码方式根据你的需求去改*/outputStream.write(("test\n").getBytes("UTF-8"));outputStream.flush();} catch (Exception e) {/*发送失败说明socket断开了或者出现了其他错误*/Log.e(TAG,"连接断开,正在重连");/*重连*/releaseSocket();e.printStackTrace();}}};}timer.schedule(task, 0, 1000*heartCycle);}/*释放资源*/private  void releaseSocket(){if (task != null) {task.cancel();task = null;}if (timer != null) {timer.purge();timer.cancel();timer = null;}if (outputStream != null) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}outputStream = null;}if(inputStream!=null){try {inputStream.close();} catch (IOException e) {e.printStackTrace();}inputStream=null;}if(dis!=null){try {dis.close();} catch (IOException e) {e.printStackTrace();}dis=null;}if (socket != null) {try {socket.close();} catch (IOException e) {}socket = null;}if (connectThread != null) {connectThread = null;}/*重新初始化socket*/if (isReConnect) {initSocket(ip,port);}}private class ReadThread extends Thread {@Overridepublic void run() {super.run();//判断进程是否在运行,更安全的结束进程while (threadStatus) {if (inputStream != null) {try {rcvLength = dis.read(buff);if (rcvLength > 0) {rcvMsg = new String(buff, 0, rcvLength, "GBK");//接收到数据,切换主线程,显示数据handler.post(new Runnable() {@Overridepublic void run() {if(onReceiveDataListener!=null){onReceiveDataListener.onReceiveData(rcvMsg);}}});}} catch (Exception e) {Log.e(TAG,"接收总控数据异常");}}}}}public interface OnSocketStatusListener{void onConnectSuccess();}public OnSocketStatusListener onSocketStatusListener;public void setOnSocketStatusListener(OnSocketStatusListener onSocketStatusListener) {this.onSocketStatusListener = onSocketStatusListener;}public interface OnReceiveDataListener{void onReceiveData(String str);}public OnReceiveDataListener onReceiveDataListener;public void setOnReceiveDataListener(OnReceiveDataListener onReceiveDataListener) {this.onReceiveDataListener = onReceiveDataListener;}
}

总体来说分为三步:连接、发送、线程监听数据,这里连接状态和接收数据使用了监听事件,可以考虑使用EventBus。整个代码写在一个工具类里面,里面还有很多需要优化的地方。不如说将这些写在服务里面,服务的生命周期与界面绑定。还有数据的读取这一方面好像有长度限制,超过一定长度,它就分为两次或三次,这个问题待解决,不过应对小数据的通信是没有问题的。

demo下载

Android Socket通信 发送心跳包 重连相关推荐

  1. java之socket的OOBInline和UrgentData和发送心跳包研究

    UrgentData可以理解为紧急发送数据方式,如果我们客户端先用write方法写入数据,再用UrgentData发送数据,再去执行flush操作,我们可以得到服务端先打印UrgentData发送的数 ...

  2. 关于android MqttClient消息推送客户端锁屏状态,无法发送心跳包解决方案

    1.客户端锁屏状态,无法发送心跳包 解决方案:使用电源锁 客户端:MqttService /** * 设备电源锁. */ private PowerManager.WakeLock mWakeLock ...

  3. android传递socket对象,Android Socket通信详解

    一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是"请求-响应方式",即在请求时 ...

  4. Socket网络编程心跳包介绍

    跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着.事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一 ...

  5. php websocket 心跳包,websocket 心跳包重连

    上次我们讲过了websocket断线重连的问题,那么久会有人提出疑问了,心跳包重连跟断线重连有什么区别呢? 其实这两个都是为了达到一个目的,那就是保证当前设备的网络状态保持通畅...而断线重连呢,只能 ...

  6. java Socket 长连接 心跳包 客户端 信息收发 demo

    今天写了个socket的测试小程序,代码如下 import java.io.IOException; import java.io.InputStream; import java.io.Output ...

  7. Android Socket通信(五) -- 实现一个多人聊天室

    系列文章: Android Socket 系列更新计划 Android Socket通信(一) – 初识与相遇 Android Socket通信(二) --UDP,单播,广播和多播(组播) Andro ...

  8. android socket通信如何抓取,安卓Socket通信实例(客户端、服务端)

    安卓Socket通信实例 本文摘自:https://whatsblog.icu/index.php/Android/17.html 1.Socket通信必须知道的地方 1.首先,Socket通信采用T ...

  9. android socket 简易聊天室 java服务器,Android Socket通信实现简单聊天室

    socket通信是基于底层TCP/IP协议实现的.这种服务端不需要任何的配置文件和tomcat就可以完成服务端的发布,使用纯java代码实现通信.socket是对TCP/IP的封装调用,本身并不是一种 ...

最新文章

  1. 协方差矩阵有什么意义?
  2. 西安python培训班多少钱-西安Python培训班哪个好
  3. reactjs组件的三大属性之props基本使用及props属性值检验
  4. IOS15的导航栏高度和状态栏高度和tabBar高度的获取
  5. jmeter集合点使用方法:Synchronizing Timer
  6. python模拟登录吃鸡_Python高级爬虫开发,高难度JS解密教程,绝地求生模拟登陆!...
  7. linux打开mysql某张表_Linux——MySQL多表连接
  8. 2021全国计算机二级知识点,2021年度Dlypeq全国计算机等级考试二级公共基础知识点总结.doc...
  9. android内存占用分析,Android内存优化————虚引用与弱引用的使用及内存分析工具...
  10. 物联网技术的基站能耗监控解决方案
  11. 基于C#的AE二次开发之GP工具的使用心得
  12. linux ip添加secondary ip,linux 添加secondary ip
  13. html p标签颜色代码,html里的颜色标签肿么写?
  14. 8.6 空间曲面及方程
  15. 抖音直播间怎样避免被封禁,直播间行为规范必看:国仁楠哥
  16. ytu 2463:给小鼠补充代码(DFS 深度优先搜索)
  17. 房地产神秘顾客调查方案
  18. ffmpeg 码率控制
  19. treap树---营业额统计
  20. Golang通用后台权限管理系统

热门文章

  1. 你能完整收看几套电视节目呢?
  2. 嵌入式ARM-Linux之OpenCV交叉编译
  3. python培训学费多少钱-python培训学费多少钱 学python课程价格是多少
  4. STM32Cube的PWM控制应用篇(二)用两个个定时器生成三个相位差120度的等效正弦波
  5. redmine安装插件流程
  6. 《摔跤吧!爸爸》——一个伟大的父亲与两位坚毅的女儿
  7. 交流电压测量之方均根——算法
  8. 应对隐私检测的各种姿势
  9. Qt跨平台文字转语音
  10. 长沙软件测试培训行情如何?