first commit

This commit is contained in:
yezhiqiu
2025-09-30 10:01:20 +08:00
commit 0214fb09ed
1862 changed files with 119528 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.easysocket" >
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

View File

@@ -0,0 +1,136 @@
package com.easysocket;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.connection.connect.SuperConnection;
import com.easysocket.connection.connect.TcpConnection;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.config.IConnectionSwitchListener;
import com.easysocket.interfaces.conn.IConnectionManager;
import java.util.HashMap;
import java.util.Map;
/**
* AuthorAlex
* Date2019/6/4
* Notesocket连接管理器
*/
public class ConnectionHolder {
private volatile Map<String, IConnectionManager> mConnectionManagerMap = new HashMap<>();
private static class InstanceHolder {
private static final ConnectionHolder INSTANCE = new ConnectionHolder();
}
public static ConnectionHolder getInstance() {
return InstanceHolder.INSTANCE;
}
private ConnectionHolder() {
mConnectionManagerMap.clear();
}
/**
* 移除某个连接
*
* @param socketAddress
*/
public void removeConnection(SocketAddress socketAddress) {
removeConnection(createKey(socketAddress));
}
public void removeConnection(String socketAddress) {
mConnectionManagerMap.remove(socketAddress);
}
/**
* 获取指定SocketAddress的连接参数配置使用默认的
*
* @param address
* @return
*/
public IConnectionManager getConnection(SocketAddress address) {
return getConnection(createKey(address));
}
public IConnectionManager getConnection(String address) {
IConnectionManager manager = mConnectionManagerMap.get(address);
if (manager == null) {
return getConnection(address, EasySocketOptions.getDefaultOptions());
} else {
return getConnection(address, manager.getOptions());
}
}
/**
* 获取指定SocketAddress的连接
*
* @param address
* @param socketOptions
* @return
*/
public IConnectionManager getConnection(SocketAddress address, EasySocketOptions socketOptions) {
return getConnection(createKey(address),socketOptions);
}
public IConnectionManager getConnection(String address, EasySocketOptions socketOptions) {
IConnectionManager manager = mConnectionManagerMap.get(address);
if (manager != null) { // 有缓存
manager.setOptions(socketOptions);
return manager;
} else {
return createNewManagerAndCache(address, socketOptions);
}
}
/**
* 创建新的连接并缓存
*
* @param address
* @param socketOptions
* @return
*/
private IConnectionManager createNewManagerAndCache(SocketAddress address, EasySocketOptions socketOptions) {
SuperConnection manager = new TcpConnection(address); // 创建连接管理器
manager.setOptions(socketOptions); // 设置参数
// 连接主机的切换监听
manager.setOnConnectionSwitchListener(new IConnectionSwitchListener() {
@Override
public void onSwitchConnectionInfo(IConnectionManager manager, SocketAddress oldAddress,
SocketAddress newAddress) {
// 切换了另外一个主机的连接,删除旧的连接和添加新的连接
synchronized (mConnectionManagerMap) {
// 首先断开连接,销毁相关线程和资源
mConnectionManagerMap.get(createKey(oldAddress)).disconnect(false);
mConnectionManagerMap.remove(createKey(oldAddress));
mConnectionManagerMap.put(createKey(newAddress), manager);
}
}
});
synchronized (mConnectionManagerMap) {
mConnectionManagerMap.put(createKey(address), manager);
}
return manager;
}
private IConnectionManager createNewManagerAndCache(String address, EasySocketOptions socketOptions) {
return createNewManagerAndCache(createSocketAddress(address), socketOptions);
}
/**
* @param socketAddress
* @return
*/
private String createKey(SocketAddress socketAddress) {
return socketAddress.getIp() + ":" + socketAddress.getPort();
}
private SocketAddress createSocketAddress(String address) {
String[] s = address.split(":");
return new SocketAddress(s[0], Integer.parseInt(s[1]));
}
}

View File

@@ -0,0 +1,335 @@
package com.easysocket;
import android.content.Context;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.connection.heartbeat.HeartManager;
import com.easysocket.entity.SocketAddress;
import com.easysocket.entity.basemsg.SuperCallbackSender;
import com.easysocket.exception.InitialExeption;
import com.easysocket.exception.NotNullException;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionListener;
/**
* AuthorAlex
* Date2019/6/4
* NoteEasySocket API
*/
public class EasySocket {
/**
* 连接的缓存
*/
private static ConnectionHolder connectionHolder = ConnectionHolder.getInstance();
// 单例
private volatile static EasySocket singleton = null;
/**
* 默认的连接参数
*/
private EasySocketOptions defOptions;
/**
* 默认的连接
*/
private IConnectionManager defConnection;
/**
* 上下文
*/
private Context context;
/**
* 单例
*
* @return
*/
public static EasySocket getInstance() {
if (singleton == null) {
synchronized (EasySocket.class) {
if (singleton == null) {
singleton = new EasySocket();
}
}
}
return singleton;
}
/**
* 获取上下文
*
* @return
*/
public Context getContext() {
return context;
}
/**
* 获取默认的配置参数
*
* @return
*/
public EasySocketOptions getDefOptions() {
return defOptions == null ? EasySocketOptions.getDefaultOptions() : defOptions;
}
/**
* 创建socket连接此连接为默认的连接如果你的项目只有一个Socket连接可以用这个方法
* 在方法不指定连接地址的情况下,默认使用都是这个连接,
* 比如: upMessage(byte[] message)、 connect()等
*
* @return
*/
public EasySocket createConnection(EasySocketOptions options, Context context) {
this.defOptions = options;
this.context = context;
SocketAddress socketAddress = options.getSocketAddress();
if (options.getSocketAddress() == null) {
throw new InitialExeption("请在初始化的时候设置SocketAddress");
}
// 如果有备用主机则设置
if (options.getBackupAddress() != null) {
socketAddress.setBackupAddress(options.getBackupAddress());
}
if (defConnection == null) {
defConnection = connectionHolder.getConnection(socketAddress,
options == null ? EasySocketOptions.getDefaultOptions() : options);
}
// 执行连接
defConnection.connect();
return this;
}
/**
* 连接socket作用于默认连接
*
* @return
*/
public EasySocket connect() {
getDefconnection().connect();
return this;
}
/**
* @param address socket地址包括ip和端口
* @return
*/
public EasySocket connect(String address) {
getConnection(address).connect();
return this;
}
/**
* 关闭连接,作用于默认连接
*
* @param isNeedReconnect 是否需要重连
* @return
*/
public EasySocket disconnect(boolean isNeedReconnect) {
getDefconnection().disconnect(isNeedReconnect);
return this;
}
/**
* 关闭连接
*
* @param isNeedReconnect 是否需要重连
* @return
*/
public EasySocket disconnect(String address, boolean isNeedReconnect) {
getConnection(address).disconnect(isNeedReconnect);
return this;
}
/**
* 销毁连接对象,作用于默认连接
*
* @return
*/
public EasySocket destroyConnection() {
// 断开连接
getDefconnection().disconnect(false);
// 移除连接
connectionHolder.removeConnection(defOptions.getSocketAddress());
defConnection = null;
return this;
}
/**
* 销毁连接对象
*
* @return
*/
public EasySocket destroyConnection(String address) {
// 断开连接
getConnection(address).disconnect(false);
// 移除连接
connectionHolder.removeConnection(address);
return this;
}
/**
* 发送有回调的消息,作用于默认连接
*
* @param sender
* @return
*/
public IConnectionManager upCallbackMessage(SuperCallbackSender sender) {
getDefconnection().upCallbackMessage(sender);
return defConnection;
}
/**
* 发送有回调的消息
*
* @param sender
* @return
*/
public IConnectionManager upCallbackMessage(SuperCallbackSender sender, String address) {
return getConnection(address).upCallbackMessage(sender);
}
/**
* 发送byte[]
*
* @param message
* @return
*/
public IConnectionManager upMessage(byte[] message, String address) {
return getConnection(address).upBytes(message);
}
/**
* 发送byte[],作用于默认连接
*
* @param message
* @return
*/
public IConnectionManager upMessage(byte[] message) {
return getDefconnection().upBytes(message);
}
/**
* 注册监听socket行为作用于默认连接
*
* @param socketActionListener
*/
public EasySocket subscribeSocketAction(ISocketActionListener socketActionListener) {
getDefconnection().subscribeSocketAction(socketActionListener);
return this;
}
/**
* 注册监听socket行为
*
* @param socketActionListener
*/
public EasySocket subscribeSocketAction(ISocketActionListener socketActionListener, String address) {
getConnection(address).subscribeSocketAction(socketActionListener);
return this;
}
/**
* 开启心跳检测,作用于默认连接
*
* @param clientHeart
* @return
*/
public EasySocket startHeartBeat(byte[] clientHeart, HeartManager.HeartbeatListener listener) {
getDefconnection().getHeartManager().startHeartbeat(clientHeart, listener);
return this;
}
/**
* 开启心跳检测
*
* @param clientHeart
* @return
*/
public EasySocket startHeartBeat(byte[] clientHeart, String address, HeartManager.HeartbeatListener listener) {
getConnection(address).getHeartManager().startHeartbeat(clientHeart, listener);
return this;
}
/**
* 获取连接
*
* @return
*/
public IConnectionManager getDefconnection() {
if (defConnection == null) {
throw new NotNullException("你还没有创建:" + defOptions.getSocketAddress().getIp() + ":" + defOptions.getSocketAddress().getPort()
+ "的Socket的连接请使用com.easysocket.EasySocket.connect()方法创建一个默认的连接");
}
return defConnection;
}
/**
* 获取连接
*
* @return
*/
public IConnectionManager getConnection(String address) {
IConnectionManager connectionManager = connectionHolder.getConnection(address);
if (connectionManager == null) {
throw new NotNullException("请先创建:" + address + "的Socket连接");
}
return connectionManager;
}
/**
* 创建指定的socket连接如果你的项目有多个socket连接可以用这个方法创建更多的连接
* 当你使用带有socket地址为参数的方法的时候作用的就是对应的连接
* 比如connect(String address)、 upMessage(byte[] message, String address)等
*
* @param socketOptions
* @return
*/
public IConnectionManager createSpecifyConnection(EasySocketOptions socketOptions, Context context) {
this.context = context;
IConnectionManager connectionManager = connectionHolder.getConnection(socketOptions.getSocketAddress(), socketOptions == null
? EasySocketOptions.getDefaultOptions() : socketOptions);
connectionManager.connect();
return connectionManager;
}
/**
* 获取指定的连接
*
* @param socketAddress
* @return
*/
public IConnectionManager getSpecifyConnection(String socketAddress) {
return connectionHolder.getConnection(socketAddress);
}
/**
* 发送消息至指定的连接
*
* @param sender
* @param socketAddress
*/
public IConnectionManager upToSpecifyConnection(byte[] sender, String socketAddress) {
IConnectionManager connect = getSpecifyConnection(socketAddress);
if (connect != null) {
connect.upBytes(sender);
}
return connect;
}
/**
* 是否为debug
*
* @param debug
*/
public void setDebug(boolean debug) {
EasySocketOptions.setIsDebug(debug);
}
}

View File

@@ -0,0 +1,116 @@
package com.easysocket.callback;
import android.app.Dialog;
import android.content.DialogInterface;
import com.easysocket.entity.OriginReadData;
import com.easysocket.exception.RequestCancelException;
import com.easysocket.interfaces.callback.IProgressDialog;
import com.easysocket.interfaces.callback.ProgressCancelListener;
/**
* 自定义带有加载进度框的回调
*/
public abstract class ProgressDialogCallBack extends SuperCallBack implements ProgressCancelListener {
private IProgressDialog progressDialog;
private Dialog mDialog;
private boolean isShowProgress = true;
/**
* @param
*/
public ProgressDialogCallBack(IProgressDialog progressDialog, String callbackId) {
super(callbackId);
this.progressDialog = progressDialog;
init(false);
onStart();
}
/**
* 自定义加载进度框,可以设置是否显示弹出框,是否可以取消
*
* @param progressDialog dialog
* @param isShowProgress 是否显示进度
* @param isCancel 对话框是否可以取消
* @param
*/
public ProgressDialogCallBack(IProgressDialog progressDialog, boolean isShowProgress,
boolean isCancel, String callbackId) {
super(callbackId);
this.progressDialog = progressDialog;
this.isShowProgress = isShowProgress;
init(isCancel);
onStart();
}
/**
* 初始化
*
* @param isCancel
*/
private void init(boolean isCancel) {
if (progressDialog == null) return;
mDialog = progressDialog.getDialog();
if (mDialog == null) return;
mDialog.setCancelable(isCancel);
if (isCancel) {
mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
ProgressDialogCallBack.this.onCancelProgress();
}
});
}
}
/**
* 展示进度框
*/
private void showProgress() {
if (!isShowProgress) {
return;
}
if (mDialog != null && !mDialog.isShowing()) {
mDialog.show();
}
}
/**
* 取消进度框
*/
private void dismissProgress() {
if (!isShowProgress) {
return;
}
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
}
}
@Override
public void onStart() {
showProgress();
}
@Override
public void onCompleted() {
dismissProgress();
}
public abstract void onResponse(OriginReadData data);
@Override
public void onError(Exception e) {
onCompleted();
}
@Override
public void onCancelProgress() {
onCompleted();
onError(new RequestCancelException("网络请求被取消"));
}
}

View File

@@ -0,0 +1,29 @@
package com.easysocket.callback;
/**
* Created by LXR ON 2018/8/29.
*/
public abstract class SimpleCallBack extends SuperCallBack{
public SimpleCallBack(String callbackId) {
super(callbackId);
}
@Override
public void onStart() {
}
@Override
public void onCompleted() {
}
@Override
public void onError(Exception e) {
}
}

View File

@@ -0,0 +1,44 @@
package com.easysocket.callback;
import com.easysocket.entity.OriginReadData;
/**
* Created by LXR ON 2018/8/29.
*/
public abstract class SuperCallBack {
/**
* 随机字符串,识别服务端应答消息的唯一标识
*/
private String callbackId;
/**
* @param callbackId 识别服务端应答消息的唯一标识
*/
public SuperCallBack(String callbackId) {
this.callbackId = callbackId;
}
/**
* 获取回调ID
*
* @return
*/
public String getCallbackId() {
return callbackId;
}
public abstract void onStart();
public abstract void onCompleted();
public abstract void onError(Exception e);
public void onSuccess(OriginReadData data) {
onCompleted();
onResponse(data);
}
public abstract void onResponse(OriginReadData data);
}

View File

@@ -0,0 +1,18 @@
package com.easysocket.config;
import com.easysocket.entity.OriginReadData;
/**
* AuthorAlex
* Date2019/6/4
* Note要想实现EasySocket的回调功能必须实现此工厂类callbackID作为回调消息的唯一标识
*/
public abstract class CallbackIDFactory {
/**
* 返回callbackID
*
* @param
* @return 如果没有callbackID请返回null
*/
public abstract String getCallbackID(OriginReadData data);
}

View File

@@ -0,0 +1,28 @@
package com.easysocket.config;
import com.easysocket.interfaces.config.IMessageProtocol;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* AuthorAlex
* Date2019/5/31
* Note默认的消息协议header为4个字节保存消息体 body的长度
*/
public class DefaultMessageProtocol implements IMessageProtocol {
@Override
public int getHeaderLength() {
return 4; // 包头长度用来保存body的长度值
}
@Override
public int getBodyLength(byte[] header, ByteOrder byteOrder) {
if (header == null || header.length < getHeaderLength()) {
return 0;
}
ByteBuffer bb = ByteBuffer.wrap(header);
bb.order(byteOrder);
return bb.getInt(); // body的长度以int的形式保存在 header
}
}

View File

@@ -0,0 +1,28 @@
package com.easysocket.config;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
/**
* AuthorAlex
* Date2019/6/3
* Note
*/
public class DefaultX509ProtocolTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}

View File

@@ -0,0 +1,478 @@
package com.easysocket.config;
import com.easysocket.connection.reconnect.AbsReconnection;
import com.easysocket.connection.reconnect.DefaultReConnection;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.config.IMessageProtocol;
import java.nio.ByteOrder;
/**
* AuthorAlex。
* Date2019/5/31。
* Notesocket相关配置。
*/
public class EasySocketOptions {
/**
* 是否调试模式
*/
private static boolean isDebug = true;
/**
* 主机地址
*/
private SocketAddress socketAddress;
/**
* 备用主机地址
*/
private SocketAddress backupAddress;
/**
* 写入Socket管道的字节序
*/
private ByteOrder writeOrder;
/**
* 从Socket读取字节时的字节序
*/
private ByteOrder readOrder;
/**
* 从socket读取数据时遵从的数据包结构协议在业务层进行定义
*/
private IMessageProtocol messageProtocol;
/**
* 写数据时单个数据包的最大值
*/
private int maxWriteBytes;
/**
* 读数据时单次读取最大缓存值,数值越大效率越高,但是系统消耗也越大
*/
private int maxReadBytes;
/**
* 心跳频率/毫秒
*/
private long heartbeatFreq;
/**
* 心跳最大的丢失次数大于这个数据将断开socket连接
*/
private int maxHeartbeatLoseTimes;
/**
* 连接超时时间(毫秒)
*/
private int connectTimeout;
/**
* 服务器返回数据的最大值单位Mb防止客户端内存溢出
*/
private int maxResponseDataMb;
/**
* socket重连管理器
*/
private AbsReconnection reconnectionManager;
/**
* 安全套接字相关配置
*/
private SocketSSLConfig easySSLConfig;
/**
* socket工厂
*/
private SocketFactory socketFactory;
/**
* 实现回调功能需要callbackID而callbackID是保存在发送消息和应答消息中的此工厂用来获取socket消息中
* 保存callbackID值的key比如json格式中的key-value中的key
*/
private CallbackIDFactory callbackIDFactory;
/**
* 请求超时时间,单位毫秒
*/
private long requestTimeout;
/**
* 是否开启请求超时检测
*/
private boolean isOpenRequestTimeout;
/**
* IO字符流的编码方式默认utf-8
*/
private String charsetName;
public boolean isDebug() {
return isDebug;
}
/**
* 静态内部类
*/
public static class Builder {
EasySocketOptions socketOptions;
// 首先获得一个默认的配置
public Builder() {
this(getDefaultOptions());
}
public Builder(EasySocketOptions defaultOptions) {
socketOptions = defaultOptions;
}
/**
* 设置socket 主机地址
*
* @param socketAddress
* @return
*/
public Builder setSocketAddress(SocketAddress socketAddress) {
socketOptions.socketAddress = socketAddress;
return this;
}
/**
* 设置备用的主机地址
*
* @param backupAddress
* @return
*/
public Builder setBackupAddress(SocketAddress backupAddress) {
socketOptions.backupAddress = backupAddress;
return this;
}
/**
* 设置是否开启请求超时的检测
*
* @param openRequestTimeout
* @return
*/
public Builder setOpenRequestTimeout(boolean openRequestTimeout) {
socketOptions.isOpenRequestTimeout = openRequestTimeout;
return this;
}
/**
* 设置请求超时时间
*
* @param requestTimeout 毫秒
* @return
*/
public Builder setRequestTimeout(long requestTimeout) {
socketOptions.requestTimeout = requestTimeout;
return this;
}
/**
* 设置请求ack的工厂
*
* @param callbackIDFactory
*/
public Builder setCallbackIDFactory(CallbackIDFactory callbackIDFactory) {
socketOptions.callbackIDFactory = callbackIDFactory;
return this;
}
/**
* 设置写数据的字节顺序
*
* @param writeOrder
* @return
*/
public Builder setWriteOrder(ByteOrder writeOrder) {
socketOptions.writeOrder = writeOrder;
return this;
}
/**
* 设置读数据的字节顺序
*
* @param readOrder
* @return
*/
public Builder setReadOrder(ByteOrder readOrder) {
socketOptions.readOrder = readOrder;
return this;
}
/**
* 设置读取数据的数据结构协议
*
* @param readerProtocol
* @return
*/
public Builder setReaderProtocol(IMessageProtocol readerProtocol) {
socketOptions.messageProtocol = readerProtocol;
return this;
}
/**
* 设置写数据时单个数据包的最大值
*
* @param maxWriteBytes
* @return
*/
public Builder setMaxWriteBytes(int maxWriteBytes) {
socketOptions.maxWriteBytes = maxWriteBytes;
return this;
}
/**
* 设置读数据时单次读取的最大缓存值
*
* @param maxReadBytes
* @return
*/
public Builder setMaxReadBytes(int maxReadBytes) {
socketOptions.maxReadBytes = maxReadBytes;
return this;
}
/**
* 设置心跳发送频率,单位毫秒
*
* @param heartbeatFreq
* @return
*/
public Builder setHeartbeatFreq(long heartbeatFreq) {
socketOptions.heartbeatFreq = heartbeatFreq;
return this;
}
/**
* 设置心跳丢失的最大允许数如果超过这个最大数就断开socket连接
*
* @param maxHeartbeatLoseTimes
* @return
*/
public Builder setMaxHeartbeatLoseTimes(int maxHeartbeatLoseTimes) {
socketOptions.maxHeartbeatLoseTimes = maxHeartbeatLoseTimes;
return this;
}
/**
* 设置连接超时时间
*
* @param connectTimeout
* @return
*/
public Builder setConnectTimeout(int connectTimeout) {
socketOptions.connectTimeout = connectTimeout;
return this;
}
/**
* 设置服务器返回数据的允许的最大值,单位兆
*
* @param maxResponseDataMb
* @return
*/
public Builder setMaxResponseDataMb(int maxResponseDataMb) {
socketOptions.maxResponseDataMb = maxResponseDataMb;
return this;
}
/**
* 设置重连管理器
*
* @param reconnectionManager
* @return
*/
public Builder setReconnectionManager(AbsReconnection reconnectionManager) {
socketOptions.reconnectionManager = reconnectionManager;
return this;
}
/**
* 安全套接字的配置
*
* @param easySSLConfig
* @return
*/
public Builder setEasySSLConfig(SocketSSLConfig easySSLConfig) {
socketOptions.easySSLConfig = easySSLConfig;
return this;
}
/**
* 自定义创建socket工厂
*
* @param socketFactory
* @return
*/
public Builder setSocketFactory(SocketFactory socketFactory) {
socketOptions.socketFactory = socketFactory;
return this;
}
public Builder setCharsetName(String charsetName) {
socketOptions.charsetName = charsetName;
return this;
}
public EasySocketOptions build() {
return socketOptions;
}
}
/**
* 获取默认的配置
*
* @return
*/
public static EasySocketOptions getDefaultOptions() {
EasySocketOptions options = new EasySocketOptions();
options.socketAddress = null;
options.backupAddress = null;
options.heartbeatFreq = 5 * 1000;
options.messageProtocol = null;
options.maxResponseDataMb = 5;
options.connectTimeout = 5 * 1000; // 连接超时默认5秒
options.maxWriteBytes = 100;
options.maxReadBytes = 50;
options.readOrder = ByteOrder.BIG_ENDIAN;
options.writeOrder = ByteOrder.BIG_ENDIAN;
options.maxHeartbeatLoseTimes = 5;
options.reconnectionManager = new DefaultReConnection();
options.easySSLConfig = null;
options.socketFactory = null;
options.callbackIDFactory = null;
options.requestTimeout = 10 * 1000; // 默认十秒
options.isOpenRequestTimeout = true; // 默认开启
options.charsetName = "UTF-8";
return options;
}
public String getCharsetName() {
return charsetName;
}
public ByteOrder getWriteOrder() {
return writeOrder;
}
public ByteOrder getReadOrder() {
return readOrder;
}
public IMessageProtocol getMessageProtocol() {
return messageProtocol;
}
public int getMaxWriteBytes() {
return maxWriteBytes;
}
public int getMaxReadBytes() {
return maxReadBytes;
}
public long getHeartbeatFreq() {
return heartbeatFreq;
}
public int getMaxHeartbeatLoseTimes() {
return maxHeartbeatLoseTimes;
}
public int getConnectTimeout() {
return connectTimeout;
}
public int getMaxResponseDataMb() {
return maxResponseDataMb;
}
public AbsReconnection getReconnectionManager() {
return reconnectionManager;
}
public SocketSSLConfig getEasySSLConfig() {
return easySSLConfig;
}
public SocketFactory getSocketFactory() {
return socketFactory;
}
public long getRequestTimeout() {
return requestTimeout;
}
public boolean isOpenRequestTimeout() {
return isOpenRequestTimeout;
}
public CallbackIDFactory getCallbackIDFactory() {
return callbackIDFactory;
}
public static void setIsDebug(boolean isDebug) {
EasySocketOptions.isDebug = isDebug;
}
public void setWriteOrder(ByteOrder writeOrder) {
this.writeOrder = writeOrder;
}
public void setReadOrder(ByteOrder readOrder) {
this.readOrder = readOrder;
}
public void setMessageProtocol(IMessageProtocol messageProtocol) {
this.messageProtocol = messageProtocol;
}
public void setMaxWriteBytes(int maxWriteBytes) {
this.maxWriteBytes = maxWriteBytes;
}
public void setMaxReadBytes(int maxReadBytes) {
this.maxReadBytes = maxReadBytes;
}
public void setHeartbeatFreq(long heartbeatFreq) {
this.heartbeatFreq = heartbeatFreq;
}
public void setMaxHeartbeatLoseTimes(int maxHeartbeatLoseTimes) {
this.maxHeartbeatLoseTimes = maxHeartbeatLoseTimes;
}
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
public void setMaxResponseDataMb(int maxResponseDataMb) {
this.maxResponseDataMb = maxResponseDataMb;
}
public void setReconnectionManager(AbsReconnection reconnectionManager) {
this.reconnectionManager = reconnectionManager;
}
public void setEasySSLConfig(SocketSSLConfig easySSLConfig) {
this.easySSLConfig = easySSLConfig;
}
public void setSocketFactory(SocketFactory socketFactory) {
this.socketFactory = socketFactory;
}
public void setCallbackIDFactory(CallbackIDFactory callbackIDFactory) {
this.callbackIDFactory = callbackIDFactory;
}
public void setRequestTimeout(long requestTimeout) {
this.requestTimeout = requestTimeout;
}
public void setOpenRequestTimeout(boolean openRequestTimeout) {
isOpenRequestTimeout = openRequestTimeout;
}
public SocketAddress getSocketAddress() {
return socketAddress;
}
public SocketAddress getBackupAddress() {
return backupAddress;
}
}

View File

@@ -0,0 +1,14 @@
package com.easysocket.config;
import com.easysocket.entity.SocketAddress;
import java.net.Socket;
/**
* AuthorAlex
* Date2019/5/31
* Notesocket工厂
*/
public abstract class SocketFactory {
public abstract Socket createSocket(SocketAddress info, EasySocketOptions options) throws Exception;
}

View File

@@ -0,0 +1,81 @@
package com.easysocket.config;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
/**
* socket的ssl配置
*/
public class SocketSSLConfig {
/**
* 安全协议名称(缺省为SSL)
*/
private String mProtocol;
/**
* 信任证书管理器(缺省为X509)
*/
private TrustManager[] mTrustManagers;
/**
* 证书秘钥管理器(缺省为null)
*/
private KeyManager[] mKeyManagers;
/**
* 自定义SSLFactory(缺省为null)
*/
private SSLSocketFactory mCustomSSLFactory;
private SocketSSLConfig() {
}
public static class Builder {
private SocketSSLConfig mConfig;
public Builder() {
mConfig = new SocketSSLConfig();
}
public Builder setProtocol(String protocol) {
mConfig.mProtocol = protocol;
return this;
}
public Builder setTrustManagers(TrustManager[] trustManagers) {
mConfig.mTrustManagers = trustManagers;
return this;
}
public Builder setKeyManagers(KeyManager[] keyManagers) {
mConfig.mKeyManagers = keyManagers;
return this;
}
public Builder setCustomSSLFactory(SSLSocketFactory customSSLFactory) {
mConfig.mCustomSSLFactory = customSSLFactory;
return this;
}
public SocketSSLConfig build() {
return mConfig;
}
}
public KeyManager[] getKeyManagers() {
return mKeyManagers;
}
public String getProtocol() {
return mProtocol;
}
public TrustManager[] getTrustManagers() {
return mTrustManagers;
}
public SSLSocketFactory getCustomSSLFactory() {
return mCustomSSLFactory;
}
}

View File

@@ -0,0 +1,11 @@
package com.easysocket.connection.action;
/**
* AuthorAlex
* Date2019/6/3
* Note
*/
public interface IOAction {
// 收到消息响应
String ACTION_READ_COMPLETE = "action_read_complete";
}

View File

@@ -0,0 +1,15 @@
package com.easysocket.connection.action;
/**
* AuthorAlex
* Date2019/6/1
* Note
*/
public interface SocketAction {
// 连接成功
String ACTION_CONN_SUCCESS="action_conn_success";
// 连接失败
String ACTION_CONN_FAIL="action_conn_fail";
// 断开连接
String ACTION_DISCONNECTION="action_disconnection";
}

View File

@@ -0,0 +1,17 @@
package com.easysocket.connection.action;
/**
* AuthorAlex
* Date2019/6/1
* Note连接状态
*/
public interface SocketStatus {
// 已断开连接
int SOCKET_DISCONNECTED = 0;
// 正在连接
int SOCKET_CONNECTING = 1;
// 已连接
int SOCKET_CONNECTED = 2;
// 正在断开连接
int SOCKET_DISCONNECTING =3;
}

View File

@@ -0,0 +1,340 @@
package com.easysocket.connection.connect;
import com.easysocket.EasySocket;
import com.easysocket.callback.SuperCallBack;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.connection.action.SocketAction;
import com.easysocket.connection.action.SocketStatus;
import com.easysocket.connection.dispatcher.CallbackResponseDispatcher;
import com.easysocket.connection.dispatcher.SocketActionDispatcher;
import com.easysocket.connection.heartbeat.HeartManager;
import com.easysocket.connection.iowork.IOManager;
import com.easysocket.connection.reconnect.AbsReconnection;
import com.easysocket.entity.SocketAddress;
import com.easysocket.entity.basemsg.SuperCallbackSender;
import com.easysocket.exception.NotNullException;
import com.easysocket.interfaces.config.IConnectionSwitchListener;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionListener;
import com.easysocket.utils.LogUtil;
import com.easysocket.utils.Utils;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
/**
* AuthorAlex
* Date2019/5/29
* Notesocket连接的超类
*/
public abstract class SuperConnection implements IConnectionManager {
/**
* 连接状态,初始值为断开连接
*/
protected final AtomicInteger connectionStatus = new AtomicInteger(SocketStatus.SOCKET_DISCONNECTED);
/**
* 连接线程
*/
private ExecutorService connExecutor;
/**
* socket地址信息
*/
protected SocketAddress socketAddress;
/**
* socket行为分发器
*/
private SocketActionDispatcher actionDispatcher;
/**
* 重连管理器
*/
private AbsReconnection reconnection;
/**
* io管理器
*/
private IOManager ioManager;
/**
* 心跳管理器
*/
private HeartManager heartManager;
/**
* 配置信息
*/
protected EasySocketOptions socketOptions;
/**
* socket回调消息的分发器
*/
private CallbackResponseDispatcher callbackResponseDispatcher;
/**
* 连接切换的监听
*/
private IConnectionSwitchListener connectionSwitchListener;
public SuperConnection(SocketAddress socketAddress) {
this.socketAddress = socketAddress;
actionDispatcher = new SocketActionDispatcher(this, socketAddress);
}
@Override
public void subscribeSocketAction(ISocketActionListener iSocketActionListener) {
actionDispatcher.subscribe(iSocketActionListener);
}
@Override
public void unSubscribeSocketAction(ISocketActionListener iSocketActionListener) {
actionDispatcher.unsubscribe(iSocketActionListener);
}
@Override
public synchronized IConnectionManager setOptions(EasySocketOptions socketOptions) {
if (socketOptions == null) return this;
this.socketOptions = socketOptions;
if (ioManager != null)
ioManager.setOptions(socketOptions);
if (heartManager != null)
heartManager.setOptions(socketOptions);
if (callbackResponseDispatcher != null)
callbackResponseDispatcher.setSocketOptions(socketOptions);
// 更改了重连器
if (reconnection != null && !reconnection.equals(socketOptions.getReconnectionManager())) {
reconnection.detach();
reconnection = socketOptions.getReconnectionManager();
reconnection.attach(this);
}
return this;
}
@Override
public EasySocketOptions getOptions() {
return socketOptions;
}
@Override
public synchronized void connect() {
LogUtil.d("---> socket开始连接");
if (socketAddress.getIp() == null) {
throw new NotNullException("请检查是否设置了IP地址");
}
// 正在连接
connectionStatus.set(SocketStatus.SOCKET_CONNECTING);
// 心跳管理器
if (heartManager == null) {
heartManager = new HeartManager(this, actionDispatcher);
}
// 重连管理器
if (reconnection != null) {
reconnection.detach();
}
reconnection = socketOptions.getReconnectionManager();
if (reconnection != null) {
reconnection.attach(this);
}
// 开启分发消息线程
if (actionDispatcher != null) {
actionDispatcher.startDispatchThread();
}
// 开启连接线程
if (connExecutor == null || connExecutor.isShutdown()) {
// 核心线程数为0非核心线程数可以有Integer.MAX_VALUE个存活时间为60秒适合于在不断进行连接的情况下避免重复创建和销毁线程
connExecutor = Executors.newCachedThreadPool();
}
// 执行连接任务
connExecutor.execute(connTask);
}
@Override
public synchronized void disconnect(boolean isNeedReconnect) {
// 判断当前socket的连接状态
if (connectionStatus.get() == SocketStatus.SOCKET_DISCONNECTED) {
return;
}
// 正在重连中
if (isNeedReconnect && reconnection.isReconning()) {
return;
}
// 正在断开连接
connectionStatus.set(SocketStatus.SOCKET_DISCONNECTING);
// 开启断开连接线程
String info = socketAddress.getIp() + " : " + socketAddress.getPort();
Thread disconnThread = new DisconnectThread(isNeedReconnect, "disconn thread" + info);
disconnThread.setDaemon(true);
disconnThread.start();
}
/**
* 断开连接线程
*/
private class DisconnectThread extends Thread {
boolean isNeedReconnect; // 当前连接的断开是否需要自动重连
public DisconnectThread(boolean isNeedReconnect, String name) {
super(name);
this.isNeedReconnect = isNeedReconnect;
}
@Override
public void run() {
try {
// 关闭io线程
if (ioManager != null)
ioManager.closeIO();
// 关闭回调分发器线程
if (callbackResponseDispatcher != null)
callbackResponseDispatcher.shutdownThread();
// 关闭连接线程
if (connExecutor != null && !connExecutor.isShutdown()) {
connExecutor.shutdown();
connExecutor = null;
}
// 关闭连接
closeConnection();
LogUtil.d("---> 关闭socket连接");
connectionStatus.set(SocketStatus.SOCKET_DISCONNECTED);
actionDispatcher.dispatchAction(SocketAction.ACTION_DISCONNECTION, new Boolean(isNeedReconnect));
} catch (IOException e) {
// 断开连接发生异常
e.printStackTrace();
}
}
}
// 连接任务
private Runnable connTask = new Runnable() {
@Override
public void run() {
try {
openConnection();
} catch (Exception e) {
// 连接异常
e.printStackTrace();
LogUtil.d("---> socket连接失败");
connectionStatus.set(SocketStatus.SOCKET_DISCONNECTED);
// 第二个参数指需要重连
actionDispatcher.dispatchAction(SocketAction.ACTION_CONN_FAIL, new Boolean(true));
}
}
};
/**
* 连接成功
*/
protected void onConnectionOpened() {
LogUtil.d("---> socket连接成功");
actionDispatcher.dispatchAction(SocketAction.ACTION_CONN_SUCCESS);
connectionStatus.set(SocketStatus.SOCKET_CONNECTED);
openSocketManager();
}
// 开启socket相关管理器
private void openSocketManager() {
if (callbackResponseDispatcher == null)
callbackResponseDispatcher = new CallbackResponseDispatcher(this);
if (ioManager == null) {
ioManager = new IOManager(this, actionDispatcher);
}
ioManager.startIO();
// 启动相关线程
callbackResponseDispatcher.engineThread();
ioManager.startIO();
}
// 切换了主机IP和端口
@Override
public synchronized void switchHost(SocketAddress socketAddress) {
if (socketAddress != null) {
SocketAddress oldAddress = this.socketAddress;
this.socketAddress = socketAddress;
if (actionDispatcher != null)
actionDispatcher.setSocketAddress(socketAddress);
// 切换主机
if (connectionSwitchListener != null) {
connectionSwitchListener.onSwitchConnectionInfo(this, oldAddress, socketAddress);
}
}
}
public void setOnConnectionSwitchListener(IConnectionSwitchListener listener) {
connectionSwitchListener = listener;
}
@Override
public boolean isConnectViable() {
// 当前socket是否处于可连接状态
return Utils.isNetConnected(EasySocket.getInstance().getContext()) && connectionStatus.get() == SocketStatus.SOCKET_DISCONNECTED;
}
@Override
public int getConnectionStatus() {
return connectionStatus.get();
}
/**
* 打开连接
*
* @throws IOException
*/
protected abstract void openConnection() throws Exception;
/**
* 关闭连接
*
* @throws IOException
*/
protected abstract void closeConnection() throws IOException;
/**
* 发送bytes数据
*
* @param bytes
* @return
*/
private IConnectionManager sendBytes(byte[] bytes) {
if (ioManager == null || connectionStatus.get() != SocketStatus.SOCKET_CONNECTED) {
return this;
}
ioManager.sendBytes(bytes);
return this;
}
@Override
public void onCallBack(SuperCallBack callBack) {
callbackResponseDispatcher.addSocketCallback(callBack);
}
@Override
public synchronized IConnectionManager upBytes(byte[] bytes) {
sendBytes(bytes);
return this;
}
@Override
public synchronized IConnectionManager upCallbackMessage(SuperCallbackSender sender) {
callbackResponseDispatcher.checkCallbackSender(sender);
// 发送
sendBytes(sender.pack());
return this;
}
@Override
public HeartManager getHeartManager() {
return heartManager;
}
}

