2025-02-15

先羅列一小段代碼,這一小段代碼代表瞭通信框架中發送請求的基本方式,讀者可以根據這段代碼,分析整個請求過程:

view plaincopy to clipboardprint?/**
 * 典型使用方式:
 * 
 * StructRequest output = new StructRequest(GameConst.COMM_PRICECOUNT_DATA);//GameConst.COMM_PRICECOUNT_DATA是請求ID,作用有兩個:用於服務器端識別請求,用於UI線程解析數據
 * 
 * output.writeString("");//請求數據
 * 
 * StructRequest output_time = new StructRequest(GameConst.COMM_SERVER_TIME);
 * 
 * output_time.writeInt(0);
 * 
 * StructRequest[] temp = { output, output_time };
 * 
 * Request request = new Request(temp, this.screenId);//依靠Request對象封裝為請求
 * 
 * sendRequest(request);//發送請求{這裡是耦合點,註意,發送請求的時候,程序的控制類[UI和網絡的耦合類]會記錄下請求的屏幕ID,用於解析}
 * 
 * output.cloese();//關閉讀寫
 */ 
/**
 * 典型使用方式:
 *
 * StructRequest output = new StructRequest(GameConst.COMM_PRICECOUNT_DATA);//GameConst.COMM_PRICECOUNT_DATA是請求ID,作用有兩個:用於服務器端識別請求,用於UI線程解析數據
 *
 * output.writeString("");//請求數據
 *
 * StructRequest output_time = new StructRequest(GameConst.COMM_SERVER_TIME);
 *
 * output_time.writeInt(0);
 *
 * StructRequest[] temp = { output, output_time };
 *
 * Request request = new Request(temp, this.screenId);//依靠Request對象封裝為請求
 *
 * sendRequest(request);//發送請求{這裡是耦合點,註意,發送請求的時候,程序的控制類[UI和網絡的耦合類]會記錄下請求的屏幕ID,用於解析}
 *
 * output.cloese();//關閉讀寫
 */
下面羅列StructRequest 類代碼,代碼中有詳細註釋,就不多敘述瞭。

view plaincopy to clipboardprint?package app.http; 
 
import java.io.ByteArrayOutputStream; 
import java.io.DataOutputStream; 
import java.io.IOException; 
import java.util.Vector; 
 
import app.program.Globe; 
 
/**
 * 功能:把各種類型的數據,轉換為字節數組。
 * 
 * 屬於工具類,為網絡連接,本地數據存儲提供從其他數據類型到字節數據類型的轉換。
 * 
 * 註意有些方法中包含瞭私有項目的網絡協議,並沒有刪除。比如writeInts2中writeLength(v[0].length);
 */ 
public class StructRequest { 
    private ByteArrayOutputStream bout; 
 
    private DataOutputStream out; 
 
    private int commID; 
 
    private boolean bTradeCipher; 
 
    /**
     * 默認為非加密通訊
     * 
     * @param commID
     *            int
     */ 
    public StructRequest(int commID) { 
        this(); 
        this.commID = commID; 
        bTradeCipher = false; 
    } 
 
    /**
     * @param commID
     *            int
     * @param bTradeCipher
     *            boolean 表示是否需要加密
     */ 
    public StructRequest(int commID, boolean bTradeCipher) { 
        this(); 
        this.commID = commID; 
        this.bTradeCipher = bTradeCipher; 
    } 
 
    public StructRequest() { 
        bout = new ByteArrayOutputStream(); 
        out = new DataOutputStream(bout); 
    } 
 
    public void writeLength(int v) { 
        writeShort(v); 
    } 
 
    public void writeBoolean(boolean v) { 
        try { 
            out.writeBoolean(v); 
        } catch (Exception ex) { 
            throw new RuntimeException(); 
        } 
    } 
 
    public void writeBooleans(boolean[] v) { 
        writeLength(v.length); 
        for (int i = 0; i < v.length; i++) { 
            writeBoolean(v[i]); 
        } 
    } 
 
    public void writeBooleans2(boolean[][] v) { 
        writeLength(v.length); 
        if (v.length > 0) { 
            writeLength(v[0].length); 
            for (int i = 0; i < v.length; i++) { 
                for (int j = 0; j < v[0].length; j++) { 
                    writeBoolean(v[i][j]); 
                } 
            } 
        } 
    } 
 
