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 List<OnStringListener> onStringListenerList;
/**
* 常量
*/
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);
}
}
};
}
}
}