View File

@@ -0,0 +1,141 @@
package com.easysocket.connection.connect;
import com.easysocket.config.DefaultX509ProtocolTrustManager;
import com.easysocket.config.SocketSSLConfig;
import com.easysocket.connection.action.SocketStatus;
import com.easysocket.entity.SocketAddress;
import com.easysocket.utils.LogUtil;
import com.easysocket.utils.Utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.SecureRandom;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
/**
* AuthorAlex
* Date2019/5/29
* Notetcp连接
*/
public class TcpConnection extends SuperConnection {
/**
* socket对象
*/
private Socket socket;
public TcpConnection(SocketAddress socketAddress) {
super(socketAddress);
}
@Override
protected void openConnection() throws Exception {
try {
socket = getSocket();
} catch (Exception e) {
e.printStackTrace();
connectionStatus.set(SocketStatus.SOCKET_DISCONNECTED); // 设置为未连接
throw new RuntimeException("创建socket失败");
}
// 进行socket连接
socket.connect(new InetSocketAddress(socketAddress.getIp(), socketAddress.getPort()), socketOptions.getConnectTimeout());
// 关闭Nagle算法,无论TCP数据报大小,立即发送
socket.setTcpNoDelay(true);
// 连接已经打开
if (socket.isConnected() && !socket.isClosed()) {
onConnectionOpened();
}
}
@Override
protected void closeConnection() throws IOException {
if (socket != null)
socket.close();
}
/**
* 根据配置信息获取对应的socket
*
* @return
*/
private synchronized Socket getSocket() throws Exception {
// 自定义的socket生成工厂
if (socketOptions.getSocketFactory() != null) {
return socketOptions.getSocketFactory().createSocket(socketAddress, socketOptions);
}
// 默认操作
SocketSSLConfig config = socketOptions.getEasySSLConfig();
if (config == null) {
return new Socket();
}
// 获取SSL配置工厂
SSLSocketFactory factory = config.getCustomSSLFactory();
if (factory == null) {
String protocol = "SSL";
if (!Utils.isStringEmpty(config.getProtocol())) {
protocol = config.getProtocol();
}
TrustManager[] trustManagers = config.getTrustManagers();
if (trustManagers == null || trustManagers.length == 0) {
// 缺省信任所有证书
trustManagers = new TrustManager[]{new DefaultX509ProtocolTrustManager()};
}
try {
SSLContext sslContext = SSLContext.getInstance(protocol);
sslContext.init(config.getKeyManagers(), trustManagers, new SecureRandom());
return sslContext.getSocketFactory().createSocket();
} catch (Exception e) {
if (socketOptions.isDebug()) {
e.printStackTrace();
}
LogUtil.e(e.getMessage());
return new Socket();
}
} else {
try {
return factory.createSocket();
} catch (IOException e) {
if (socketOptions.isDebug()) {
e.printStackTrace();
}
LogUtil.e(e.getMessage());
return new Socket();
}
}
}
@Override
public InputStream getInputStream() {
if (socket != null && socket.isConnected() && !socket.isClosed()) {
try {
return socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public OutputStream getOutStream() {
if (socket != null && socket.isConnected() && !socket.isClosed()) {
try {
return socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}

View File

@@ -0,0 +1,187 @@
package com.easysocket.connection.dispatcher;
import com.easysocket.callback.SuperCallBack;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
import com.easysocket.entity.basemsg.SuperCallbackSender;
import com.easysocket.exception.RequestTimeOutException;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.SocketActionListener;
import com.easysocket.utils.LogUtil;
import com.easysocket.utils.Utils;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* AuthorAlex
* Date2019/6/4
* Note回调消息分发器
*/
public class CallbackResponseDispatcher {
/**
* 保存发送的每个回调消息的监听实例key为回调标识callbackId这样回调消息有反馈的时候就可以找到并调用
* 对应的监听对象
*/
private Map<String, SuperCallBack> callbacks = new HashMap<>();
/**
* 保存需要进行超时检测的请求,这是一个延时队列,元素超时的时候会被取出来
*/
private DelayQueue<timeoutItem> timeoutQueue = new DelayQueue<>();
/**
* 超时检测的线程管理器
*/
private ExecutorService timeoutExecutor;
/**
* 连接管理
*/
IConnectionManager connectionManager;
private EasySocketOptions socketOptions;
public CallbackResponseDispatcher(IConnectionManager connectionManager) {
this.connectionManager = connectionManager;
socketOptions = connectionManager.getOptions();
// 注册监听
connectionManager.subscribeSocketAction(socketActionListener);
// 开始超时检测线程
engineThread();
}
/**
* 设置socketoptions
*
* @param socketOptions
*/
public void setSocketOptions(EasySocketOptions socketOptions) {
this.socketOptions = socketOptions;
}
/**
* 超时检测线程
*/
public void engineThread() {
if (timeoutExecutor == null || timeoutExecutor.isShutdown()) {
timeoutExecutor = Executors.newSingleThreadExecutor();
timeoutExecutor.execute(new Runnable() {
@Override
public void run() {
try {
// 只有超时的元素才会被取出,没有的话会被等待
timeoutItem item = timeoutQueue.take();
if (item != null) {
SuperCallBack callBack = callbacks.remove(item.callbackId);
if (callBack != null)
callBack.onError(new RequestTimeOutException("request timeout"));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
// 继续循环
if (timeoutExecutor != null && !timeoutExecutor.isShutdown()) {
run();
}
}
});
}
}
/**
* 关闭线程
*/
public void shutdownThread() {
if (timeoutExecutor != null && !timeoutExecutor.isShutdown()) {
// shutdown和shutdownNow的主要区别是前者中断未执行的线程后者中断所有线程
timeoutExecutor.shutdownNow();
timeoutExecutor = null;
}
}
/**
* socket行为监听重写反馈消息的回调方法
*/
private SocketActionListener socketActionListener = new SocketActionListener() {
@Override
public void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData) {
if (callbacks.size() == 0) return;
if (socketOptions.getCallbackIDFactory() == null) return;
// 获取回调ID
String callbackID = socketOptions.getCallbackIDFactory().getCallbackID(originReadData);
if (callbackID != null) {
// 获取callbackID对应的callback
SuperCallBack callBack = callbacks.get(callbackID);
if (callBack != null) {
// 回调
callBack.onSuccess(originReadData);
callbacks.remove(callbackID); // 移除完成任务的callback
LogUtil.d("移除的callbackId-->" + callbackID);
}
}
}
};
/**
* 每发一条回调消息都要在这里添加监听对象
*
* @param superCallBack
*/
public void addSocketCallback(SuperCallBack superCallBack) {
callbacks.put(superCallBack.getCallbackId(), superCallBack);
// 放入延时队列
long delayTime = socketOptions == null ?
EasySocketOptions.getDefaultOptions().getRequestTimeout() : socketOptions.getRequestTimeout();
timeoutQueue.add(new timeoutItem(superCallBack.getCallbackId(), delayTime, TimeUnit.MILLISECONDS));
}
/**
* 延时队列的item
*/
class timeoutItem implements Delayed {
String callbackId; // 当前callback的callbackId
long executeTime; // 触发时间
public timeoutItem(String callbackId, long delayTime, TimeUnit timeUnit) {
this.callbackId = callbackId;
this.executeTime = System.currentTimeMillis() + (delayTime > 0 ? timeUnit.toMillis(delayTime) : 0);
}
@Override
public long getDelay(TimeUnit unit) {
return executeTime - System.currentTimeMillis();
}
@Override
public int compareTo(Delayed o) {
return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
}
}
/**
* 同一个消息发送多次callbackId是不能一样的所以这里要先check一下否则服务端反馈的时候客户端接收就会乱套
*
* @param callbackSender
* @return
*/
public void checkCallbackSender(SuperCallbackSender callbackSender) {
Utils.checkNotNull(socketOptions.getCallbackIDFactory(), "要想实现EasySocket的回调功能CallbackIdFactory不能为null" +
"请实现一个CallbackIdFactory并在初始化的时候通过EasySocketOptions的setCallbackIdFactory进行配置");
String callbackId = callbackSender.getCallbackId();
// 同一个消息发送两次以上callbackId是不能一样的否则服务端反馈的时候客户端接收就会乱套
if (callbacks.containsKey(callbackId)) {
callbackSender.generateCallbackId();
}
}
}

View File

@@ -0,0 +1,21 @@
package com.easysocket.connection.dispatcher;
import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.Executor;
/**
* AuthorMapogo
* Date2020/4/8
* Note切到主线程
*/
public class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}

View File

@@ -0,0 +1,221 @@
package com.easysocket.connection.dispatcher;
import com.easysocket.EasySocket;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionDispatch;
import com.easysocket.interfaces.conn.ISocketActionListener;
import com.easysocket.utils.Utils;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import static com.easysocket.connection.action.IOAction.ACTION_READ_COMPLETE;
import static com.easysocket.connection.action.SocketAction.ACTION_CONN_FAIL;
import static com.easysocket.connection.action.SocketAction.ACTION_CONN_SUCCESS;
import static com.easysocket.connection.action.SocketAction.ACTION_DISCONNECTION;
/**
* AuthorAlex
* Date2019/6/1
* Notesocket行为分发器
*/
public class SocketActionDispatcher implements ISocketActionDispatch {
/**
* 连接地址
*/
private SocketAddress socketAddress;
/**
* 连接器
*/
private IConnectionManager connectionManager;
/**
* 回调监听集合
*/
private List<ISocketActionListener> actionListeners = new ArrayList<>();
/**
* 处理socket行为的线程
*/
private Thread actionThread;
/**
* 是否停止分发
*/
private boolean isStop;
/**
* 事件消费队列
*/
private final LinkedBlockingQueue<ActionBean> socketActions = new LinkedBlockingQueue();
/**
* 切换到UI线程
*/
private MainThreadExecutor mainThreadExecutor = new MainThreadExecutor();
public SocketActionDispatcher(IConnectionManager connectionManager, SocketAddress socketAddress) {
this.socketAddress = socketAddress;
this.connectionManager = connectionManager;
}
public void setSocketAddress(SocketAddress info) {
socketAddress = info;
}
@Override
public void dispatchAction(String action) {
dispatchAction(action, null);
}
@Override
public void dispatchAction(String action, Serializable serializable) {
// 将接收到的socket行为封装入列
ActionBean actionBean = new ActionBean(action, serializable, this);
socketActions.offer(actionBean);
}
@Override
public void subscribe(ISocketActionListener iSocketActionListener) {
if (iSocketActionListener != null && !actionListeners.contains(iSocketActionListener)) {
actionListeners.add(iSocketActionListener);
}
}
@Override
public void unsubscribe(ISocketActionListener iSocketActionListener) {
actionListeners.remove(iSocketActionListener);
}
/**
* 分发线程
*/
private class DispatchThread extends Thread {
public DispatchThread() {
super("dispatch thread");
}
@Override
public void run() {
// 循环处理socket的行为信息
while (!isStop) {
try {
ActionBean actionBean = socketActions.take();
if (actionBean != null && actionBean.mDispatcher != null) {
SocketActionDispatcher actionDispatcher = actionBean.mDispatcher;
List<ISocketActionListener> copyListeners = new ArrayList<>(actionDispatcher.actionListeners);
Iterator<ISocketActionListener> listeners = copyListeners.iterator();
// 通知所有监听者
while (listeners.hasNext()) {
ISocketActionListener listener = listeners.next();
actionDispatcher.dispatchActionToListener(actionBean.mAction, actionBean.arg, listener);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* socket行为的封装
*/
protected static class ActionBean {
public ActionBean(String action, Serializable arg, SocketActionDispatcher dispatcher) {
mAction = action;
this.arg = arg;
mDispatcher = dispatcher;
}
String mAction = "";
Serializable arg;
SocketActionDispatcher mDispatcher;
}
/**
* 分发行为给监听者
*
* @param action
* @param content
* @param actionListener
*/
private void dispatchActionToListener(String action, final Serializable content, final ISocketActionListener actionListener) {
switch (action) {
case ACTION_CONN_SUCCESS: // 连接成功
mainThreadExecutor.execute(new Runnable() {
@Override
public void run() {
actionListener.onSocketConnSuccess(socketAddress);
}
});
break;
case ACTION_CONN_FAIL: // 连接失败
mainThreadExecutor.execute(new Runnable() {
@Override
public void run() {
actionListener.onSocketConnFail(socketAddress, ((Boolean) content).booleanValue());
}
});
break;
case ACTION_DISCONNECTION: // 连接断开
mainThreadExecutor.execute(new Runnable() {
@Override
public void run() {
actionListener.onSocketDisconnect(socketAddress, ((Boolean) content).booleanValue());
// 不需要重连,则释放资源
if (!(Boolean) content) {
stopDispatchThread();
}
}
});
break;
case ACTION_READ_COMPLETE: // 读取数据完成
mainThreadExecutor.execute(new Runnable() {
@Override
public void run() {
// response有三种形式
actionListener.onSocketResponse(socketAddress, (OriginReadData) content);
byte[] data = Utils.concatBytes(((OriginReadData) content).getHeaderData(), ((OriginReadData) content).getBodyBytes());
actionListener.onSocketResponse(socketAddress, new String(data, Charset.forName(EasySocket.getInstance().getDefOptions().getCharsetName())));
actionListener.onSocketResponse(socketAddress, data);
}
});
break;
}
}
// 开始分发线程
@Override
public void startDispatchThread() {
isStop = false;
if (actionThread == null) {
actionThread = new DispatchThread();
actionThread.start();
}
}
@Override
public void stopDispatchThread() {
if (actionThread != null && actionThread.isAlive() && !actionThread.isInterrupted()) {
socketActions.clear();
//actionListeners.clear();
isStop = true;
actionThread.interrupt();
actionThread = null;
}
}
}

View File

@@ -0,0 +1,181 @@
package com.easysocket.connection.heartbeat;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.config.IOptions;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.IHeartManager;
import com.easysocket.interfaces.conn.ISocketActionDispatch;
import com.easysocket.interfaces.conn.SocketActionListener;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* AuthorAlex
* Date2019/12/8
* Note心跳包检测管理器
*/
public class HeartManager extends SocketActionListener implements IOptions, IHeartManager {
/**
* 连接器
*/
private IConnectionManager connectionManager;
/**
* 连接参数
*/
private EasySocketOptions socketOptions;
/**
* 客户端心跳包
*/
private byte[] clientHeart;
/**
* 心跳包发送线程
*/
private ScheduledExecutorService heartExecutor;
/**
* 记录心跳的失联次数
*/
private AtomicInteger loseTimes = new AtomicInteger(-1);
/**
* 心跳频率
*/
private long freq;
/**
* 是否激活了心跳
*/
private boolean isActivate;
/**
* 心跳包接收监听
*/
private HeartbeatListener heartbeatListener;
public HeartManager(IConnectionManager iConnectionManager, ISocketActionDispatch actionDispatch) {
this.connectionManager = iConnectionManager;
socketOptions = iConnectionManager.getOptions();
actionDispatch.subscribe(this); // 注册监听
}
/**
* 心跳发送任务
*/
private final Runnable beatTask = new Runnable() {
@Override
public void run() {
// 心跳丢失次数判断心跳包丢失了一定的次数则会进行socket的断开重连
if (socketOptions.getMaxHeartbeatLoseTimes() != -1
&& loseTimes.incrementAndGet() >= socketOptions.getMaxHeartbeatLoseTimes()) {
// 断开重连
connectionManager.disconnect(true);
resetLoseTimes();
} else { // 发送心跳包
connectionManager.upBytes(clientHeart);
}
}
};
@Override
public void startHeartbeat(byte[] clientHeart, HeartbeatListener listener) {
this.clientHeart = clientHeart;
this.heartbeatListener = listener;
isActivate = true;
openThread();
}
// 启动心跳线程
private void openThread() {
freq = socketOptions.getHeartbeatFreq(); // 心跳频率
// 启动线程发送心跳
if (heartExecutor == null || heartExecutor.isShutdown()) {
heartExecutor = Executors.newSingleThreadScheduledExecutor();
heartExecutor.scheduleWithFixedDelay(beatTask, 0, freq, TimeUnit.MILLISECONDS);
}
}
/**
* 停止心跳发送
*/
@Override
public void stopHeartbeat() {
isActivate = false;
closeThread();
}
// 停止心跳线程
private void closeThread() {
if (heartExecutor != null && !heartExecutor.isShutdown()) {
heartExecutor.shutdownNow();
heartExecutor = null;
resetLoseTimes(); // 重置
}
}
@Override
public void onReceiveHeartBeat() {
resetLoseTimes();
}
private void resetLoseTimes() {
loseTimes.set(-1);
}
@Override
public void onSocketConnSuccess(SocketAddress socketAddress) {
if (isActivate) {
openThread();
}
}
@Override
public void onSocketConnFail(SocketAddress socketAddress, boolean isNeedReconnect) {
// 如果不需要重连,则停止心跳频率线程
if (!isNeedReconnect) {
closeThread();
}
}
@Override
public void onSocketDisconnect(SocketAddress socketAddress, boolean isNeedReconnect) {
// 如果不需要重连,则停止心跳检测
if (!isNeedReconnect) {
closeThread();
}
}
@Override
public void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData) {
if (heartbeatListener != null && heartbeatListener.isServerHeartbeat(originReadData)) {
// 收到服务器心跳
onReceiveHeartBeat();
}
}
@Override
public Object setOptions(EasySocketOptions socketOptions) {
this.socketOptions = socketOptions;
freq = socketOptions.getHeartbeatFreq();
freq = freq < 1000 ? 1000 : freq; // 不能小于一秒
return this;
}
@Override
public EasySocketOptions getOptions() {
return socketOptions;
}
public interface HeartbeatListener {
// 是否为服务器心跳
boolean isServerHeartbeat(OriginReadData orginReadData);
}
}

View File

@@ -0,0 +1,327 @@
package com.easysocket.connection.iowork;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.connection.action.IOAction;
import com.easysocket.entity.OriginReadData;
import com.easysocket.exception.ReadRecoverableExeption;
import com.easysocket.exception.ReadUnrecoverableException;
import com.easysocket.interfaces.config.IMessageProtocol;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionDispatch;
import com.easysocket.interfaces.io.IReader;
import com.easysocket.utils.LogUtil;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
/**
* AuthorAlex
* Date2019/6/1
* Note
*/
public class EasyReader implements IReader<EasySocketOptions> {
/**
* 输入流
*/
private InputStream inputStream;
/**
* 读取原始数据的缓存空间
*/
private ByteBuffer originBuf;
/**
* socket行为分发器
*/
private ISocketActionDispatch actionDispatch;
/**
* 连接器
*/
private IConnectionManager connectionManager;
/**
* 连接参数
*/
private EasySocketOptions socketOptions;
/**
* 读数据时,余留数据的缓存
*/
private ByteBuffer remainingBuf;
/**
* 读数据线程
*/
private Thread readerThread;
/**
* 是否停止线程
*/
private boolean stopThread;
public EasyReader(IConnectionManager connectionManager, ISocketActionDispatch actionDispatch) {
this.actionDispatch = actionDispatch;
this.connectionManager = connectionManager;
socketOptions = connectionManager.getOptions();
}
@Override
public void read() throws IOException, ReadRecoverableExeption, ReadUnrecoverableException {
OriginReadData originalData = new OriginReadData();
IMessageProtocol messageProtocol = socketOptions.getMessageProtocol();
// 消息协议为null则直接读原始消息不建议这样使用因为会发生黏包、分包的问题
if (messageProtocol == null) {
readOriginDataFromSteam(originalData);
return;
}
// 定义了消息协议
int headerLength = messageProtocol.getHeaderLength(); // 包头长度
ByteBuffer headBuf = ByteBuffer.allocate(headerLength); // 包头数据的buffer
headBuf.order(socketOptions.getReadOrder());
/*1、读 header=====>>>*/
if (remainingBuf != null) { // 有余留
// flip方法一般从Buffer读数据前调用将limit设置为当前position将position设置为0在读数据时limit代表可读数据的有效长度
remainingBuf.flip();
// 读余留数据的长度
int length = Math.min(remainingBuf.remaining(), headerLength);
// 读入余留数据
headBuf.put(remainingBuf.array(), 0, length);
if (length < headerLength) { // 余留数据小于一个header
// there are no data left
remainingBuf = null;
// 从stream中读剩下的header数据
readHeaderFromSteam(headBuf, headerLength - length);
} else {
// 移动开始读数据的指针
remainingBuf.position(headerLength);
}
} else { // 无余留
// 从stream读取一个完整的 header
readHeaderFromSteam(headBuf, headBuf.capacity());
}
// 保存header
originalData.setHeaderData(headBuf.array());
/*2、读 body=====>>>*/
int bodyLength = messageProtocol.getBodyLength(originalData.getHeaderData(), socketOptions.getReadOrder());
if (bodyLength > 0) {
if (bodyLength > socketOptions.getMaxResponseDataMb() * 1024 * 1024) {
throw new ReadUnrecoverableException("服务器返回的单次数据超过了规定的最大值可能你的Socket消息协议不对一般消息格式" +
"Header+Body其中Header保存消息长度和类型等Body保存消息内容请规范好你的协议");
}
// 分配空间
ByteBuffer bodyBuf = ByteBuffer.allocate(bodyLength);
bodyBuf.order(socketOptions.getReadOrder());
// 有余留
if (remainingBuf != null) {
int bodyStartPosition = remainingBuf.position();
int length = Math.min(remainingBuf.remaining(), bodyLength);
// 读length大小的余留数据
bodyBuf.put(remainingBuf.array(), bodyStartPosition, length);
// 移动position位置
remainingBuf.position(bodyStartPosition + length);
// 读的余留数据刚好等于一个body
if (length == bodyLength) {
if (remainingBuf.remaining() > 0) { // 余留数据未读完
ByteBuffer temp = ByteBuffer.allocate(remainingBuf.remaining());
temp.order(socketOptions.getReadOrder());
temp.put(remainingBuf.array(), remainingBuf.position(), remainingBuf.remaining());
remainingBuf = temp;
} else { // there are no data left
remainingBuf = null;
}
// 保存body
originalData.setBodyData(bodyBuf.array());
LogUtil.d("Socket收到数据-->" + originalData.getBodyString());
// 分发数据
actionDispatch.dispatchAction(IOAction.ACTION_READ_COMPLETE, originalData);
/*return读取结束*/
return;
} else { // there are no data left in buffer and some data pieces in channel
remainingBuf = null;
}
}
// 无余留则从stream中读
readBodyFromStream(bodyBuf);
// 保存body到originalData
originalData.setBodyData(bodyBuf.array());
} else if (bodyLength == 0) { // 没有body数据
originalData.setBodyData(new byte[0]);
if (remainingBuf != null) {
// the body is empty so header remaining buf need set null
if (remainingBuf.hasRemaining()) {
ByteBuffer temp = ByteBuffer.allocate(remainingBuf.remaining());
temp.order(socketOptions.getReadOrder());
temp.put(remainingBuf.array(), remainingBuf.position(), remainingBuf.remaining());
remainingBuf = temp;
} else {
remainingBuf = null;
}
}
} else if (bodyLength < 0) {
throw new ReadUnrecoverableException("数据body的长度不能小于0");
}
LogUtil.d("Socket收到数据-->" + originalData.getBodyString());
// 分发
actionDispatch.dispatchAction(IOAction.ACTION_READ_COMPLETE, originalData);
}
/**
* 读数据任务
*/
private Runnable readerTask = new Runnable() {
@Override
public void run() {
try {
while (!stopThread) {
read();
}
} catch (ReadUnrecoverableException unrecoverableException) {
// 读异常
unrecoverableException.printStackTrace();
// 停止线程
stopThread = true;
release();
} catch (ReadRecoverableExeption readRecoverableExeption) {
readRecoverableExeption.printStackTrace();
// 重连
connectionManager.disconnect(true);
} catch (IOException e) {
e.printStackTrace();
// 重连
connectionManager.disconnect(true);
}
}
};
private void readHeaderFromSteam(ByteBuffer headBuf, int readLength) throws ReadRecoverableExeption, IOException {
for (int i = 0; i < readLength; i++) {
byte[] bytes = new byte[1];
// 从输入流中读数据,无数据时会阻塞
int value = inputStream.read(bytes);
// -1代表读到了文件的末尾一般是因为服务器断开了连接
if (value == -1) {
throw new ReadRecoverableExeption("读数据失败可能是因为socket跟服务器断开了连接");
}
headBuf.put(bytes);
}
}
private void readOriginDataFromSteam(OriginReadData readData) throws ReadRecoverableExeption, IOException {
// 用 全局originBuf避免重复创建字节数组
int len = inputStream.read(originBuf.array());
// no more data
if (len == -1) {
throw new ReadRecoverableExeption("读数据失败可能因为socket跟服务器断开了连接");
}
// bytes复制
byte[] data = new byte[len];
originBuf.get(data, 0, len);
readData.setBodyData(data);
LogUtil.d("Socket收到数据-->" + readData.getBodyString());
// 分发数据
actionDispatch.dispatchAction(IOAction.ACTION_READ_COMPLETE, readData);
// 相当于把指针重新指向positon=0
originBuf.clear();
}
private void readBodyFromStream(ByteBuffer byteBuffer) throws ReadRecoverableExeption, IOException {
// while循环直到byteBuffer装满数据
while (byteBuffer.hasRemaining()) {
byte[] bufArray = new byte[socketOptions.getMaxReadBytes()]; // 从服务器单次读取的最大值
int len = inputStream.read(bufArray);
if (len == -1) { // no more data
throw new ReadRecoverableExeption("读数据失败可能是因为socket跟服务器断开了连接");
}
int remaining = byteBuffer.remaining();
if (len > remaining) { // 从stream读的数据超过byteBuffer的剩余空间
byteBuffer.put(bufArray, 0, remaining);
// 将多余的数据保存到remainingBuf中缓存等下一次读取
remainingBuf = ByteBuffer.allocate(len - remaining);
remainingBuf.order(socketOptions.getReadOrder());
remainingBuf.put(bufArray, remaining, len - remaining);
} else { // 从stream读的数据小于或等于byteBuffer的剩余空间
byteBuffer.put(bufArray, 0, len);
}
}
}
@Override
public void openReader() {
init();
if (readerThread == null || !readerThread.isAlive()) {
readerThread = new Thread(readerTask, "reader thread");
stopThread = false;
readerThread.start();
}
}
@Override
public void closeReader() {
try {
// 关闭线程释放资源
shutDownThread();
release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 释放资源
private void release() {
if (originBuf != null) {
originBuf = null;
}
if (remainingBuf != null) {
remainingBuf = null;
}
if (readerThread != null && !readerThread.isAlive()) {
readerThread = null;
}
try {
if (inputStream != null)
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
inputStream = null;
}
}
// 初始化
private void init() {
inputStream = connectionManager.getInputStream();
// 没有定义消息协议
if (socketOptions.getMessageProtocol() == null) {
originBuf = ByteBuffer.allocate(1024 * 4);
}
}
@Override
public void setOption(EasySocketOptions socketOptions) {
this.socketOptions = socketOptions;
}
// 关闭读数据线程
private void shutDownThread() throws InterruptedException {
if (readerThread != null && readerThread.isAlive() && !readerThread.isInterrupted()) {
stopThread = true;
readerThread.interrupt();
readerThread.join();
}
}
}

View File

@@ -0,0 +1,146 @@
package com.easysocket.connection.iowork;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionDispatch;
import com.easysocket.interfaces.io.IWriter;
import com.easysocket.utils.LogUtil;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.concurrent.LinkedBlockingDeque;
/**
* AuthorAlex
* Date2019/6/1
* Note
*/
public class EasyWriter implements IWriter<EasySocketOptions> {
/**
* 输出流
*/
private OutputStream outputStream;
/**
* 连接管理器
*/
private IConnectionManager connectionManager;
/**
* socket参数
*/
private EasySocketOptions socketOptions;
/**
* 行为分发
*/
private ISocketActionDispatch actionDispatch;
/**
* 写数据线程
*/
private Thread writerThread;
/**
* 是否停止写数据
*/
private boolean isStop;
/**
* 待写入数据
*/
private LinkedBlockingDeque<byte[]> packetsToSend = new LinkedBlockingDeque<>();
public EasyWriter(IConnectionManager connectionManager, ISocketActionDispatch actionDispatch) {
this.connectionManager = connectionManager;
socketOptions = connectionManager.getOptions();
this.actionDispatch = actionDispatch;
}
@Override
public void openWriter() {
outputStream = connectionManager.getOutStream();
if (writerThread == null) {
isStop = false;
writerThread = new Thread(writerTask, "writer thread");
writerThread.start();
}
}
@Override
public void setOption(EasySocketOptions socketOptions) {
this.socketOptions = socketOptions;
}
/**
* 写任务
*/
private Runnable writerTask = new Runnable() {
@Override
public void run() {
// 循环写数据
while (!isStop) {
try {
byte[] sender = packetsToSend.take();
write(sender);
} catch (InterruptedException | IOException e) {
e.printStackTrace();
}
}
}
};
@Override
public void write(byte[] sendBytes) throws IOException {
if (sendBytes != null) {
LogUtil.d("Socket发送数据String-->" + new String(sendBytes, Charset.forName("utf-8")));
LogUtil.d("Socket发送数据byte[]-->" + Arrays.toString(sendBytes));
int packageSize = socketOptions.getMaxWriteBytes(); // 每次可以发送的最大数据
int remainingCount = sendBytes.length;
ByteBuffer writeBuf = ByteBuffer.allocate(packageSize);
writeBuf.order(socketOptions.getReadOrder());
int index = 0;
// 如果发送的数据大于单次可发送的最大数据,则分多次发送
while (remainingCount > 0) {
int realWriteLength = Math.min(packageSize, remainingCount);
writeBuf.clear(); // 清空缓存
writeBuf.rewind(); // 将position位置移到0
writeBuf.put(sendBytes, index, realWriteLength);
writeBuf.flip();
byte[] writeArr = new byte[realWriteLength];
writeBuf.get(writeArr);
outputStream.write(writeArr);
outputStream.flush(); // 强制写入缓存中残留数据
index += realWriteLength;
remainingCount -= realWriteLength;
}
}
}
@Override
public void offer(byte[] sender) {
if (!isStop)
packetsToSend.offer(sender);
}
@Override
public void closeWriter() {
try {
if (outputStream != null)
outputStream.close();
shutDownThread();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
} finally {
outputStream = null;
}
}
private void shutDownThread() throws InterruptedException {
if (writerThread != null && writerThread.isAlive() && !writerThread.isInterrupted()) {
isStop = true;
writerThread.interrupt();
writerThread.join();
writerThread = null;
}
}
}

View File

@@ -0,0 +1,98 @@
package com.easysocket.connection.iowork;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.interfaces.config.IOptions;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionDispatch;
import com.easysocket.interfaces.io.IIOManager;
import com.easysocket.interfaces.io.IReader;
import com.easysocket.interfaces.io.IWriter;
/**
* AuthorAlex
* Date2019/5/28
* Note
*/
public class IOManager implements IIOManager, IOptions {
/**
* socket行为回调
*/
private ISocketActionDispatch actionDispatch;
/**
* 连接管理
*/
private IConnectionManager connectionManager;
/**
* 写
*/
private IWriter writer;
/**
* 读
*/
private IReader reader;
public IOManager(IConnectionManager connectionManager,
ISocketActionDispatch connActionDispatch) {
this.connectionManager = connectionManager;
this.actionDispatch = connActionDispatch;
initIO();
}
// 初始化io
private void initIO() {
//makesureHeaderProtocolNotEmpty();
reader = new EasyReader(connectionManager, actionDispatch); // 读
writer = new EasyWriter(connectionManager, actionDispatch); // 写
}
@Override
public void sendBytes(byte[] bytes) {
if (writer != null)
writer.offer(bytes);
}
@Override
public void startIO() {
if (writer != null)
writer.openWriter();
if (reader != null)
reader.openReader();
}
@Override
public void closeIO() {
if (writer != null)
writer.closeWriter();
if (reader != null)
reader.closeReader();
}
@Override
public Object setOptions(EasySocketOptions socketOptions) {
//makesureHeaderProtocolNotEmpty();
if (writer != null)
writer.setOption(socketOptions);
if (reader != null)
reader.setOption(socketOptions);
return this;
}
@Override
public EasySocketOptions getOptions() {
return connectionManager.getOptions();
}
/**
* 确保包结构协议不为空
*/
// private void makesureHeaderProtocolNotEmpty() {
// IMessageProtocol protocol = connectionManager.getOptions().getMessageProtocol();
// if (protocol == null) {
// throw new NoNullException("The reader protocol can not be Null.");
// }
//
// if (protocol.getHeaderLength() == 0) {
// throw new NoNullException("The header length can not be zero.");
// }
// }
}

View File

@@ -0,0 +1,52 @@
package com.easysocket.connection.reconnect;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.IReconnListener;
import com.easysocket.interfaces.conn.SocketActionListener;
/**
* AuthorAlex
* Date2019/5/31
* Note抽象重连器
*/
public abstract class AbsReconnection extends SocketActionListener implements IReconnListener {
/**
* 连接管理器
*/
protected IConnectionManager connectionManager;
/**
* socket连接管理器是否已销毁
*/
protected boolean isDetach;
@Override
public synchronized void attach(IConnectionManager iConnectionManager) {
if (!isDetach) {
detach();
}
isDetach = false;
connectionManager = iConnectionManager;
connectionManager.subscribeSocketAction(this); // 监听socket行为
}
@Override
public synchronized void detach() {
isDetach = true;
if (connectionManager != null)
connectionManager.unSubscribeSocketAction(this);
}
@Override
public void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData) {
// donothing
}
/**
* 是否正在重连
* @return
*/
public abstract boolean isReconning();
}

View File

@@ -0,0 +1,148 @@
package com.easysocket.connection.reconnect;
import android.os.Handler;
import android.os.HandlerThread;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.utils.LogUtil;
/**
* AuthorAlex
* Date2019/5/28
* Note默认重连器
*/
public class DefaultReConnection extends AbsReconnection {
/**
* 最大连接失败次数,超过可以切换到备用的服务器地址
*/
private static final int MAX_CONNECTION_FAILED_TIMES = 10;
/**
* 连接失败的次数
*/
private int connectionFailedTimes = 0;
/**
* 重连间隔不能小于10秒为了避免全部客户端socket在同一时间连接服务端间隔时间需要上下浮动50%
*/
private long reconnectTimeDelay = 30 * 1000;
/**
* 重连线程
*/
private HandlerThread handlerThread;
/**
* 实现延时任务的 handler
*/
private Handler handler;
public DefaultReConnection() {
}
@Override
public synchronized void attach(IConnectionManager iConnectionManager) {
super.attach(iConnectionManager);
if (reconnectTimeDelay < connectionManager.getOptions().getConnectTimeout()) {
reconnectTimeDelay = connectionManager.getOptions().getConnectTimeout();
}
}
/**
* 重连任务
*/
private final Runnable RcConnTask = new Runnable() {
@Override
public void run() {
LogUtil.d("---> 执行重连");
if (isDetach) {
shutDown();
return;
}
// 是否可连接的
if (!connectionManager.isConnectViable()) {
LogUtil.d("当前条件不允许连接");
// 尝试再次重连
handler.postDelayed(RcConnTask, (long) (reconnectTimeDelay * (Math.random() + 0.5)));
return;
}
// 重连
connectionManager.connect();
}
};
/**
* 进行重连
*/
private void reconnect() {
if (handlerThread == null) {
handlerThread = new HandlerThread("re_conn");
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
}
LogUtil.d("重连间隔时间-->" + reconnectTimeDelay * (Math.random() + 0.5));
handler.postDelayed(RcConnTask, (long) (reconnectTimeDelay * (Math.random() + 0.5)));
}
// 关闭重连线程
private void shutDown() {
if (handlerThread != null && handlerThread.isAlive()) {
handlerThread.quit();
handlerThread = null;
handler = null;
}
}
@Override
public boolean equals(Object o) {
// getClass返回Class类型的对象比较它们的类型对象是否==其实是比较它们是否为同一个Class创建的对象
if (o == null || getClass() != o.getClass()) return false;
return true;
}
@Override
public void onSocketConnSuccess(SocketAddress socketAddress) {
// 连接成功关闭重连线程
shutDown();
}
@Override
public void onSocketConnFail(SocketAddress socketAddress, boolean isNeedReconnect) {
// 不需要重连,则关闭重连线程
if (!isNeedReconnect) {
shutDown();
return;
}
connectionFailedTimes++;
// 如果大于最大连接次数并且有备用host,则轮流切换两个host
if (connectionFailedTimes > MAX_CONNECTION_FAILED_TIMES && socketAddress.getBackupAddress() != null) {
connectionFailedTimes = 0; // 归零
SocketAddress backupAddress = socketAddress.getBackupAddress();
SocketAddress nowAddress = new SocketAddress(socketAddress.getIp(), socketAddress.getPort());
backupAddress.setBackupAddress(nowAddress);
if (connectionManager.isConnectViable()) {
connectionManager.switchHost(backupAddress);
// 切换主机地址,重新连接
reconnect();
}
} else {
reconnect();
}
}
@Override
public void onSocketDisconnect(SocketAddress socketAddress, boolean isNeedReconnect) {
// 是否需要重连
if (!isNeedReconnect) {
shutDown();
return;
}
reconnect();
}
@Override
public boolean isReconning() {
return handlerThread != null && handlerThread.isAlive();
}
}

View File

@@ -0,0 +1,58 @@
package com.easysocket.entity;
import com.easysocket.EasySocket;
import com.easysocket.utils.Utils;
import java.io.Serializable;
import java.nio.charset.Charset;
/**
* AuthorAlex
* Date2019/6/1
* Note读到的数据
*/
public class OriginReadData implements Serializable {
/**
* 包头数据
*/
private byte[] headerData;
/**
* 包体数据
*/
private byte[] bodyData;
public byte[] getHeaderData() {
return headerData;
}
public void setHeaderData(byte[] headerData) {
this.headerData = headerData;
}
public byte[] getBodyBytes() {
return bodyData;
}
public void setBodyData(byte[] bodyData) {
this.bodyData = bodyData;
}
/**
* 获取数据body的string
*
* @return
*/
public String getBodyString() {
return new String(getBodyBytes(), Charset.forName(EasySocket.getInstance().getDefOptions().getCharsetName()));
}
/**
* 获取完整的数据,包括包头和包体
*
* @return
*/
public byte[] getOriginDataBytes() {
return Utils.concatBytes(getHeaderData(), getBodyBytes());
}
}

View File

@@ -0,0 +1,54 @@
package com.easysocket.entity;
/**
* AuthorAlex
* Date2019/5/31
* Notesocket主机地址
*/
public class SocketAddress {
/**
* IPV4地址
*/
private String ip;
/**
* 连接服务器端口号
*/
private int port;
/**
* 当此IP地址Ping不通时的备用IP
*/
private SocketAddress backupAddress;
/**
* 获取备用的Ip和端口号
*
* @return 备用的端口号和IP地址
*/
public SocketAddress getBackupAddress() {
return backupAddress;
}
/**
* 设置备用的IP和端口号,可以不设置
*
* @param backupAddress 备用的IP和端口号信息
*/
public void setBackupAddress(SocketAddress backupAddress) {
this.backupAddress = backupAddress;
}
public SocketAddress(String ip, int port){
this.ip =ip;
this.port =port;
}
public String getIp() {
return ip;
}
public int getPort() {
return port;
}
}

View File

@@ -0,0 +1,9 @@
package com.easysocket.entity.basemsg;
/**
* AuthorAlex
* Date2019/12/8
* Note
*/
public interface IResponse {
}

View File

@@ -0,0 +1,11 @@
package com.easysocket.entity.basemsg;
import java.io.Serializable;
/**
* AuthorAlex
* Date2019/6/1
* Note发送数据的接口
*/
public interface ISender extends Serializable {
}

View File

@@ -0,0 +1,13 @@
package com.easysocket.entity.basemsg;
/**
* AuthorAlex
* Date2019/12/7
*/
public abstract class SuperCallbackResponse implements IResponse {
public abstract String getCallbackId();
public abstract void setCallbackId(String callbackId);
}

View File

@@ -0,0 +1,36 @@
package com.easysocket.entity.basemsg;
import com.easysocket.utils.Utils;
/**
* AuthorAlex
* Date2019/10/19
*/
public abstract class SuperCallbackSender extends SuperSender {
private String callbackId;
public SuperCallbackSender() {
generateCallbackId();
}
public String getCallbackId() {
return callbackId;
}
/**
* 根据自己的协议打包消息
*
* @return
*/
public abstract byte[] pack();
/**
* 随机生成一个回调标识 CallbackId在消息发送前执行CallbackId作为消息的唯一标识一起传给服务器服务器反馈
* 当前消息的时候也是携带同样的CallbackId给客户端用以识别
*/
public void generateCallbackId() {
callbackId= Utils.getRandomChar(20);
}
}

View File

@@ -0,0 +1,9 @@
package com.easysocket.entity.basemsg;
/**
* AuthorAlex
* Date2019/10/19
* Note基础消息
*/
public class SuperSender implements ISender {
}

View File

@@ -0,0 +1,12 @@
package com.easysocket.exception;
/**
* AuthorAlex
* Date2019/6/5
* Note初始化异常
*/
public class InitialExeption extends RuntimeException{
public InitialExeption(String s){
super(s);
}
}

View File

@@ -0,0 +1,12 @@
package com.easysocket.exception;
/**
* AuthorAlex
* Date2019/6/5
* Note非空异常
*/
public class NotNullException extends RuntimeException {
public NotNullException(String e) {
super(e);
}
}

View File

@@ -0,0 +1,13 @@
package com.easysocket.exception;
/**
* AuthorAlex
* Date2019/6/5
* Note可恢复socket读数据异常
*/
public class ReadRecoverableExeption extends Exception {
public ReadRecoverableExeption(String s){
super(s);
}
}

View File

@@ -0,0 +1,12 @@
package com.easysocket.exception;
/**
* AuthorMapogo
* Date2020/12/29
* Note不可修复的读取错误
*/
public class ReadUnrecoverableException extends Exception {
public ReadUnrecoverableException(String s) {
super(s);
}
}

View File

@@ -0,0 +1,13 @@
package com.easysocket.exception;
/**
* AuthorAlex
* Date2019/6/4
* Note请求取消异常
*/
public class RequestCancelException extends Exception{
public RequestCancelException(String s){
super(s);
}
}

View File

@@ -0,0 +1,13 @@
package com.easysocket.exception;
/**
* AuthorAlex
* Date2019/6/4
* Note请求超时异常
*/
public class RequestTimeOutException extends Exception{
public RequestTimeOutException(String s){
super(s);
}
}

View File

@@ -0,0 +1,18 @@
package com.easysocket.interfaces.callback;
import com.easysocket.callback.SuperCallBack;
/**
* AuthorAlex
* Date2019/6/5
* Note
*/
public interface ICallBack {
/**
* socket请求回调
* @param callBack
*/
void onCallBack(SuperCallBack callBack);
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2017 zhouyou(478319399@qq.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.easysocket.interfaces.callback;
import android.app.Dialog;
/**
* <p>描述自定义对话框的dialog</p>
*/
public interface IProgressDialog {
Dialog getDialog();
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2017 zhouyou(478319399@qq.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.easysocket.interfaces.callback;
import java.lang.reflect.Type;
/**
* <p>描述:获取类型接口</p>
*/
public interface IType<T> {
Type getType();
Class<?> getGenericityClazz();
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2017 zhouyou(478319399@qq.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.easysocket.interfaces.callback;
/**
* <p>描述:进度框取消监听</p>
*/
public interface ProgressCancelListener {
void onCancelProgress();
}

View File

@@ -0,0 +1,13 @@
package com.easysocket.interfaces.config;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.conn.IConnectionManager;
/**
* AuthorAlex
* Date2019/6/4
* Note
*/
public interface IConnectionSwitchListener {
void onSwitchConnectionInfo(IConnectionManager manager, SocketAddress oldAddress, SocketAddress newAddress);
}

View File

@@ -0,0 +1,20 @@
package com.easysocket.interfaces.config;
import java.nio.ByteOrder;
/**
* 消息数据格式
*/
public interface IMessageProtocol {
/**
* 获取包头的长度
*/
int getHeaderLength();
/**
* 获取数据包体的长度,根据协议这个长度应该写在包头中,在读取数据时用到
*/
int getBodyLength(byte[] header, ByteOrder byteOrder);
}

View File

@@ -0,0 +1,22 @@
package com.easysocket.interfaces.config;
import com.easysocket.config.EasySocketOptions;
/**
* AuthorAlex
* Date2019/6/1
* Note
*/
public interface IOptions<T> {
/**
* 设置配置信息
* @param socketOptions
*/
T setOptions(EasySocketOptions socketOptions);
/**
* 获取配置信息
* @return
*/
EasySocketOptions getOptions();
}

View File

@@ -0,0 +1,65 @@
package com.easysocket.interfaces.conn;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.callback.ICallBack;
import com.easysocket.interfaces.config.IOptions;
import java.io.InputStream;
import java.io.OutputStream;
/**
* AuthorAlex
* Date2019/5/29
* Note连接管理的接口规范
*/
public interface IConnectionManager extends ISubscribeSocketAction, IOptions<IConnectionManager>,ISend, ICallBack {
/**
* 开始连接
*/
void connect();
/**
* 关闭连接
* @param isNeedReconnect 是否需要重连
*/
void disconnect(boolean isNeedReconnect);
/**
* 获取socket连接状态
* @return
*/
int getConnectionStatus();
/**
* 是否可连接的
* @return
*/
boolean isConnectViable();
/**
* 切换host
* @param socketAddress
*/
void switchHost(SocketAddress socketAddress);
/**
* 获取输入流
* @return
*/
InputStream getInputStream();
/**
* 获取输出流
* @return
*/
OutputStream getOutStream();
/**
* 获取心跳管理器
* @return
*/
IHeartManager getHeartManager();
}

View File

@@ -0,0 +1,28 @@
package com.easysocket.interfaces.conn;
import com.easysocket.connection.heartbeat.HeartManager;
/**
* AuthorAlex
* Date2019/12/8
* Note
*/
public interface IHeartManager {
/**
* 开始心跳
* @param clientHeart
*/
void startHeartbeat(byte[] clientHeart, HeartManager.HeartbeatListener listener);
/**
* 停止心跳
*/
void stopHeartbeat();
/**
* 接收到心跳
*/
void onReceiveHeartBeat();
}

View File

@@ -0,0 +1,20 @@
package com.easysocket.interfaces.conn;
/**
* AuthorAlex
* Date2019/6/1
* Note
*/
public interface IReconnListener {
/**
* 关联连接器
* @param iConnectionManager
*/
void attach(IConnectionManager iConnectionManager);
/**
* 分离连接器
*/
void detach();
}

View File

@@ -0,0 +1,25 @@
package com.easysocket.interfaces.conn;
import com.easysocket.entity.basemsg.SuperCallbackSender;
/**
* AuthorAlex
* Date2019/6/5
* Note发送接口
*/
public interface ISend {
/**
* 发送一个有回调的消息
* @param sender
* @return
*/
IConnectionManager upCallbackMessage(SuperCallbackSender sender);
/**
* 发送bytes
* @param bytes
* @return
*/
IConnectionManager upBytes(byte[] bytes);
}

View File

@@ -0,0 +1,38 @@
package com.easysocket.interfaces.conn;
import java.io.Serializable;
/**
* AuthorAlex
* Date2019/6/1
* Notesocket行为分发接口
*/
public interface ISocketActionDispatch {
/**
* 停止分发线程
*/
void stopDispatchThread();
void startDispatchThread();
void dispatchAction(String action);
/**
* socket行为的分发
* @param action
* @param serializable
*/
void dispatchAction(String action, Serializable serializable);
/**
* 订阅socket行为
* @param iSocketActionListener
*/
void subscribe(ISocketActionListener iSocketActionListener);
/**
* 解除socket行为的订阅
* @param iSocketActionListener
*/
void unsubscribe(ISocketActionListener iSocketActionListener);
}

View File

@@ -0,0 +1,52 @@
package com.easysocket.interfaces.conn;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
/**
* AuthorAlex
* Date2019/6/1
* Notesocket行为监听接口
*/
public interface ISocketActionListener {
/**
* socket连接成功
* @param socketAddress
*/
void onSocketConnSuccess(SocketAddress socketAddress);
/**
* socket连接失败
* @param socketAddress
* @param isNeedReconnect 是否需要重连
*/
void onSocketConnFail(SocketAddress socketAddress, boolean isNeedReconnect);
/**
* 断开socket连接
* @param socketAddress
* @param isNeedReconnect 是否需要重连
*/
void onSocketDisconnect(SocketAddress socketAddress, boolean isNeedReconnect);
/**
* socket数据响应
* @param socketAddress
* @param originReadData
*/
void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData);
/**
* socket数据响应
* @param socketAddress
* @param readData
*/
void onSocketResponse(SocketAddress socketAddress, String readData);
/**
* socket数据响应
* @param socketAddress
* @param readData
*/
void onSocketResponse(SocketAddress socketAddress, byte[] readData);
}

View File

@@ -0,0 +1,20 @@
package com.easysocket.interfaces.conn;
/**
* AuthorAlex
* Date2019/6/1
* Note订阅监听socket
*/
public interface ISubscribeSocketAction {
/**
* 注册监听socket的行为
* @param iSocketActionListener
*/
void subscribeSocketAction(ISocketActionListener iSocketActionListener);
/**
* 注销监听socket的行为
* @param iSocketActionListener
*/
void unSubscribeSocketAction(ISocketActionListener iSocketActionListener);
}

View File

@@ -0,0 +1,57 @@
package com.easysocket.interfaces.conn;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
/**
* AuthorAlex
* Date2019/6/4
* Notesocket行为监听的抽象类继承此类可以选择性地重写方法
*/
public abstract class SocketActionListener implements ISocketActionListener{
/**
* socket连接成功
* @param socketAddress
*/
@Override
public void onSocketConnSuccess(SocketAddress socketAddress) {
}
/**
* socket连接失败
* @param socketAddress
* @param isNeedReconnect 是否需要重连
*/
@Override
public void onSocketConnFail(SocketAddress socketAddress, boolean isNeedReconnect) {
}
/**
* 断开socket连接
* @param socketAddress
* @param isNeedReconnect 是否需要重连
*/
@Override
public void onSocketDisconnect(SocketAddress socketAddress, boolean isNeedReconnect) {
}
/**
* socket读数据反馈
* @param socketAddress
* @param originReadData
*/
@Override
public void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData) {
}
@Override
public void onSocketResponse(SocketAddress socketAddress, byte[] readData) {
}
@Override
public void onSocketResponse(SocketAddress socketAddress, String readData) {
}
}

View File

@@ -0,0 +1,27 @@
package com.easysocket.interfaces.io;
/**
* AuthorAlex
* Date2019/6/1
* Note
*/
public interface IIOManager {
/**
* 发送字节流
*
* @param bytes
*/
void sendBytes(byte[] bytes);
/**
* 关闭io管理器
*/
void closeIO();
/**
* 开启io操作
*/
void startIO();
}

View File

@@ -0,0 +1,32 @@
package com.easysocket.interfaces.io;
/**
* AuthorAlex
* Date2019/6/1
* Note
*/
public interface IReader<T> {
/**
* 读数据
*/
void read() throws Exception;
/**
* 打开数据的读取
*/
void openReader();
/**
* 关闭数据的读取
*/
void closeReader();
/**
* 设置参数
* @param t
*/
void setOption(T t);
}

View File

@@ -0,0 +1,38 @@
package com.easysocket.interfaces.io;
import java.io.IOException;
/**
* AuthorAlex
* Date2019/6/1
* Note
*/
public interface IWriter<T> {
/**
* 保存要写的数据
*/
void offer(byte[] sender);
/**
* 写数据
* @param sender
*/
void write(byte[] sender) throws IOException;
/**
* 关闭stream
*/
void closeWriter();
/**
* 开启写数据
*/
void openWriter();
/**
* 设置参数
* @param t
*/
void setOption(T t);
}

View File

@@ -0,0 +1,87 @@
package com.easysocket.utils;
import android.util.Log;
import com.easysocket.EasySocket;
public class LogUtil {
public static final String LOGTAG = "easysocket";
public static boolean debugEnabled = EasySocket.getInstance().getDefOptions().isDebug();
public LogUtil() {
}
private static String getDebugInfo() {
Throwable stack = new Throwable().fillInStackTrace();
StackTraceElement[] trace = stack.getStackTrace();
int n = 2;
return trace[n].getClassName() + " " + trace[n].getMethodName() + "()" + ":" + trace[n].getLineNumber() +
" ";
}
private static String getLogInfoByArray(String[] infos) {
StringBuilder sb = new StringBuilder();
for (String info : infos) {
sb.append(info);
sb.append(" ");
}
return sb.toString();
}
public static void i(String... s) {
if (debugEnabled) {
i(LOGTAG, getDebugInfo() + getLogInfoByArray(s));
}
}
public static void e(Throwable tr) {
if (debugEnabled) {
Log.e(LOGTAG, getDebugInfo() ,tr);
}
}
public static void e(String... s) {
if (debugEnabled) {
e(LOGTAG, getDebugInfo() + getLogInfoByArray(s));
}
}
public static void d(String... s) {
if (debugEnabled) {
d(LOGTAG, getDebugInfo() + getLogInfoByArray(s));
}
}
public static void v(String... s) {
if (debugEnabled) {
v(LOGTAG, getDebugInfo() + getLogInfoByArray(s));
}
}
public static void w(String... s) {
if (debugEnabled) {
w(LOGTAG, getDebugInfo() + getLogInfoByArray(s));
}
}
private static void i(String name, String log) {
System.out.println(name + "" + log);
}
private static void d(String name, String log) {
System.out.println(name + "" + log);
}
private static void v(String name, String log) {
System.out.println(name + "" + log);
}
private static void e(String name, String log) {
System.err.println(name + "" + log);
}
private static void w(String name, String log) {
System.err.println(name + "" + log);
}
}

View File

@@ -0,0 +1,149 @@
package com.easysocket.utils;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.Looper;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Random;
/**
* Created by LXR ON 2018/8/30.
*/
public class Utils {
/**
* 获取泛型参数的类型
*
* @param <T>
* @return
*/
public static <T> Type findGenericityType(Class<T> cls) {
Type genType = cls.getGenericSuperclass(); //返回直接继承的父类(包含泛型参数)类型,如果有泛型T,也要包括进去
//getActualTypeArguments 获取泛型中的实际类型比如Map<Sting,String>中的String类型
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
Type type = params[0]; //泛型的实际类型
Type finalNeedType;
if (type instanceof ParameterizedType) { //二级泛型,这里就处理最多二级吧,形如 A<B<T>>,两个<>
finalNeedType = ((ParameterizedType) type).getActualTypeArguments()[0];
} else { // 一级泛型形如A<T>
finalNeedType = type;
}
//如果泛型类型还是变量类型比如T、V之类的代表没有填写泛型参数
if (finalNeedType instanceof TypeVariable) throw new IllegalStateException("没有填写泛型参数");
return finalNeedType;
}
/**
* 字符串是否为空
*
* @param str
* @return
*/
public static boolean isStringEmpty(String str) {
return str == null || str.trim().length() == 0;
}
/**
* 生成随机字符串
*
* @param length
* @return
*/
public static String getRandomChar(int length) {
char[] chr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
Random random = new Random();
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < length; i++) {
buffer.append(chr[random.nextInt(36)]);
}
return buffer.toString();
}
/**
* 获取handler对象
*
* @param isMainHandler 是否为主线程的handler为false时返回的是当前线程handler
* @return
*/
public static Handler getHandler(boolean isMainHandler) {
Handler handler;
if (isMainHandler) {
handler = new Handler(Looper.getMainLooper());
} else {
Looper.prepare();
handler = new Handler();
}
return handler;
}
/**
* 睡眠多少毫秒
*
* @param milliSecond 毫秒
*/
public static void sleep(long milliSecond) {
try {
Thread.sleep(milliSecond);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 非空检查
*
* @param object
* @param emsg
* @throws
*/
public static void checkNotNull(Object object, String emsg) {
try {
if (object == null) {
throw new Exception(emsg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void throwNotNull(Object object, String emsg) throws Exception {
if (object == null) {
throw new Exception(emsg);
}
}
// 判断是否连接网络
public static boolean isNetConnected(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
return info != null && info.isConnected();
}
/**
* 拼接两个byte[]
*
* @param
* @param
* @return
*/
public static byte[] concatBytes(byte[] bt1, byte[] bt2) {
if (bt1 == null) {
return bt2;
}
if (bt2 == null) {
return bt1;
}
byte[] bt3 = new byte[bt1.length + bt2.length];
System.arraycopy(bt1, 0, bt3, 0, bt1.length);
System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
return bt3;
}
}