    public void writeByte(int v) { 
        try { 
            out.writeByte(v); 
        } catch (Exception ex) { 
            throw new RuntimeException(); 
        } 
    } 
 
    public void writeBytes(int[] v) { 
        writeLength(v.length); 
        for (int i = 0; i < v.length; i++) { 
            writeByte(v[i]); 
        } 
    } 
 
    public void writeBytes2(int[][] v) { 
        writeLength(v.length); 
        if (v.length > 0) { 
            writeLength(v[0].length); 
            for (int i = 0; i < v.length; i++) { 
                for (int j = 0; j < v[0].length; j++) { 
                    writeByte(v[i][j]); 
                } 
            } 
        } 
    } 
 
    public void writeShort(int v) { 
        try { 
            out.write((v >>> 0) & 0xff); 
            out.write((v >>> 8) & 0xff); 
        } catch (Exception ex) { 
            throw new RuntimeException(); 
        } 
    } 
 
    public void writeShorts(int[] v) { 
        writeLength(v.length); 
        for (int i = 0; i < v.length; i++) { 
            writeShort(v[i]); 
        } 
    } 
 
    public void writeShorts2(int[][] v) { 
        writeLength(v.length); 
        if (v.length > 0) { 
            writeLength(v[0].length); 
            for (int i = 0; i < v.length; i++) { 
                for (int j = 0; j < v[0].length; j++) { 
                    writeShort(v[i][j]); 
                } 
            } 
        } 
    } 
 
    public void writeInt(int v) { 
        try { 
            out.write((v >>> 0) & 0xff); 
            out.write((v >>> 8) & 0xff); 
            out.write((v >>> 16) & 0xff); 
            out.write((v >>> 24) & 0xff); 
        } catch (Exception ex) { 
            throw new RuntimeException(); 
        } 
    } 
 
    public void writeInts(int[] v) { 
        writeLength(v.length); 
        for (int i = 0; i < v.length; i++) { 
            writeInt(v[i]); 
        } 
    } 
 
    public void writeInts2(int[][] v) { 
        writeLength(v.length); 
        if (v.length > 0) { 
            writeLength(v[0].length); 
            for (int i = 0; i < v.length; i++) { 
                for (int j = 0; j < v[0].length; j++) { 
                    writeInt(v[i][j]); 
                } 
            } 
        } 
    } 
 
    private int getSize(int limit) { 
        if (limit >= -128 && limit <= 127) { 
            return 1; 
        } 
        if (limit >= -32768 && limit <= 32767) { 
            return 2; 
        } 
        return 4; 
    } 
 
    public void writeNumbers(int[] v, int limit) { 
        int size = getSize(limit); 
        writeByte(size); 
        if (size == 1) { 
            writeBytes(v); 
        } else if (size == 2) { 
            writeShorts(v); 
        } else { 
            writeInts(v); 
        } 
    } 
 
    public void writeNumbers2(int[][] v, int limit) { 
        int size = getSize(limit); 
        writeByte(size); 
        if (size == 1) { 
            writeBytes2(v); 
        } else if (size == 2) { 
            writeShorts2(v); 
        } else { 
            writeInts2(v); 
        } 
    } 
 
    public void writeLong(long v) { 
        try { 
            out.write(((int) v >>> 0) & 0xff); 
            out.write(((int) v >>> 8) & 0xff); 
            out.write(((int) v >>> 16) & 0xff); 
            out.write(((int) v >>> 24) & 0xff); 
            out.write(((int) v >>> 32) & 0xff); 
            out.write(((int) v >>> 40) & 0xff); 
            out.write(((int) v >>> 48) & 0xff); 
            out.write(((int) v >>> 56) & 0xff); 
        } catch (Exception ex) { 
            throw new RuntimeException(); 
        } 
    } 
 
    public void writeStringTrade(String v) { 
        try { 
            byte[] tmp = v.getBytes("UTF-8"); 
            out.write(tmp); 
        } catch (Exception ex1) { 
        } 
    } 
 
    public void writeString(String v) { 
        try { 
            byte[] tmp = v.getBytes("UTF-8"); 
            writeLength(tmp.length); 
            out.write(tmp); 
        } catch (Exception ex1) { 
        } 
 
    } 
 
    public void writeStringArray(String[] v) { 
        for (int i = 0; i < v.length; i++) { 
            writeString(v[i]); 
        } 
    } 
 
    public void writeStrings(String[] v) { 
        writeLength(v.length); 
        for (int i = 0; i < v.length; i++) { 
            writeString(v[i]); 
        } 
    } 
 
    public void writeStrings2(String[][] v) { 
        writeLength(v.length); 
        for (int i = 0; i < v.length; i++) { 
            writeStrings(v[i]); 
        } 
    } 
 
    public void writeByteArray(byte[] v) { 
        writeLength(v.length); 
        for (int i = 0; i < v.length; i++) { 
            writeByte(v[i]); 
        } 
    } 
 
 
    public void writeByteArray2(byte[] v) { 
        for (int i = 0; i < v.length; i++) { 
            writeByte(v[i]); 
        } 
    } 
 
    public int getType() { 
        return commID; 
    } 
 
    /**
     * 此方法可以實現對程序數據的加密
     */ 
    public byte[] getBytes() { 
        if (!bTradeCipher) { 
            return bout.toByteArray(); 
        } else { 
            byte[] data = bout.toByteArray(); 
            for (int i = 0; i < data.length; i++) { 
                data[i] = (byte) (data[i] ^ Globe.key[i % Globe.key.length]); 
            } 
            return data; 
        } 
    } 
 
    public void writeVector(Vector v) { 
        int num = v.size(); 
        writeLength(num); 
        for (int i = 0; i < num; i++) { 
            writeString((String) v.elementAt(i)); 
        } 
    } 
 
    public void cloese() { 
        try { 
            if (out != null) { 
                out.close(); 
            } 
            if (bout != null) { 
                bout.close(); 
            } 
            out = null; 
            bout = null; 
        } catch (IOException ex) { 
        } 
    } 

package app.http;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Vector;

import app.program.Globe;

/**
 * 功能:把各種類型的數據,轉換為字節數組。
 *
 * 屬於工具類,為網絡連接,本地數據存儲提供從其他數據類型到字節數據類型的轉換。
 *
 * 註意有些方法中包含瞭私有項目的網絡協議,並沒有刪除。比如writeInts2中writeLength(v[0].length);
 */
public class StructRequest {
 private ByteArrayOutputStream bout;

 private DataOutputStream out;

 private int commID;

 private boolean bTradeCipher;

 /**
  * 默認為非加密通訊
  *
  * @param commID
  *            int
  */
 public StructRequest(int commID) {
  this();
  this.commID = commID;
  bTradeCipher = false;
 }

 /**
  * @param commID
  *            int
  * @param bTradeCipher
  *            boolean 表示是否需要加密
  */
 public StructRequest(int commID, boolean bTradeCipher) {
  this();
  this.commID = commID;
  this.bTradeCipher = bTradeCipher;
 }

 public StructRequest() {
  bout = new ByteArrayOutputStream();
  out = new DataOutputStream(bout);
 }

 public void writeLength(int v) {
  writeShort(v);
 }

 public void writeBoolean(boolean v) {
  try {
   out.writeBoolean(v);
  } catch (Exception ex) {
   throw new RuntimeException();
  }
 }

 public void writeBooleans(boolean[] v) {
  writeLength(v.length);
  for (int i = 0; i < v.length; i++) {
   writeBoolean(v[i]);
  }
 }

 public void writeBooleans2(boolean[][] v) {
  writeLength(v.length);
  if (v.length > 0) {
   writeLength(v[0].length);
   for (int i = 0; i < v.length; i++) {
    for (int j = 0; j < v[0].length; j++) {
     writeBoolean(v[i][j]);
    }
   }
  }
 }

 public void writeByte(int v) {
  try {
   out.writeByte(v);
  } catch (Exception ex) {
   throw new RuntimeException();
  }
 }

 public void writeBytes(int[] v) {
  writeLength(v.length);
  for (int i = 0; i < v.length; i++) {
   writeByte(v[i]);
  }
 }

