Tcp的连接和断开其实也就是很简短的代码,比较麻烦的就是断线检测重连等机制,如何设置的比较合理节省资源。
本代码暂时只是做简单的发送接收,并没有做比较严格的发送接收队列。
首先是断线,socket.isClosed() || !socket.isConnected()这两个socket方法都只是本地方法,如果在服务器端断开连接的话,这两个方法是检测不出来的。网上查了一下,据说是有4中方法来检测连接是否已经真正断开,方便起见我选用了sendUrgentData()方法,
socket.sendUrgentData(0);//发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信
为了验证发送状态,我再每次发送消息之前都会做一次检测,如果是频繁发送数据,不建议加上这个。
接收线程是阻塞的,所以不太好时时刻刻做这检测,所以我另外加了一个心跳机制,每秒(这个时间是非常频繁的)检测一次连接是否断开,如果断开则启动重连机制。
ALog类是我自定的输出打印类,用Log替换一下即可
package com.imxiaoyu.common.impl;/** * 回调一个字符串 * Created by 她叫我小渝 on 2016/11/1. */public interface OnStringListener { void onClick(String str);}
整个类的代码:
package com.ilink.ght.core.network.helper;import android.os.Handler;import android.os.Message;import com.imxiaoyu.common.impl.OnStringListener;import com.imxiaoyu.common.impl.OnSuccessListener;import com.imxiaoyu.common.utils.ALog;import com.imxiaoyu.common.utils.ByteUtils;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.net.Socket;import java.util.ArrayList;import java.util.List;/** * tcp发送接受帮助类 * Created by XiaoYu on 2017/2/22. */public class TcpHelper { private static String content; private static ListonStringListenerList; /** * 常量 */ private static final String HOST = "192.168.0.191"; private static final int PORT = 34952; /** * 变量 */ private static Socket socket = null; private static BufferedReader in = null; private static PrintWriter out = null; /** * TCP连接 */ public static void connTCP() { new Thread() { @Override public void run() { try { socket = new Socket(HOST, PORT); in = new BufferedReader(new InputStreamReader(socket .getInputStream())); out = new PrintWriter(new BufferedWriter(new OutputStreamWriter( socket.getOutputStream())), true); ALog.e("连接成功"); Message msg = new Message(); msg.obj = "连接成功"; mHandler.sendMessage(msg); if (checkConn()) { receiveMsg();//注册消息接收 ALog.e("连接注册消息接收"); handler.postAtTime(runnable, 1000); } else { ALog.e("服务里,TCP连接失败"); } } catch (Exception e) { e.printStackTrace(); ALog.e("TCP连接失败,尝试重连"); connTCP(); } } }.start(); startPing(); } /** * 断开连接 */ public static void disConn() { try { in.close(); out.close(); socket.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 判断连接是否可用 * * @return */ public static boolean checkConn() { if (socket == null) { return false; } if (socket.isClosed() || !socket.isConnected()) { return false; } try { socket.sendUrgentData(0);//发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信 return true; } catch (Exception se) { return false; } } /** * 发送消息 * * @param str * @param onSuccessListener */ public static void sendMsg(final String str, final OnSuccessListener onSuccessListener) { final Handler sendHandlde = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if(msg.what==1){ onSuccessListener.onSuccess(); }else{ String error=msg.obj+""; onSuccessListener.onError(error); } } }; new Thread() { @Override public void run() { Message msg=new Message(); if (checkConn()) { if (!socket.isOutputShutdown()) { out.print(str); msg.what=1; } else { ALog.e("发送,断开输出通道了"); msg.what=0; } } else { msg.what=0; msg.obj="连接已断开"; ALog.e("连接已断开"); } sendHandlde.sendMessage(msg); } }.start(); } /** * 接收消息 * 当连接发生变更的时候,必须要初始化一次这个方法, */ public static void receiveMsg() { try { while (true) { if (!socket.isClosed()) { if (socket.isConnected()) { if (!socket.isInputShutdown()) { if ((content = in.readLine()) != null) { content += "\n"; ALog.e("接收到消息:" + content); Message msg = new Message(); msg.obj = content; mHandler.sendMessage(msg); } else { ALog.e("读取不到,可能连接已经断开,关闭后尝试重连"); disConn(); ALog.e("正在尝试重连"); connTCP(); break; } } else { //输入流已经关闭 ALog.e("输入流已经关闭"); } } else { //是否已连接 ALog.e("输入流,连接已经断开"); } } else { //连接已关闭 ALog.e("输入流,连接已经关闭"); } } } catch (Exception e) { e.printStackTrace(); } } public static Handler mHandler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); if (onStringListenerList == null) { onStringListenerList = new ArrayList<>(); } for (int i = 0; i < onStringListenerList.size(); i++) { if (onStringListenerList != null) { onStringListenerList.get(i).onClick(msg.obj + ""); } } } }; /** * 添加消息监听器 */ public static void addRceiveListener(OnStringListener onStringListener) { if (onStringListenerList == null) { onStringListenerList = new ArrayList<>(); } if (onStringListener != null) { onStringListenerList.add(onStringListener); } } /** * 移除消息监听器 * * @param onStringListener */ public static void removeRceiveListener(OnStringListener onStringListener) { if (onStringListener != null) { for (int i = onStringListenerList.size() - 1; i >= 0; i++) { if (onStringListenerList.get(i) == onStringListener) { onStringListenerList.remove(i); } } } } private static Handler handler; private static Runnable runnable; private static void startPing() { if (handler == null) { handler = new Handler(); } if (runnable == null) { runnable = new Runnable() { @Override public void run() { if (!checkConn()) { ALog.e("心跳包验证失败,已经断开,尝试重连"); Message msg = new Message(); msg.obj = "心跳包验证失败,已经断开,尝试重连"; mHandler.sendMessage(msg); disConn(); connTCP(); } else { handler.postAtTime(this, 1000); } } }; } }}