1. 程式人生 > >自己動手寫網路框架

自己動手寫網路框架

一、概述

最近有個專案,伺服器是用的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();
}

有需要程式碼的可以私信~