 public void writeBytes2(int[][] v) {
  writeLength(v.length);
  if (v.length > 0) {
   writeLength(v[0].length);
   for (int i = 0; i < v.length; i++) {
    for (int j = 0; j < v[0].length; j++) {
     writeByte(v[i][j]);
    }
   }
  }
 }

 public void writeShort(int v) {
  try {
   out.write((v >>> 0) & 0xff);
   out.write((v >>> 8) & 0xff);
  } catch (Exception ex) {
   throw new RuntimeException();
  }
 }

 public void writeShorts(int[] v) {
  writeLength(v.length);
  for (int i = 0; i < v.length; i++) {
   writeShort(v[i]);
  }
 }

 public void writeShorts2(int[][] v) {
  writeLength(v.length);
  if (v.length > 0) {
   writeLength(v[0].length);
   for (int i = 0; i < v.length; i++) {
    for (int j = 0; j < v[0].length; j++) {
     writeShort(v[i][j]);
    }
   }
  }
 }

 public void writeInt(int v) {
  try {
   out.write((v >>> 0) & 0xff);
   out.write((v >>> 8) & 0xff);
   out.write((v >>> 16) & 0xff);
   out.write((v >>> 24) & 0xff);
  } catch (Exception ex) {
   throw new RuntimeException();
  }
 }

 public void writeInts(int[] v) {
  writeLength(v.length);
  for (int i = 0; i < v.length; i++) {
   writeInt(v[i]);
  }
 }

 public void writeInts2(int[][] v) {
  writeLength(v.length);
  if (v.length > 0) {
   writeLength(v[0].length);
   for (int i = 0; i < v.length; i++) {
    for (int j = 0; j < v[0].length; j++) {
     writeInt(v[i][j]);
    }
   }
  }
 }

 private int getSize(int limit) {
  if (limit >= -128 && limit <= 127) {
   return 1;
  }
  if (limit >= -32768 && limit <= 32767) {
   return 2;
  }
  return 4;
 }

 public void writeNumbers(int[] v, int limit) {
  int size = getSize(limit);
  writeByte(size);
  if (size == 1) {
   writeBytes(v);
  } else if (size == 2) {
   writeShorts(v);
  } else {
   writeInts(v);
  }
 }

 public void writeNumbers2(int[][] v, int limit) {
  int size = getSize(limit);
  writeByte(size);
  if (size == 1) {
   writeBytes2(v);
  } else if (size == 2) {
   writeShorts2(v);
  } else {
   writeInts2(v);
  }
 }

 public void writeLong(long v) {
  try {
   out.write(((int) v >>> 0) & 0xff);
   out.write(((int) v >>> 8) & 0xff);
   out.write(((int) v >>> 16) & 0xff);
   out.write(((int) v >>> 24) & 0xff);
   out.write(((int) v >>> 32) & 0xff);
   out.write(((int) v >>> 40) & 0xff);
   out.write(((int) v >>> 48) & 0xff);
   out.write(((int) v >>> 56) & 0xff);
  } catch (Exception ex) {
   throw new RuntimeException();
  }
 }

 public void writeStringTrade(String v) {
  try {
   byte[] tmp = v.getBytes("UTF-8");
   out.write(tmp);
  } catch (Exception ex1) {
  }
 }

 public void writeString(String v) {
  try {
   byte[] tmp = v.getBytes("UTF-8");
   writeLength(tmp.length);
   out.write(tmp);
  } catch (Exception ex1) {
  }

 }

 public void writeStringArray(String[] v) {
  for (int i = 0; i < v.length; i++) {
   writeString(v[i]);
  }
 }

 public void writeStrings(String[] v) {
  writeLength(v.length);
  for (int i = 0; i < v.length; i++) {
   writeString(v[i]);
  }
 }

 public void writeStrings2(String[][] v) {
  writeLength(v.length);
  for (int i = 0; i < v.length; i++) {
   writeStrings(v[i]);
  }
 }

 public void writeByteArray(byte[] v) {
  writeLength(v.length);
  for (int i = 0; i < v.length; i++) {
   writeByte(v[i]);
  }
 }


 public void writeByteArray2(byte[] v) {
  for (int i = 0; i < v.length; i++) {
   writeByte(v[i]);
  }
 }

 public int getType() {
  return commID;
 }

 /**
  * 此方法可以實現對程序數據的加密
  */
 public byte[] getBytes() {
  if (!bTradeCipher) {
   return bout.toByteArray();
  } else {
   byte[] data = bout.toByteArray();
   for (int i = 0; i < data.length; i++) {
    data[i] = (byte) (data[i] ^ Globe.key[i % Globe.key.length]);
   }
   return data;
  }
 }

 public void writeVector(Vector v) {
  int num = v.size();
  writeLength(num);
  for (int i = 0; i < num; i++) {
   writeString((String) v.elementAt(i));
  }
 }

 public void cloese() {
  try {
   if (out != null) {
    out.close();
   }
   if (bout != null) {
    bout.close();
   }
   out = null;
   bout = null;
  } catch (IOException ex) {
  }
 }
}
 
下面羅列Request的代碼,註意裡面的請求方式分為兩種,第一種是一次隻請求一種數據,第二種是一次請求多種數據(這種方式有效的減少瞭請求的次數):

view plaincopy to clipboardprint?package app.http; 
 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
 
 
/** 
 * 功能: 
 *  
 * 把需要發送的內容,再次經過私有協議封裝,合並為一個Request對象,並且給這個對象一個和屏幕一致的ID,用於接收和解析數據 
 *  
 * 其他參照StructRequest 
 */ 
public class Request { 
    private byte[] content = null; 
    private int screenId = 0; 
    private static final byte START_FLAG = (byte) '{'; 
    private static final byte END_FLAG = (byte) '}'; 
    private static final byte OTHER_FLAG = (byte) ':'; 
 
    private boolean bTrade = false; 
 
    /** 
     * 單個通訊 
     *  
     * @param output 
     *            StructOutput 
     */ 
    public Request(StructRequest output, int screeID) { 
        screenId = screeID; 
        ByteArrayOutputStream out = new ByteArrayOutputStream(); 
        try { 
            out.write(START_FLAG); // 標識符 
            out.write(output.getType() & 0xFF); 
            out.write((output.getType() >>> 8) & 0xFF); 
            out.write(0); 
            out.write(0); 
            out.write(output.getBytes().length & 0xFF); 
            out.write((output.getBytes().length >>> 8) & 0xFF); 
            out.write(output.getBytes()); 
            out.write(END_FLAG); // 校驗符 
        } catch (Exception ex) { 
        } 
 
        content = out.toByteArray(); 
        try { 
            out.close(); 
        } catch (IOException ex1) { 
        } 
        out = null; 
    } 
 
    public Request(int screeID) { 
        screenId = screeID; 
        ByteArrayOutputStream out = new ByteArrayOutputStream(); 
        try { 
            out.write(START_FLAG); // 標識符 
            out.write(0); 
            out.write(0); 
            out.write(0); 
            out.write(0); 
            out.write(0); 
            out.write(0); 
            out.write(END_FLAG); // 校驗符 
        } catch (Exception ex) { 
        } 
 
        content = out.toByteArray(); 
        try { 
            out.close(); 
        } catch (IOException ex1) { 
        } 
        out = null; 
    } 
 
    /** 
     * 多個通訊 
     *  
     * @param output 
     *            StructOutput[] 
     */ 
    public Request(StructRequest[] output, int screeID) { 
        screenId = screeID; 
        ByteArrayOutputStream out = new ByteArrayOutputStream(); 
        try { 
            out.write(START_FLAG); // 標識符 
            for (int i = 0; i < output.length; i++) { 
                out.write(output[i].getType() & 0xFF); 
                out.write((output[i].getType() >>> 8) & 0xFF); 
                out.write(0); 
                out.write(0); 
                out.write(output[i].getBytes().length & 0xFF); 
                out.write((output[i].getBytes().length >>> 8) & 0xFF); 
                out.write(output[i].getBytes()); 
                if (i < output.length – 1) { 
                    out.write(OTHER_FLAG); 
                } 
            } 
            out.write(END_FLAG); // 校驗符 
        } catch (Exception ex) { 
        } 
 
        content = out.toByteArray(); 
 
        try { 
            out.close(); 
        } catch (IOException ex1) { 
        } 
        out = null; 
    } 
 
    public int getScreenId() { 
        return screenId; 
    } 
 
    public byte[] getContent() { 
        return content; 
    } 
 
