Java實現客戶端與服務器端的通信


客戶端與服務器端交互數據需要進行通信,本文介紹安卓客戶端是如何與服務器端進行通信的,包括客戶端連接服務器端、客戶端向服務器端發送請求、將請求信息封裝成請求單元、將請求單元存放到隊列、從隊列中獲取請求單元並執行請求。主要的步驟為:”客戶端配置請求服務器的ip地址”、“”客戶端向服務器端發送請求”、“將一個請求封裝成請求單元HttpRequestUnit”、“將請求單元放到一個隊列中,開啟一個線程執行隊列中的請求”、“HttpRequestManager類負責緩存和獲取HttpRequestThread對象”。

1、客戶端配置請求服務器的ip地址。

設置服務器的IP地址,如果是在自己的電腦運行服務器項目,那就設置成電腦的ip地址,然后客戶端和電腦要連接同一個網絡,確保在同一局域網。

(1)打開cmd命令行窗口,輸入ipconfig命令查看電腦的本機ip地址。

CMD命令ipconfig查IP

(2)在Configuration類配置服務器ip地址。

public final class Configuration {
    public static final String APP_Config_Key_env = "env";

    public static final String SERVER_IP_DEV = "https://dev.wx.bxit.vip/";
    public static final String SERVER_IP_SIT = "https://sit.wx.bxit.vip/";
    public static final String SERVER_IP_UAT = "https://uat.wx.bxit.vip/";
    public static final String SERVER_IP_PRODUCTION = "https://account.prosalesbox.cn/";

    public static String HTTP_IP = "http://192.168.123.144/";//運行Pos_Local測試時,要確保與Pos在同一局域網;搞清楚NBR的IP是多少,並填寫在這里

2、客戶端向服務器端發送請求。

(1)創建請求體RequestBody對象。

RequestBody body = new FormBody.Builder()
        .add(staff.field.getFIELD_NAME_phone(), staff.getPhone())
        .build();

(2)創建Request對象。

Request request = new Request.Builder()
        .url(Configuration.HTTP_IP + "staff/getTokenEx.bx")
        .addHeader(BaseHttpBO.COOKIE, GlobalController.getInstance().getSessionID())
        .post(body)
        .build();

(3)發送請求。

httpEvent.setStatus(BaseEvent.EnumEventStatus.EES_Http_ToDo);
HttpRequestUnit hru1 = new StaffGetToken();
hru1.setRequest(request);
hru1.setTimeout(TIME_OUT);
hru1.setbPostEventToUI(true);
hru1.setEvent(httpEvent);
HttpRequestManager.getCache(HttpRequestManager.EnumDomainType.EDT_Communication).pushHttpRequest(hru1);

3、將一個請求封裝成請求單元HttpRequestUnit。

HttpRequestUnit定義為一個請求單元,它實現了okhttp3.Call接口,實現了請求成功和請求失敗的回調方法onResponse和onFailure:

public abstract class HttpRequestUnit implements Callback 

(1)     請求成功后執行onResponse方法。

獲取到服務器返回的數據,做下一步處理:

@Override
public void onResponse(Call call, Response response) throws IOException {
    log.info("請求后返回的response:" + response);
    dateEnd = new Date(System.currentTimeMillis() + NtpHttpBO.TimeDifference);
    if (isTimeout(call)) {
        event.setLastErrorCode(ErrorInfo.EnumErrorCode.EC_Timeout);
        return;
    }
    log.info(" Http onResponse,收到服務器的響應");
    if (NtpHttpBO.bForNtpOnly) {// 在同步的時候設置POS接收到答復的時間,用於POS機與服務器同步時間
        event.setData(new Date(System.currentTimeMillis() + NtpHttpBO.TimeDifference).getTime());
        NtpHttpBO.bForNtpOnly = false;
    }
    event.setLastErrorCode(ErrorInfo.EnumErrorCode.EC_NoError);
    if (bPostEventToUI) {
        event.setRequestType(getEnumRequestType());
        event.setResponseData(response.body().string());
        event.setResponse(response);
        //...設置Event狀態???
        EventBus.getDefault().post(event);
    }
}

(2)請求失敗后執行onFailure方法。

@Override
public void onFailure(Call call, IOException e) {
    this.event.setEventProcessed(true); //終止UI層的等待
    //...
    log.info(" Http onFailure,向服務器發送請求失敗。異常信息:" + e.getMessage());
    dateEnd = new Date(System.currentTimeMillis() + NtpHttpBO.TimeDifference); //用於計算超時
    if (isTimeout(call)) {
        event.setLastErrorCode(ErrorInfo.EnumErrorCode.EC_Timeout);
    } else {
        event.setLastErrorCode(ErrorInfo.EnumErrorCode.EC_OtherError);
    }
    this.event.setLastErrorMessage(BaseHttpBO.ERROR_MSG_Network);
    //
    GlobalController.getInstance().setSessionID(null);
    //
    EventBus.getDefault().post(event);
}

4、將請求單元放到一個隊列中,開啟一個線程執行隊列中的請求。

HttpRequestThread 繼承了 Thread,負責將一個個HttpRequestUnit放到隊列當中,並且開啟一個線程,不停的從隊列中獲取HttpRequestUnit,執行請求:

public class HttpRequestThread extends Thread {

protected Queue<HttpRequestUnit> queue;

(1)將請求單元HttpRequestUnit放到隊列queue中。

public void pushHttpRequest(HttpRequestUnit hu) {
    if (hu != null) {
        lock.writeLock().lock();
        queue.offer(hu);
        lock.writeLock().unlock();
    }
    synchronized (this) {
        notify();
    }
}

(2)啟動線程的run方法,執行doTask()方法。

@Override
public void run() {
    while (atomicInteger.get() != SIGNAL_ThreadExit) {
        lock.writeLock().lock();
        doTask();
        lock.writeLock().unlock();
        synchronized (this) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    log.info("線程:" + this.getName() + "已經退出");
}

(3)doTask方法從隊列中獲取請求單元HttpRequestUnit,並交給okhttp3.OkHttpClient對象執行請求。

protected void doTask() {
    while (!queue.isEmpty()) {
        lock.writeLock().lock();
        HttpRequestUnit hu = queue.poll();
        if (hu == null) {
            lock.writeLock().unlock();
            break;
        }
        hu.setDateStart(new Date(System.currentTimeMillis() + NtpHttpBO.TimeDifference));
        GlobalController.client.newCall(hu.getRequest()).enqueue(hu);
        lock.writeLock().unlock();
    }
}

(4)client為okhttp3.OkHttpClient對象。

//設置OKHttp的超時時間
public static OkHttpClient client = new OkHttpClient.Builder()
        .connectTimeout(HTTP_REQ_Timeout, TimeUnit.SECONDS)
        .readTimeout(HTTP_REQ_Timeout, TimeUnit.SECONDS)
        .writeTimeout(HTTP_REQ_Timeout, TimeUnit.SECONDS)
        .build();
5、HttpRequestManager類負責緩存和獲取HttpRequestThread對象。
public class HttpRequestManager {
    public enum EnumDomainType {
        EDT_Communication("EDT_Communication", 0), //
        EDT_Authentication("EDT_Authentication", 1);
	……

private static HashMap<EnumDomainType, HttpRequestThread> list = new HashMap<EnumDomainType, HttpRequestThread>();

public static void register(EnumDomainType ect, HttpRequestThread bc) {
    list.put(ect, bc);
}

public static HttpRequestThread getCache(EnumDomainType ect) {
    return list.get(ect);
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM