早期移動互聯網時代,MIDP 1.0/2.0 設備通過 HTTP 協議與後端 Servlet 交互是主流架構。本文基於 HttpConnection、DataOutputStream/DataInputStream 實現多參數請求、多返回值響應、Keep-Alive 長連接、中文編碼處理的完整通信協議。
採用 長度前綴 + UTF-8 字符串 序列化方式:
dos.writeUTF(param1); dos.writeUTF(param2); ...dis.readUTF(); dis.readUTF(); ... 嚴格按序讀取dos.writeUTF(result1); dos.writeUTF(result2);,客戶端按序 readUTF()優點:無需解析 JSON/XML、解析極快、內存佔用極低,適合 MIDP 設備受限環境。缺點:雙方協議強耦合、無自描述能力、擴展困難。
public class ClientApp extends MIDlet implements CommandListener {
private static final String URL = "https://localhost:8080/examples/servlet/ServletApp";
private TextField tf1, tf2; // 參數輸入框
private Form inputForm, resultForm;
private Command cmdSend, cmdBack;
public void invokeServlet(String url) throws IOException {
HttpConnection hc = null;
DataOutputStream dos = null;
DataInputStream dis = null;
try {
hc = (HttpConnection) Connector.open(url, Connector.READ_WRITE);
// 請求屬性設置
hc.setRequestMethod(HttpConnection.POST);
hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
hc.setRequestProperty("Connection", "Keep-Alive"); // 關鍵:長連接
hc.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.1");
// 發送參數
dos = hc.openDataOutputStream();
dos.writeUTF(tf1.getString());
dos.writeUTF(tf2.getString());
dos.flush(); dos.close(); // 必須關閉輸出流才會真正發送請求
// 接收響應
dis = new DataInputStream(hc.openInputStream());
String r1 = dis.readUTF();
String r2 = dis.readUTF();
// 更新 UI 顯示結果...
} finally {
closeQuietly(dis); closeQuietly(dos); closeQuietly(hc);
}
}
}
| 技術點 | 說明 | 注意事項 |
|---|---|---|
| POST vs GET | POST 用 setRequestMethod(POST) + 請求體發送數據 | GET 參數拼在 URL,長度受限,不適合中文/二進制 |
| Keep-Alive | Connection: Keep-Alive 複用 TCP 連接 | 減少握手開銷,需服務端支持(Tomcat 默認開啟) |
| 流關閉順序 | 先關閉 DataOutputStream 再讀取輸入流 | 不關閉輸出流,請求不會發送,導致死等 |
| 中文編碼 | writeUTF/readUTF 內部使用修改版 UTF-8 | 雙方均用 Data流無需手動編碼,避免 ISO-8859-1 亂碼 |
| 異常處理 | 捕獲 IOException、ConnectionNotFoundException | 網絡不可用、服務端宕機、超時均需友好提示用戶 |
| 線程模型 | 網絡操作必須在子線程,阻塞會凍結 UI | 用 new Thread(runnable).start() 或 MIDP 2.0 Thread |
public class ServletApp extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
DataInputStream dis = new DataInputStream(req.getInputStream());
DataOutputStream dos = new DataOutputStream(resp.getOutputStream());
try {
String p1 = dis.readUTF(); // 對應客戶端第一個 writeUTF
String p2 = dis.readUTF(); // 第二個
System.out.println("收到參數: " + p1 + ", " + p2);
// 業務邏輯處理...
String result1 = "Processed: " + p1;
String result2 = "Processed: " + p2;
// 返回結果
dos.writeUTF(result1);
dos.writeUTF(result2);
dos.flush();
} finally {
dis.close(); dos.close();
}
}
}
webapps/examples/WEB-INF/classes/,配置 web.xml 映射 /servlet/ServletAppRange 頭 + HttpConnection 分段請求ObjectOutputStream 傳遞 Java 對象(需雙方共享類定義、注意 serialVersionUID)HttpConnection + DataInput/OutputStream 是 J2ME 時代最輕量、最高效的客戶端-服務端通信模式。核心要點:POST 請求、UTF 序列化、流關閉順序、Keep-Alive、子線程網絡、異常兜底。雖然現代 Android/iOS 採用 JSON/HTTP+OkHttp/Retrofit,但該協議設計思想(二進制流、零拷貝解析、狀態無關)在物聯網設備、嵌入式模組通信中仍具參考價值。