一、概述
最近有个项目,服务器是用的Socket通信,由于是合作开发项目,负责界面的同事,不太想关注具体的业务部分逻辑,直接获取到数据区组织界面就可以了。但是基于socket通信,很难做到这么简洁,想到之前使用过的http,何不按照http模式,简单实现一个易用的网络框架呢?有了想法就要付诸实践。简单流程:
二、框架涉及到类:
1、Request类,定义了请求命令参数,url地址,请求类型,是否需要缓存数据,请求的优先级。
2、ITask类,接口类,定义如下:
abstract public class Request {
private String url = "127.0.0.0";
private int port = 8080;
public String url() {
return url;
}
public int port() {
return port;
}
public boolean isDownload() {
return false;
}
public String ackFunc() {
return getProtocol().getFunc() + Constants.RSP_ACK;
}
public String dataFunc() {
return getProtocol().getFunc() + Constants.RSP_DATA;
}
public String downloadFilepath() {
return "";
}
public String getSendContent() {
if (getProtocol() != null) {
String jsonStr = Utils.toJson(getProtocol());
try {
return Constants.HEADER_PREFIX + Utils.fillZeroString(jsonStr.getBytes("gb2312").length) + Constants.HEADER_SUFFXI + jsonStr;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return "";
}
protected abstract Protocol getProtocol();
}
public class Response {
public Request request;
public boolean isOK;
public Protocol protocol;
public File downloadFile;
public ERRORCODE errorCode = NOERROR;
public enum ERRORCODE {
NOERROR,
NOCONNECT,
NODATA,
NOTFOUNDPARSER,
DOWNLOADFAIL,
SENDREQUESTFAIL,
}
}
public interface ITask extends Cloneable {
Request request();
Response execute() throws IOException;
void enqueue(Callback responseCallback);
void enqueue();
void cancel();
boolean isExecuted();
boolean isCanceled();
ITask clone();
void sendRequest(final String content) throws IOException;
interface Factory {
ITask newCall(Request request);
}
}
/**
* 进度控制接口, updateProgress
* Created by Jacky on 2017/7/4.
*/
public interface ProgressHandler {
/**
* @param total
* @param current
* @param downloadFile
* @return continue
*/
boolean updateProgress(long total, long current, File downloadFile);
}
3、RealTask,实现ITask接口,具体执行socket write很read操作及回调Callback。
4、Response类,socket数据应答类,保存数据头信息就数据体,以及对应的Request
5、Dispatcher,任务分发器类,接收用户请求,并将请求添加进队列,由ExecutorService控制执行RealTask。可以根据任务的优先级进行执行。
6、SocketClient实现了ITask.Factory,根据请求来实例一个请求任务。实例Dispatcher,创建Socket对象。设置socket状态超时时间。
7、Header,固定格式的数据头信息,提取有效信息,解析数据body。
8、Callback接口
public interface Callback {
void onFailure(Response response, IOException E);
void onResponse(final Response response) throws IOException;
void onParser(final BaseObject object);
public interface ProgressCallback extends Callback {
void onLoading(final DownloadProgress progress);
void onFinished(final File result);
}
public static class CancelledException extends RuntimeException {
public CancelledException(String detailMessage) {
super(detailMessage);
}
}
}
9、解析数据接口类:
public abstract class IParser<T> {
abstract public IParser<T> newInstance();
abstract public BaseObject onParser(final String jsonBuffer);
}
public final class ParserFactory {
private ParserFactory() {
}
/**
* key: parserType
*/
private static final HashMap<String, IParser> parserHashMap = new HashMap<String, IParser>();
static {
parserHashMap.put(Constants.DEVICES_STATE, new DeviceStateParser());
parserHashMap.put(Constants.HISTORY_FILELIST, new HistoryFileParser());
}
public static IParser<?> getParser(final String key) {
IParser<?> result = parserHashMap.get(key);
return result;
}
public static <T> void registerParser(String key, IParser<T> parser) {
parserHashMap.put(key, parser);
}
}
public class WeChatContactsParser extends IParser<String[]>{
@Override
public IParser<String[]> newInstance() {
return new WeChatContactsParser();
}
@Override
public BaseObject onParser(String jsonBuffer) {
if (jsonBuffer != null) {
WeChatContacts contacts = new WeChatContacts();
String[] list = jsonBuffer.split("\r\n");
if (list != null) {
if (list.length > 0) {
for (int i = 0; i < list.length; i ++) {
String data = list[i];
if (data.trim().length() > 0) {
contacts.getWeChatContacts().add(data);
}
}
if (contacts.getWeChatContacts().size() > 0) {
EventBus.getDefault().post(contacts);
}
}
return contacts;
}
}
return null;
}
}
根据具体的请求类型创建各自的解析数据类,将解析数据已Object返回。
三、总结
上述框架类似Http的框架机制,但是没有Http的get、post等请求方法。但是可以实现同步还是异步方式。框架里用到了Builder以及Factory设计模式。
四、代码调用示例:
private void testSocket() {
final Request request = new Request.Builder()
.url("104.236.162.42")
.port(8080)
.packet("test cmd")
.isCache(true)
.build();
ITask task = Application.getSocketClient().newTask(request);
task.enqueue(new Callback() {
@Override
public void onFailure(Response response, IOException E) {
}
@Override
public void onResponse(Response response,IOException E) throws IOException {
//注册解析器
ParserFactory.newParser(Constants.REQUEST_TYPE.GET_WECHATS).parser(response.toString().getBytes());
}
});
//如果想取消网络请求可以调用
task.cancel();
}
有需要代码的可以私信~