自己動手寫網路框架
阿新 • • 發佈:2019-02-19
一、概述
最近有個專案,伺服器是用的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(); }
有需要程式碼的可以私信~