日志 教程
当前位置: 教程  >  游戏开发  >  手机游戏开发  >  正文

j2me最佳联网方案终结版

作者:郭同学 发表于 2011/9/6 23:02:27     评论(0)     阅读(4773)     
(1) .由于无线设备所能支持的网络协议非常有限,仅限于HTTP,Socket,UDP等几种协议,不同的厂家可能还支持其他网络协议,但是,MIDP 无线论坛[http://www.j2me.com.cn/bbs] 
1.0规范规定,HTTP协议是必须实现的协议,而其他协议的实现都是可选的。因此,为了能在不同类型的手机上移植,我们尽量采用HTTP作为网络连接的首选协议,这样还能重用服务器端的代码。但是,由于HTTP是一个基于文本的效率较低的协议,因此,必须仔细考虑手机和服务器端的通信内容,尽可能地提高效率。
无线论坛[http://www.j2me.com.cn/bbs] 
  对于MIDP应用程序,应当尽量做到:
无线论坛[http://www.j2me.com.cn/bbs] 
  1.发送请求时,附加一个User-Agent头,传入MIDP和自身版本号,以便服务器能识别此请求来自MIDP应用程序,并且根据版本号发送相应的相应。
无线论坛[http://www.j2me.com.cn/bbs] 
无线论坛[http://www.j2me.com.cn/bbs] 
  2.连接服务器时,显示一个下载进度条使用户能看到下载进度,并能随时中断连接。
无线论坛[http://www.j2me.com.cn/bbs] 
无线论坛[http://www.j2me.com.cn/bbs] 
  3.由于无线网络连接速度还很慢,因此有必要将某些数据缓存起来,可以存储在内存中,也可以放到RMS中。
无线论坛[http://www.j2me.com.cn/bbs] 
  对于服务器端而言,其输出响应应当尽量做到:
无线论坛[http://www.j2me.com.cn/bbs] 
  1. 
无线论坛[http://www.j2me.com.cn/bbs] 
明确设置Content-Length字段,以便MIDP应用程序能读取HTTP头并判断自身是否有能力处理此长度的数据,如果不能,可以直接关闭连接而不必继续读取HTTP正文。
无线论坛[http://www.j2me.com.cn/bbs] 
无线论坛[http://www.j2me.com.cn/bbs] 
  2. 
无线论坛[http://www.j2me.com.cn/bbs] 
服务器不应当发送HTML内容,因为MIDP应用程序很难解析HTML,XML虽然能够解析,但是耗费CPU和内存资源,因此,应当发送紧凑的二进制内容,用DataOutputStream直接写入并设置Content-Type为application/octet-stream。
无线论坛[http://www.j2me.com.cn/bbs] 
无线论坛[http://www.j2me.com.cn/bbs] 
  3. 尽量不要重定向URL,这样会导致MIDP应用程序再次连接服务器,增加了用户的等待时间和网络流量。
无线论坛[http://www.j2me.com.cn/bbs] 
无线论坛[http://www.j2me.com.cn/bbs] 
  4. 
无线论坛[http://www.j2me.com.cn/bbs] 
如果发生异常,例如请求的资源未找到,或者身份验证失败,通常,服务器会向浏览器发送一个显示出错的页面,可能还包括一个用户登录的Form,但是,向MIDP发送错误页面毫无意义,应当直接发送一个404或401错误,这样MIDP应用程序就可以直接读取HTTP头的响应码获取错误信息而不必继续读取相应内容。
无线论坛[http://www.j2me.com.cn/bbs] 
无线论坛[http://www.j2me.com.cn/bbs] 
  5. 
无线论坛[http://www.j2me.com.cn/bbs] 
由于服务器的计算能力远远超过手机客户端,因此,针对不同客户端版本发送不同响应的任务应该在服务器端完成。例如,根据客户端传送的User-Agent头确定客户端版本。这样,低版本的客户端不必升级也能继续使用。
无线论坛[http://www.j2me.com.cn/bbs] 
  MIDP的联网框架定义了多种协议的网络连接,但是每个厂商都必须实现HTTP连接,在MIDP 
无线论坛[http://www.j2me.com.cn/bbs] 
2.0中还增加了必须实现的HTTPS连接。因此,要保证MIDP应用程序能在不同厂商的手机平台上移植,最好只使用HTTP连接。虽然HTTP是一个基于文本的效率较低的协议,但是由于使用特别广泛,大多数服务器应用的前端都是基于HTTP的Web页面,因此能最大限度地复用服务器端的代码。只要控制好缓存,仍然有不错的速度。
无线论坛[http://www.j2me.com.cn/bbs] 
  SUN的MIDP库提供了javax.microediton.io包,能非常容易地实现HTTP连接。但是要注意,由于网络有很大的延时,必须把联网操作放入一个单独的线程中,以避免主线程阻塞导致用户界面停止响应。事实上,MIDP运行环境根本就不允许在主线程中操作网络连接。因此,我们必须实现一个灵活的HTTP联网模块,能让用户非常直观地看到当前上传和下载的进度,并且能够随时取消连接。
无线论坛[http://www.j2me.com.cn/bbs] 
  一个完整的HTTP连接为:用户通过某个命令发起连接请求,然后系统给出一个等待屏幕提示正在连接,当连接正常结束后,前进到下一个屏幕并处理下载的数据。如果连接过程出现异常,将给用户提示并返回到前一个屏幕。用户在等待过程中能够随时取消并返回前一个屏幕。
无线论坛[http://www.j2me.com.cn/bbs] 
  我们设计一个HttpThread线程类负责在后台连接服务器,HttpListener接口实现Observer(观察者)模式,以便HttpThread能提示观察者下载开始、下载结束、更新进度条等。HttpListener接口如下:
无线论坛[http://www.j2me.com.cn/bbs] 
public interface HttpListener {
无线论坛[http://www.j2me.com.cn/bbs] 
  void onSetSize(int size);
无线论坛[http://www.j2me.com.cn/bbs] 
  void onFinish(byte[] data, int size);
无线论坛[http://www.j2me.com.cn/bbs] 
  void onProgress(int percent);
无线论坛[http://www.j2me.com.cn/bbs] 
  void onError(int code, String message);
无线论坛[http://www.j2me.com.cn/bbs] 
}
无线论坛[http://www.j2me.com.cn/bbs] 
  实现HttpListener接口的是继承自Form的一个HttpWaitUI屏幕,它显示一个进度条和一些提示信息,并允许用户随时中断连接:
无线论坛[http://www.j2me.com.cn/bbs] 
public class HttpWaitUI extends Form implements CommandListener, HttpListener {
无线论坛[http://www.j2me.com.cn/bbs] 
  private Gauge gauge;
无线论坛[http://www.j2me.com.cn/bbs] 
  private Command cancel;
无线论坛[http://www.j2me.com.cn/bbs] 
  private HttpThread downloader;
无线论坛[http://www.j2me.com.cn/bbs] 
  private Displayable displayable;
无线论坛[http://www.j2me.com.cn/bbs] 
  public HttpWaitUI(String url, Displayable displayable) {
无线论坛[http://www.j2me.com.cn/bbs] 
    super("Connecting");
无线论坛[http://www.j2me.com.cn/bbs] 
    this.gauge = new Gauge("Progress", false, 100, 0);
无线论坛[http://www.j2me.com.cn/bbs] 
    this.cancel = new Command("Cancel", Command.CANCEL, 0);
无线论坛[http://www.j2me.com.cn/bbs] 
    append(gauge);
无线论坛[http://www.j2me.com.cn/bbs] 
    addCommand(cancel);
无线论坛[http://www.j2me.com.cn/bbs] 
    setCommandListener(this);
无线论坛[http://www.j2me.com.cn/bbs] 
    downloader = new HttpThread(url, this);
无线论坛[http://www.j2me.com.cn/bbs] 
    downloader.start();
无线论坛[http://www.j2me.com.cn/bbs] 
  }
无线论坛[http://www.j2me.com.cn/bbs] 
  public void commandAction(Command c, Displayable d) {
无线论坛[http://www.j2me.com.cn/bbs] 
    if(c==cancel) {
无线论坛[http://www.j2me.com.cn/bbs] 
        downloader.cancel();
无线论坛[http://www.j2me.com.cn/bbs] 
        ControllerMIDlet.goBack();
无线论坛[http://www.j2me.com.cn/bbs] 
    }
无线论坛[http://www.j2me.com.cn/bbs] 
  }
无线论坛[http://www.j2me.com.cn/bbs] 
  public void onFinish(byte[] buffer, int size) { … }
无线论坛[http://www.j2me.com.cn/bbs] 
  public void onError(int code, String message) { … }
无线论坛[http://www.j2me.com.cn/bbs] 
  public void onProgress(int percent) { … }
无线论坛[http://www.j2me.com.cn/bbs] 
  public void onSetSize(int size) { … }
无线论坛[http://www.j2me.com.cn/bbs] 
}
无线论坛[http://www.j2me.com.cn/bbs] 
  HttpThread是负责处理Http连接的线程类,它接受一个URL和HttpListener:
无线论坛[http://www.j2me.com.cn/bbs] 
class HttpThread extends Thread {
无线论坛[http://www.j2me.com.cn/bbs] 
  private static final int MAX_LENGTH = 20 * 1024; // 20K
无线论坛[http://www.j2me.com.cn/bbs] 
  private boolean cancel = false;
无线论坛[http://www.j2me.com.cn/bbs] 
  private String url;
无线论坛[http://www.j2me.com.cn/bbs] 
  private byte[] buffer = null;
无线论坛[http://www.j2me.com.cn/bbs] 
  private HttpListener listener;
无线论坛[http://www.j2me.com.cn/bbs] 
  public HttpThread(String url, HttpListener listener) {
无线论坛[http://www.j2me.com.cn/bbs] 
    this.url = url;
无线论坛[http://www.j2me.com.cn/bbs] 
    this.listener = listener;
无线论坛[http://www.j2me.com.cn/bbs] 
  }
无线论坛[http://www.j2me.com.cn/bbs] 
  public void cancel() { cancel = true; }
无线论坛[http://www.j2me.com.cn/bbs] 
}
无线论坛[http://www.j2me.com.cn/bbs] 
(2). 
无线论坛[http://www.j2me.com.cn/bbs] 
  使用GET获取内容
无线论坛[http://www.j2me.com.cn/bbs] 
  我们先讨论最简单的GET请求。GET请求只需向服务器发送一个URL,然后取得服务器响应即可。在HttpThread的run()方法中实现如下:
无线论坛[http://www.j2me.com.cn/bbs] 
public void run() {
无线论坛[http://www.j2me.com.cn/bbs] 
  HttpConnection hc = null;
无线论坛[http://www.j2me.com.cn/bbs] 
  InputStream input = null;
无线论坛[http://www.j2me.com.cn/bbs] 
  try {
无线论坛[http://www.j2me.com.cn/bbs] 
    hc = (HttpConnection)Connector.open(url);
无线论坛[http://www.j2me.com.cn/bbs] 
    hc.setRequestMethod(HttpConnection.GET); // 默认即为GET
无线论坛[http://www.j2me.com.cn/bbs] 
    hc.setRequestProperty("User-Agent", USER_AGENT);
无线论坛[http://www.j2me.com.cn/bbs] 
    // get response code:
无线论坛[http://www.j2me.com.cn/bbs] 
    int code = hc.getResponseCode();
无线论坛[http://www.j2me.com.cn/bbs] 
    if(code!=HttpConnection.HTTP_OK) {
无线论坛[http://www.j2me.com.cn/bbs] 
        listener.onError(code, hc.getResponseMessage());
无线论坛[http://www.j2me.com.cn/bbs] 
        return;
无线论坛[http://www.j2me.com.cn/bbs] 
    }
无线论坛[http://www.j2me.com.cn/bbs] 
    // get size:
无线论坛[http://www.j2me.com.cn/bbs] 
    int size = (int)hc.getLength(); // 返回响应大小,或者-1如果大小无法确定
无线论坛[http://www.j2me.com.cn/bbs] 
    listener.onSetSize(size);
无线论坛[http://www.j2me.com.cn/bbs] 
    // 开始读响应:
无线论坛[http://www.j2me.com.cn/bbs] 
    input = hc.openInputStream();
无线论坛[http://www.j2me.com.cn/bbs] 
    int percent = 0; // percentage
无线论坛[http://www.j2me.com.cn/bbs] 
    int tmp_percent = 0;
无线论坛[http://www.j2me.com.cn/bbs] 
    int index = 0; // buffer index
无线论坛[http://www.j2me.com.cn/bbs] 
    int reads; // each byte
无线论坛[http://www.j2me.com.cn/bbs] 
    if(size!=(-1))
无线论坛[http://www.j2me.com.cn/bbs] 
        buffer = new byte[size]; // 响应大小已知,确定缓冲区大小
无线论坛[http://www.j2me.com.cn/bbs] 
    else
无线论坛[http://www.j2me.com.cn/bbs] 
        buffer = new byte[MAX_LENGTH]; // 响应大小未知,设定一个固定大小的缓冲区
无线论坛[http://www.j2me.com.cn/bbs] 
    while(!cancel) {
无线论坛[http://www.j2me.com.cn/bbs] 
        int len = buffer.length - index;
无线论坛[http://www.j2me.com.cn/bbs] 
        len = len>128 ? 128 : len;
无线论坛[http://www.j2me.com.cn/bbs] 
        reads = input.read(buffer, index, len);
无线论坛[http://www.j2me.com.cn/bbs] 
        if(reads<=0)
无线论坛[http://www.j2me.com.cn/bbs] 
          break;
无线论坛[http://www.j2me.com.cn/bbs] 
        index += reads;
无线论坛[http://www.j2me.com.cn/bbs] 
        if(size>0) { // 更新进度
无线论坛[http://www.j2me.com.cn/bbs] 
          tmp_percent = index * 100 / size;
无线论坛[http://www.j2me.com.cn/bbs] 
          if(tmp_percent!=percent) {
无线论坛[http://www.j2me.com.cn/bbs] 
            percent = tmp_percent;
无线论坛[http://www.j2me.com.cn/bbs] 
            listener.onProgress(percent);
无线论坛[http://www.j2me.com.cn/bbs] 
          }
无线论坛[http://www.j2me.com.cn/bbs] 
        }
无线论坛[http://www.j2me.com.cn/bbs] 
    }
无线论坛[http://www.j2me.com.cn/bbs] 
    if(!cancel && input.available()>0) // 缓冲区已满,无法继续读取
无线论坛[http://www.j2me.com.cn/bbs] 
        listener.onError(601, "Buffer overflow.");
无线论坛[http://www.j2me.com.cn/bbs] 
    if(!cancel) {
无线论坛[http://www.j2me.com.cn/bbs] 
        if(size!=(-1) && index!=size)
无线论坛[http://www.j2me.com.cn/bbs] 
          listener.onError(102, "Content-Length does not match.");
无线论坛[http://www.j2me.com.cn/bbs] 
        else
无线论坛[http://www.j2me.com.cn/bbs] 
          listener.onFinish(buffer, index);
无线论坛[http://www.j2me.com.cn/bbs] 
    }
无线论坛[http://www.j2me.com.cn/bbs] 
  }
无线论坛[http://www.j2me.com.cn/bbs] 
  catch(IOException ioe) {
无线论坛[http://www.j2me.com.cn/bbs] 
    listener.onError(101, "IOException: " + ioe.getMessage());
无线论坛[http://www.j2me.com.cn/bbs] 
  }
无线论坛[http://www.j2me.com.cn/bbs] 
  finally { // 清理资源
无线论坛[http://www.j2me.com.cn/bbs] 
    if(input!=null)
无线论坛[http://www.j2me.com.cn/bbs] 
        try { input.close(); } catch(IOException ioe) {}
无线论坛[http://www.j2me.com.cn/bbs] 
    if(hc!=null)
无线论坛[http://www.j2me.com.cn/bbs] 
        try { hc.close(); } catch(IOException ioe) {}
无线论坛[http://www.j2me.com.cn/bbs] 
  }
无线论坛[http://www.j2me.com.cn/bbs] 
}
无线论坛[http://www.j2me.com.cn/bbs] 
  当下载完毕后,HttpWaitUI就获得了来自服务器的数据,要传递给下一个屏幕处理,HttpWaitUI必须包含对此屏幕的引用并通过一个setData(DataInputStream 
无线论坛[http://www.j2me.com.cn/bbs] 
input)方法让下一个屏幕能非常方便地读取数据。因此,定义一个DataHandler接口:
无线论坛[http://www.j2me.com.cn/bbs] 
public interface DataHandler {
无线论坛[http://www.j2me.com.cn/bbs] 
  void setData(DataInputStream input) throws IOException;
无线论坛[http://www.j2me.com.cn/bbs] 
}
无线论坛[http://www.j2me.com.cn/bbs] 
  HttpWaitUI响应HttpThread的onFinish事件并调用下一个屏幕的setData方法将数据传递给它并显示下一个屏幕:
无线论坛[http://www.j2me.com.cn/bbs] 
public void onFinish(byte[] buffer, int size) {
无线论坛[http://www.j2me.com.cn/bbs] 
  byte[] data = buffer;
无线论坛[http://www.j2me.com.cn/bbs] 
  if(size!=buffer.length) {
无线论坛[http://www.j2me.com.cn/bbs] 
    data = new byte[size];
无线论坛[http://www.j2me.com.cn/bbs] 
    System.arraycopy(data, 0, buffer, 0, size);
无线论坛[http://www.j2me.com.cn/bbs] 
  }
无线论坛[http://www.j2me.com.cn/bbs] 
  DataInputStream input = null;
无线论坛[http://www.j2me.com.cn/bbs] 
  try {
无线论坛[http://www.j2me.com.cn/bbs] 
    input = new DataInputStream(new ByteArrayInputStream(data));
无线论坛[http://www.j2me.com.cn/bbs] 
    if(displayable instanceof DataHandler)
无线论坛[http://www.j2me.com.cn/bbs] 
        ((DataHandler)displayable).setData(input);
无线论坛[http://www.j2me.com.cn/bbs] 
    else
无线论坛[http://www.j2me.com.cn/bbs] 
        System.err.println("[WARNING] Displayable object cannot handle 
无线论坛[http://www.j2me.com.cn/bbs] 
data.");
无线论坛[http://www.j2me.com.cn/bbs] 
    ControllerMIDlet.replace(displayable);
无线论坛[http://www.j2me.com.cn/bbs] 
  }
无线论坛[http://www.j2me.com.cn/bbs] 
  catch(IOException ioe) { … }
无线论坛[http://www.j2me.com.cn/bbs] 
}
无线论坛[http://www.j2me.com.cn/bbs] 
  以下载一则新闻为例,一个完整的HTTP GET请求过程如下:
无线论坛[http://www.j2me.com.cn/bbs] 
  首先,用户通过点击某个屏幕的命令希望阅读指定的一则新闻,在commandAction事件中,我们初始化HttpWaitUI和显示数据的NewsUI屏幕:
无线论坛[http://www.j2me.com.cn/bbs] 
public void commandAction(Command c, Displayable d) {
无线论坛[http://www.j2me.com.cn/bbs] 
  HttpWaitUI wait = new HttpWaitUI("
http://192.168.0.1/news.do?id=1", new 无线论坛[http://www.j2me.com.cn/bbs] 
NewsUI());
无线论坛[http://www.j2me.com.cn/bbs] 
  ControllerMIDlet.forward(wait);
无线论坛[http://www.j2me.com.cn/bbs] 
}
无线论坛[http://www.j2me.com.cn/bbs] 
  NewsUI实现DataHandler接口并负责显示下载的数据:
无线论坛[http://www.j2me.com.cn/bbs] 
public class NewsUI extends Form implements DataHandler {
无线论坛[http://www.j2me.com.cn/bbs] 
  public void setData(DataInputStream input) throws IOException {
无线论坛[http://www.j2me.com.cn/bbs] 
    String title = input.readUTF();
无线论坛[http://www.j2me.com.cn/bbs] 
    Date date = new Date(input.readLong());
无线论坛[http://www.j2me.com.cn/bbs] 
    String text = input.readUTF();
无线论坛[http://www.j2me.com.cn/bbs] 
    append(new StringItem("Title", title));
无线论坛[http://www.j2me.com.cn/bbs] 
    append(new StringItem("Date", date.toString()));
无线论坛[http://www.j2me.com.cn/bbs] 
    append(text);
无线论坛[http://www.j2me.com.cn/bbs] 
  }
无线论坛[http://www.j2me.com.cn/bbs] 
}
无线论坛[http://www.j2me.com.cn/bbs] 
  服务器端只要以String, long, 
无线论坛[http://www.j2me.com.cn/bbs] 
String的顺序依次写入DataOutputStream,MIDP客户端就可以通过DataInputStream依次取得相应的数据,完全不需要解析XML之类的文本,非常高效而且方便。
无线论坛[http://www.j2me.com.cn/bbs] 
  需要获得联网数据的屏幕只需实现DataHandler接口,并向HttpWaitUI传入一个URL即可复用上述代码,无须关心如何连接网络以及如何处理用户中断连接。
无线论坛[http://www.j2me.com.cn/bbs] 
(3).
无线论坛[http://www.j2me.com.cn/bbs] 
  使用POST发送数据
无线论坛[http://www.j2me.com.cn/bbs] 
  以POST方式发送数据主要是为了向服务器发送较大量的客户端的数据,它不受URL的长度限制。POST请求将数据以URL编码的形式放在HTTP正文中,字段形式为fieldname=value,用&分隔每个字段。注意所有的字段都被作为字符串处理。实际上我们要做的就是模拟浏览器POST一个表单。以下是IE发送一个登陆表单的POST请求:
无线论坛[http://www.j2me.com.cn/bbs] 
POST 
http://127.0.0.1/login.do HTTP/1.0无线论坛[http://www.j2me.com.cn/bbs] 
Accept: image/gif, image/jpeg, image/pjpeg, */*
无线论坛[http://www.j2me.com.cn/bbs] 
Accept-Language: en-us,zh-cn;q=0.5
无线论坛[http://www.j2me.com.cn/bbs] 
Content-Type: application/x-www-form-urlencoded
无线论坛[http://www.j2me.com.cn/bbs] 
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
无线论坛[http://www.j2me.com.cn/bbs] 
Content-Length: 28
无线论坛[http://www.j2me.com.cn/bbs] 
\r\n
无线论坛[http://www.j2me.com.cn/bbs] 
username=admin&password=1234
无线论坛[http://www.j2me.com.cn/bbs] 
  要在MIDP应用程序中模拟浏览器发送这个POST请求,首先设置HttpConnection的请求方式为POST:
无线论坛[http://www.j2me.com.cn/bbs] 
hc.setRequestMethod(HttpConnection.POST);
无线论坛[http://www.j2me.com.cn/bbs] 
  然后构造出HTTP正文:
无线论坛[http://www.j2me.com.cn/bbs] 
byte[] data = "username=admin&password=1234".getBytes();
无线论坛[http://www.j2me.com.cn/bbs] 
  并计算正文长度,填入Content-Type和Content-Length:
无线论坛[http://www.j2me.com.cn/bbs] 
hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
无线论坛[http://www.j2me.com.cn/bbs] 
hc.setRequestProperty("Content-Length", String.valueOf(data.length));
无线论坛[http://www.j2me.com.cn/bbs] 
  然后打开OutputStream将正文写入:
无线论坛[http://www.j2me.com.cn/bbs] 
OutputStream output = hc.openOutputStream();
无线论坛[http://www.j2me.com.cn/bbs] 
output.write(data);
无线论坛[http://www.j2me.com.cn/bbs] 
  需要注意的是,数据仍需要以URL编码格式编码,由于MIDP库中没有J2SE中与之对应的URLEncoder类,因此,需要自己动手编写这个encode()方法,可以参考java.net.URLEncoder.java的源码。剩下的便是读取服务器响应,代码与GET一致,这里就不再详述。
无线论坛[http://www.j2me.com.cn/bbs] 
  使用multipart/form-data发送文件
无线论坛[http://www.j2me.com.cn/bbs] 
  如果要在MIDP客户端向服务器上传文件,我们就必须模拟一个POST 
无线论坛[http://www.j2me.com.cn/bbs] 
multipart/form-data类型的请求,Content-Type必须是multipart/form-data。
无线论坛[http://www.j2me.com.cn/bbs] 
  以multipart/form-data编码的POST请求格式与application/x-www-form-urlencoded完全不同,multipart/form-data需要首先在HTTP请求头设置一个分隔符,例如ABCD:
无线论坛[http://www.j2me.com.cn/bbs] 
hc.setRequestProperty("Content-Type", "multipart/form-data; boundary=ABCD");
无线论坛[http://www.j2me.com.cn/bbs] 
  然后,将每个字段用“--分隔符”分隔,最后一个“--分隔符--”表示结束。例如,要上传一个title字段"Today"和一个文件C:\1.txt,HTTP正文如下:
无线论坛[http://www.j2me.com.cn/bbs] 
--ABCD
无线论坛[http://www.j2me.com.cn/bbs] 
Content-Disposition: form-data; name="title"
无线论坛[http://www.j2me.com.cn/bbs] 
\r\n
无线论坛[http://www.j2me.com.cn/bbs] 
Today
无线论坛[http://www.j2me.com.cn/bbs] 
--ABCD
无线论坛[http://www.j2me.com.cn/bbs] 
Content-Disposition: form-data; name="1.txt"; filename="C:\1.txt"
无线论坛[http://www.j2me.com.cn/bbs] 
Content-Type: text/plain
无线论坛[http://www.j2me.com.cn/bbs] 
\r\n
无线论坛[http://www.j2me.com.cn/bbs] 
<这里是1.txt文件的内容>
无线论坛[http://www.j2me.com.cn/bbs] 
--ABCD--
无线论坛[http://www.j2me.com.cn/bbs] 
\r\n
无线论坛[http://www.j2me.com.cn/bbs] 
  请注意,每一行都必须以\r\n结束,包括最后一行。如果用Sniffer程序检测IE发送的POST请求,可以发现IE的分隔符类似于---------------------------7d4a6d158c9,这是IE产生的一个随机数,目的是防止上传文件中出现分隔符导致服务器无法正确识别文件起始位置。我们可以写一个固定的分隔符,只要足够复杂即可。
无线论坛[http://www.j2me.com.cn/bbs] 
  发送文件的POST代码如下:
无线论坛[http://www.j2me.com.cn/bbs] 
String[] props = ... // 字段名
无线论坛[http://www.j2me.com.cn/bbs] 
String[] values = ... // 字段值
无线论坛[http://www.j2me.com.cn/bbs] 
byte[] file = ... // 文件内容
无线论坛[http://www.j2me.com.cn/bbs] 
String BOUNDARY = "---------------------------7d4a6d158c9"; // 分隔符
无线论坛[http://www.j2me.com.cn/bbs] 
StringBuffer sb = new StringBuffer();
无线论坛[http://www.j2me.com.cn/bbs] 
// 发送每个字段:
无线论坛[http://www.j2me.com.cn/bbs] 
for(int i=0; i   sb = sb.append("--");
无线论坛[http://www.j2me.com.cn/bbs] 
  sb = sb.append(BOUNDARY);
无线论坛[http://www.j2me.com.cn/bbs] 
  sb = sb.append("\r\n");
无线论坛[http://www.j2me.com.cn/bbs] 
  sb = sb.append("Content-Disposition: form-data; name=\""+ props
 + 无线论坛[http://www.j2me.com.cn/bbs] 
"\"\r\n\r\n");
无线论坛[http://www.j2me.com.cn/bbs] 
  sb = sb.append(URLEncoder.encode(values
));无线论坛[http://www.j2me.com.cn/bbs] 
  sb = sb.append("\r\n");
无线论坛[http://www.j2me.com.cn/bbs] 
}
无线论坛[http://www.j2me.com.cn/bbs] 
// 发送文件:
无线论坛[http://www.j2me.com.cn/bbs] 
sb = sb.append("--");
无线论坛[http://www.j2me.com.cn/bbs] 
sb = sb.append(BOUNDARY);
无线论坛[http://www.j2me.com.cn/bbs] 
sb = sb.append("\r\n");
无线论坛[http://www.j2me.com.cn/bbs] 
sb = sb.append("Content-Disposition: form-data; name=\"1\"; 
无线论坛[http://www.j2me.com.cn/bbs] 
filename=\"1.txt\"\r\n");
无线论坛[http://www.j2me.com.cn/bbs] 
sb = sb.append("Content-Type: application/octet-stream\r\n\r\n");
无线论坛[http://www.j2me.com.cn/bbs] 
byte[] data = sb.toString().getBytes();
无线论坛[http://www.j2me.com.cn/bbs] 
byte[] end_data = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
无线论坛[http://www.j2me.com.cn/bbs] 
// 设置HTTP头:
无线论坛[http://www.j2me.com.cn/bbs] 
hc.setRequestProperty("Content-Type", MULTIPART_FORM_DATA + "; boundary=" + 
无线论坛[http://www.j2me.com.cn/bbs] 
BOUNDARY);
无线论坛[http://www.j2me.com.cn/bbs] 
hc.setRequestProperty("Content-Length", String.valueOf(data.length + file.length 
无线论坛[http://www.j2me.com.cn/bbs] 
+ end_data.length));
无线论坛[http://www.j2me.com.cn/bbs] 
// 输出:
无线论坛[http://www.j2me.com.cn/bbs] 
output = hc.openOutputStream();
无线论坛[http://www.j2me.com.cn/bbs] 
output.write(data);
无线论坛[http://www.j2me.com.cn/bbs] 
output.write(file);
无线论坛[http://www.j2me.com.cn/bbs] 
output.write(end_data);
无线论坛[http://www.j2me.com.cn/bbs] 
// 读取服务器响应:
无线论坛[http://www.j2me.com.cn/bbs] 
// TODO...
无线论坛[http://www.j2me.com.cn/bbs] 
(4).
无线论坛[http://www.j2me.com.cn/bbs] 
  使用Cookie保持Session
无线论坛[http://www.j2me.com.cn/bbs] 
  通常服务器使用Session来跟踪会话。Session的简单实现就是利用Cookie。当客户端第一次连接服务器时,服务器检测到客户端没有相应的Cookie字段,就发送一个包含一个识别码的Set-Cookie字段。在此后的会话过程中,客户端发送的请求都包含这个Cookie,因此服务器能够识别出客户端曾经连接过服务器。
无线论坛[http://www.j2me.com.cn/bbs] 
  要实现与浏览器一样的效果,MIDP应用程序必须也能识别Cookie,并在每个请求头中包含此Cookie。
无线论坛[http://www.j2me.com.cn/bbs] 
  在处理每次连接的响应中,我们都检查是否有Set-Cookie这个头,如果有,则是服务器第一次发送的Session 
无线论坛[http://www.j2me.com.cn/bbs] 
ID,或者服务器认为会话超时,需要重新生成一个Session ID。如果检测到Set-Cookie头,就将其保存,并在随后的每次请求中附加它:
无线论坛[http://www.j2me.com.cn/bbs] 
String session = null;
无线论坛[http://www.j2me.com.cn/bbs] 
String cookie = hc.getHeaderField("Set-Cookie");
无线论坛[http://www.j2me.com.cn/bbs] 
if(cookie!=null) {
无线论坛[http://www.j2me.com.cn/bbs] 
  int n = cookie.indexOf(';');
无线论坛[http://www.j2me.com.cn/bbs] 
  session = cookie.substring(0, n);
无线论坛[http://www.j2me.com.cn/bbs] 
}
无线论坛[http://www.j2me.com.cn/bbs] 
  使用Sniffer程序可以捕获到不同的Web服务器发送的Session。WebLogic Server 7.0返回的Session如下:
无线论坛[http://www.j2me.com.cn/bbs] 
Set-Cookie: 
无线论坛[http://www.j2me.com.cn/bbs] 
JSESSIONID=CxP4FMwOJB06XCByBWfwZBQ0IfkroKO2W7FZpkLbmWsnERuN5u2L!-1200402410; 
无线论坛[http://www.j2me.com.cn/bbs] 
path=/
无线论坛[http://www.j2me.com.cn/bbs] 
  而Resin 2.1返回的Session则是:
无线论坛[http://www.j2me.com.cn/bbs] 
Set-Cookie: JSESSIONID= aTMCmwe9F5j9; path=/
无线论坛[http://www.j2me.com.cn/bbs] 
  运行ASP.Net的IIS返回的Session:
无线论坛[http://www.j2me.com.cn/bbs] 
Set-Cookie: ASPSESSIONIDQATSASQB=GNGEEJIDMDFCMOOFLEAKDGGP; path=/
无线论坛[http://www.j2me.com.cn/bbs] 
  我们无须关心Session ID的内容,服务器自己会识别它。我们只需在随后的请求中附加上这个Session ID即可:
无线论坛[http://www.j2me.com.cn/bbs] 
if(session!=null)
无线论坛[http://www.j2me.com.cn/bbs] 
  hc.setRequestProperty("Cookie", session);
无线论坛[http://www.j2me.com.cn/bbs] 
  对于URL重写来保持Session的方法,在PC客户端可能很有用,但是,由于MIDP程序很难分析出URL中有用的Session信息,因此,不推荐使用这种方法
评论
显示
悄悄话
汇众教育官网 | 联系方式 | 版权声明 | 友情链接
Copyright 2008© 汇众益智(北京)教育科技有限公司. All Rights Reserved
京ICP备09092043号 京公网安备11010802009023号