    public void sedIsTrade(boolean trade) { 
        this.bTrade = trade; 
    } 
 
    public boolean getIsTrade() { 
        return this.bTrade; 
    } 
 

package app.http;

import java.io.ByteArrayOutputStream;
import java.io.IOException;


/**
 * 功能:
 *
 * 把需要發送的內容,再次經過私有協議封裝,合並為一個Request對象,並且給這個對象一個和屏幕一致的ID,用於接收和解析數據
 *
 * 其他參照StructRequest
 */
public class Request {
 private byte[] content = null;
 private int screenId = 0;
 private static final byte START_FLAG = (byte) '{';
 private static final byte END_FLAG = (byte) '}';
 private static final byte OTHER_FLAG = (byte) ':';

 private boolean bTrade = false;

 /**
  * 單個通訊
  *
  * @param output
  *            StructOutput
  */
 public Request(StructRequest output, int screeID) {
  screenId = screeID;
  ByteArrayOutputStream out = new ByteArrayOutputStream();
  try {
   out.write(START_FLAG); // 標識符
   out.write(output.getType() & 0xFF);
   out.write((output.getType() >>> 8) & 0xFF);
   out.write(0);
   out.write(0);
   out.write(output.getBytes().length & 0xFF);
   out.write((output.getBytes().length >>> 8) & 0xFF);
   out.write(output.getBytes());
   out.write(END_FLAG); // 校驗符
  } catch (Exception ex) {
  }

  content = out.toByteArray();
  try {
   out.close();
  } catch (IOException ex1) {
  }
  out = null;
 }

 public Request(int screeID) {
  screenId = screeID;
  ByteArrayOutputStream out = new ByteArrayOutputStream();
  try {
   out.write(START_FLAG); // 標識符
   out.write(0);
   out.write(0);
   out.write(0);
   out.write(0);
   out.write(0);
   out.write(0);
   out.write(END_FLAG); // 校驗符
  } catch (Exception ex) {
  }

  content = out.toByteArray();
  try {
   out.close();
  } catch (IOException ex1) {
  }
  out = null;
 }

 /**
  * 多個通訊
  *
  * @param output
  *            StructOutput[]
  */
 public Request(StructRequest[] output, int screeID) {
  screenId = screeID;
  ByteArrayOutputStream out = new ByteArrayOutputStream();
  try {
   out.write(START_FLAG); // 標識符
   for (int i = 0; i < output.length; i++) {
    out.write(output[i].getType() & 0xFF);
    out.write((output[i].getType() >>> 8) & 0xFF);
    out.write(0);
    out.write(0);
    out.write(output[i].getBytes().length & 0xFF);
    out.write((output[i].getBytes().length >>> 8) & 0xFF);
    out.write(output[i].getBytes());
    if (i < output.length – 1) {
     out.write(OTHER_FLAG);
    }
   }
   out.write(END_FLAG); // 校驗符
  } catch (Exception ex) {
  }

  content = out.toByteArray();

  try {
   out.close();
  } catch (IOException ex1) {
  }
  out = null;
 }

 public int getScreenId() {
  return screenId;
 }

 public byte[] getContent() {
  return content;
 }

 public void sedIsTrade(boolean trade) {
  this.bTrade = trade;
 }

 public boolean getIsTrade() {
  return this.bTrade;
 }

}
 

補充說明:在通信的時候,有兩種ID,首先是屏幕ID(本文第一段代碼中的this.screenId),這個ID用來確定請求的屏幕,以便請求結束以後,由這個屏幕來解析響應。其次是請求ID(本文第一段代碼中的GameConst.COMM_PRICECOUNT_DATA)。

 

為瞭便於讀者理解,下面一段代碼展示典型的響應解析方式:

view plaincopy to clipboardprint?public void httpCompleted(Response resp) { 
        byte[] tmp = resp.getData(GameConst.COMM_DATA);//這裡就根據請求ID來解析響應  
 
        if (tmp != null) { 
 


public void httpCompleted(Response resp) {
  byte[] tmp = resp.getData(GameConst.COMM_DATA);//這裡就根據請求ID來解析響應

  if (tmp != null) {

}
}

下一篇講解請求的發送和響應的接收。

 作者“馮小衛”

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *