服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

开发midp联网应用程序

♦ 引言

  在上讲中,我们介绍了如何利用record store把数据保存在终端内。本讲,我们将阐述midp java网络的相关功能。由于n800终端只能使用http通信,所以我们将以http为主要范例进行讲解。到目前为止,只能制作终端内的单机型应用程序,如果利用网络,连接网络服务器,那么就能够制作出多种应用程序。

1. 利用网络

  1.1. generic connection frame work

  j2me应该能支持各种手机终端。由于终端不同其网络功能及文件i/o功能也迥然不同,网络和文件i/o关联的图书馆所需的条件也不同。

  为了解决上述问题,jsme的cldc采用了generic connection framework。generic connection framework拥有不同终端所需的省空间网络功能以及文件i/o功能。广泛应用j2se的java.io和java.net包里的网络、文件i/o功能,并准备7个interface。这样,为能支持各种手机终端的通信功能,只限定interface,在每个手机终端上都能自由安装。不支持手机终端连接的实际安装不能进行。各种interface的说明如表1所示、层次结构如图1所示。

 interface  作用
 connection 成为其他interface基础的interface
 streamconnectionnotifier 具有socket通信连接通知功能的interface
 inputconnection 具有接收数据功能的interface
 outputconnection 具有发送数据功能的interface
 datagramconnection 具有连接udp的数据电报通信功能的interface
 streamconnection 具有socket通信接收/发送功能的interface
 contentconnection 具有通信内容调查功能的interface
 httpconnection 具有http通信功能的interface

表 1

开发midp联网应用程序(图一)
图 1

  1.2. connection interface

  connection interface在generic connection framework中是连接interface的基础interface。其他的连接interface是从connection interface派生而来的。

  1.3. connector 类

  使用connector类的static方法open (string connectstring)入网。

connection con = connector.open("http://www.nec-mfriend.com/");

ex. 1

  例如、如ex. 1所示,在open方法的自变量中输入“http://www.nec-mfiend.com/”,就可以实现与www.nec-mfriend.com服务器进行http通信。
  而generic connection framework的全部链接都是利用connector类的open方法完成的。也就是说,即使链接类型不同,也能以同样的方法完成。j2me由于这样的设计而拥有丰富的扩展性,对于上述新的装置它也配备了简单的支持系统。
  按照下述形式指定open方法的自变量。

{protocol}:[{target}][{params}]

在protocol部分可以指定如下所示的protocol。

 值 链接方式
 file 文件 i/o
 comm. 串行端口通信
 socket socket通信
 datagram 数据电报通信
 http web服务器通信

表 2

*n800不支持socket通信、数据电报通信,而n820支持socket通信。

  在target部分指定服务器的用户名、端口号和文件名等。若有必要的添加信息则在params部分指定。

  open方法也可以指定其他的自变量。

    static connection open(string connectstring, int mode)

从connectstring中制作connection、打开链接,若要使用mode链接则需指定access mode。在access mode中,可以指定connector.read,connector.read_write和connector.write ,若不指定,则为connector.read_write 。在protocol中不能指定access mode时,则放弃illegalargumentexception。

  下表是其他connector类的static方法。

 方法 作用
 datainputstream opendatainputstream(string connectstring) 从connectstring中制作新的datainputstream 并打开。
 dataoutputstream opendataoutputstream(string connectstring) 从connectstring中制作新的dataoutputstream并打开。
 inputstream openinputstream(string connectstring) 从connectstring中制作新的inputstream并打开。
 outputstream openoutputstream(string connectstring) 从connectstring中制作新的outputstream并打开。

  1.4. http 通信

  现在,我们对n800所支持的http通信进行阐述。利用http通信可以连接web服务器。例如,可以把手机终端难以处理的复杂问题交给web服务器处理,得出结果。http通信采用midp方法作为标准,但是,采用midp作为基本方法的终端却不能进行http通信,或者有很大的限制,这一点请注意。

为能在n800中使用http通信需遵从以下规定。
• 要实现midlet通信必须在jad(adf)文件中设定midlet-usenetwork(参考3.jad(adf)文件)为yes。.
• 最大发送量为10kbyte。
大于10kbyte时,超出部分被清除,小于10kbyte的数据才是有效的。
• 最大接收量为100kbyte。
大于100kbyte时,超出部分被清除,小于100kbyte的数据才是有效的。
• 连接处url
从http://开始,包含http://,最多为512byte。不分大/小写。

  http通信由request和response两部分组成。从客户发出的request信息传到服务器,服务器接收request,返还response信息。

  http通信主要有下述三种request方式。

 方式 作用
 get 要求指定的文件。
 head 要求指定文件的header信息。
 post 要求向指定文件发送信息,并得出结果。

接下来,让我们试着用多种request与服务器进行通信。

  1.5. 利用get

    利用get可以读取服务器上的文件。在使用get之前,如下所示需在已完成的httpconnection方法的setrequestmethod方法中,指定httpconnection的static变数get。

httpconnection con = (httpconnection)connector.open("http://www.nec-mfriend.com/");
con.setrequestmethod(httpconnection.get);

ex. 2

    如下所示可以利用datainputstream获取response。

string res="";
datainputstream in = con.opendatainputstream();
int input;
while((input = in.read())!=-1){
res = res + (char)input;
}
in.close();

ex. 3

   以下实际是与服务器通信,获取html文件的sample。为简单介绍sample的操作,得把通信结果,即获取的html文件内容,输入控制台。因此,此sample是以在模拟器上面操作为前提的。

import java.io.datainputstream;
import java.io.ioexception;

import javax.microedition.io.connector;
import javax.microedition.io.httpconnection;
import javax.microedition.midlet.midlet;
import javax.microedition.midlet.midletstatechangeexception;


/**
* 利用get发送request的sample
* 从控制台输出response
*/
public class gettest extends midlet {

   /**
  * 访问服务器
  */
  protected void startapp() throws midletstatechangeexception {

  try {
    httpconnection con = (httpconnection)connector.open("http://www.nec-mfriend.com/en/ ");

    //指定get
    con.setrequestmethod(httpconnection.get);

    datainputstream in = con.opendatainputstream();
    int input;
    while((input = in.read())!=-1){
      system.out.print((char)input);
    }
    in.close();

    //关闭链接
    con.close();
    } catch (ioexception e) {
      e.printstacktrace();
    }
  }
  protected void pauseapp() {
  }
  protected void destroyapp(boolean arg0) throws midletstatechangeexception   {
  }
}

ex. 4

  实际操作后的结果。

开发midp联网应用程序(图二) 
1.6. 利用head

  接下来介绍如何利用head方法获取文件的header。多数情况下,在http header中,包含了文件种类、尺寸大小、文字编码、回复日期、request文件的最后修改时间、以及兑现期限的截止日期等。一般来讲,使用head方法检查其是否对兑现内容进行了新信息的替换。

 为使用head,如下所示要在作成的httpconnection的setrequestmethod方法中,指定httpconnection的static变量head。

httpconnection con = (httpconnection) connector.open("http://www.nec-mfriend.com/en/");
con.setrequestmethod(httpconnection.head);

  获取head信息的方法。

 方法 
 string getheaderfield(int index) 取得由indexheader field指定的header field值
 string getheaderfield(string name) 取得name指定的header field值
 string getheaderfieldkey(int index) 取得index指定的header field名
 long getlength() 取得content-length值
 string gettype() 取得content-typeencoding值
 string getencoding() 取得content-encoding值
 int getresponsecode() 取得应答http的status code
 string getresponsemessage() 取得应答http的信息
 int getheaderfieldint(string name,long def) 在int上取得name指定的header field值。错误时,返还def。
 long getheaderfielddate(string name, long def) 在long上取得name指定的header field值。错误时,返还def。

表 3

  下面是利用getheaderfield方法和getheaderfieldkey方法,获取全部header信息的sample。这个sample与刚才所介绍的一样,是以在模拟器上进行操作为前提而作成的,它只用于说明,实际操作还没有进行测定。由此获取的全部header信息内容将输入控制台。

import java.io.ioexception;

import javax.microedition.io.connector;
import javax.microedition.io.httpconnection;
import javax.microedition.midlet.midlet;
import javax.microedition.midlet.midletstatechangeexception;

/**
* 利用head发送request的sample
* 从控制台输出response
*/
public class headtest extends midlet {

    /**
    * 显示header信息
    */
    protected void startapp() throws midletstatechangeexception {

      try {
        httpconnection con =
    (httpconnection) connector.open("http://www.nec-mfriend.com/en/");

//指定head
        con.setrequestmethod(httpconnection.head);

        //取得关键的http header信息――成对的值
        int i = 0;
        string message = "";
        string key = "";
        string value = "";
        while((value=con.getheaderfield(i))!= null){
          key = con.getheaderfieldkey(i++);
          message = message + key+":"+value+"/n";
        }
        system.out.println(message);

        //关闭链接
        con.close();
      } catch (ioexception e) {
        e.printstacktrace();
      }
    }
    protected void pauseapp() {
  }
  protected void destroyapp(boolean arg0) throws midletstatechangeexception   {
  }
}

ex. 5

   实际操作后的结果如下所示。

开发midp联网应用程序(图三)
图 3

  1.7. 利用post

  为能利用post发送request,要使用inputstream和outputstream 。用outputstream向服务器发送数据,而inputstream则接收来自服务器的response。

  用下述方法指定post。

httpconnection con = (httpconnection) connector.open("http://www.yahoo.com");
con.setrequestmethod(httpconnection.post);

ex. 6

  如下所示使用outputstream在requeat信息中输入数据,使输入数据为(message=helloworld),而变量con是指定了post的httpconnection。

string message=?hmessage=helloworld?h;
dataoutputstream dos = con.opendataoutputstream();
byte[] request = message.getbytes();
for(int i=0;i<request.length;i++){
dos.writebyte(request[i]);
}
dos.flush();

ex. 7

  下面实际是利用post与服务器进行通信的sample。在这里,web服务器将转发利用post发送的信息值,并接收最终结果response。接收的response内容将被输入控制台,请用模拟器进行确认。

import java.io.datainputstream;
import java.io.dataoutputstream;
import java.io.ioexception;

import javax.microedition.io.connector;
import javax.microedition.io.httpconnection;
import javax.microedition.midlet.midlet;
import javax.microedition.midlet.midletstatechangeexception;


/**
* 利用post发送request的sample
* 从控制台输出response
*/
public class posttest extends midlet {

  /**
  * 利用post送信息
  */
  protected void startapp() throws midletstatechangeexception {

    try {
      httpconnection con = (httpconnection)connector.open("http://localhost:8080/nec_server/servlet/reverseservlet");

      //指定post
      con.setrequestmethod(httpconnection.post);

      //在request中输入数据
      string message ="message=helloworld";
      dataoutputstream dos = con.opendataoutputstream();
      byte[] messagebyte = message.getbytes();
      for(int i=0;i < messagebyte.length;i++){
        dos.writebyte(messagebyte[i]);
      }
      dos.flush();
      dos.close();

      //接收response
      datainputstream in = con.opendatainputstream();
      int input;
      while((input = in.read())!=-1){
        system.out.print((char)input);
      }
      in.close();

      //关闭链接
      con.close();
      } catch (ioexception e) {
        e.printstacktrace();
      }
    }
  protected void pauseapp() {
  }
  protected void destroyapp(boolean arg0) throws midletstatechangeexception   {
  }
}

ex. 8

  接下来介绍本次使用的servlet sample,作为服务器实际安装的例子。因为本讲座是midp讲座,所以关于servlet的详细说明就不再赘述,网上有许多这方面的信息,请大家参考sun ―http://java.sun.com/products/servlet/等网站。

import java.io.ioexception;
import java.io.printwriter;

import javax.servlet.servletexception;
import javax.servlet.http.httpservlet;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;


/**
* 把接收的文字列进行转发的servlet
*/
public class reverseservlet extends httpservlet {

  /**
  * 处理post request
  */
  protected void dopost(httpservletrequest req, httpservletresponse res)
  throws servletexception, ioexception {

    //接收参数
    string message = req.getparameter("message");

    //转发文字
    string reverse = "";
    for(int i = message.length();i > 0;i--){
      reverse = reverse + message.charat(i-1);
    }

    //写response
    printwriter out = res.getwriter();
    out.write("<html>/n");
    out.write("<head>/n");
    out.write("<title>request is post.</title>/n");
    out.write("</head>/n");
    out.write("<body>/n");
    out.write("message is "+message+"<br>/n");
    out.write("reverse message is "+reverse+"/n");
    out.write("</body>/n");
    out.write("</html>");
    out.close();
  }
}

ex. 9

实际操作如下所示:

开发midp联网应用程序(图四) 

2. 制作应用程序

  现在,我们介绍如何实际制作利用http通信的应用程序。这次增添了以前所作的泡泡龙游戏(blockapplication)的内容,并把游戏结束的时间作成高低分一览表,由服务器管理。为了使程序更简单,还省略了与声音相关的操作。以下是内容改变前的source code:

blockapplication.java

blockcanvas.java

  给这个程序添加

• 计算结束时间功能。

• 向服务器发送时间表功能。

• 从服务器接收最高分功能。

通过游戏或游戏结束时,显示出最高分。

  为了计算http通信和时间表,给实际变量添加以下变量:

//相关经过时间
private int second = 0;
private long startms;

//http通信类
private final string server_url =
"http://localhost:8080/nec_server/servlet/blockscoreservlet";//服务器的upl
private string[] highscore = null;//最高分

ex. 10

    2.1. 计算结束时间

    为了计算结束时间,要记录游戏开始时的系统时间(startms),以这个时间为准计算经过时间,如下画面所示:

/*****************************************
* 计时器相关处理
*****************************************/
/**
* 计算经过时间
*/
public int getsecond() {
  return (int)((system.currenttimemillis()-startms)/1000);
}

ex. 11

    2.2. 向服务器发送时间表,接收最高分

  如上所述,游戏结束时显示最高分。但是,游戏结束时向服务器发送时间表,而通过游戏时不发送时间表,只显示最高分。

  为在通过游戏时显示最高分,要与服务器进行通信,由此获得最高分。这里,可以用我们介绍的httpconnection,利用get取得最高分。可以在游戏结束时使用以下方法。

/**
* 与服务器进行通信,获取最高分。
*/
public string[] gethighscore() {
  string[] str = new string[5];
  httpconnection con = null;
  datainputstream in = null;
  try {
    con = (httpconnection) connector.open(server_url);

//接收response
    in = con.opendatainputstream();
    int input;
    int i = 0;
    string s = "";
    while ((input = in.read()) != -1) {
      if ((char) input == '/n') {
        str[i] = s;
        i++;
        s = "";
        continue;
      }
      s = s + (char) input;
    }

  } catch (ioexception e) {
    e.printstacktrace();
  } finally {
    if (con != null) {
    try {
      con.close();
    } catch (ioexception e1) {
      e1.printstacktrace();
    }
  }
    if (in != null) {
      try {
        in.close();
      } catch (ioexception e1) {
        e1.printstacktrace();
      }
    }
  }

  return str;
}

ex. 12

    下面是进行游戏时的操作。结束游戏时向服务器发送结束时间,即利用post如下所示发送结束时间。然后,接收来自服务器的response最高分。可以在游戏结束时使用以下方法。

/**
* 向服务器发送时间表,取得最高分
*/
public string[] sendscore() {
  string[] str = new string[5];
  httpconnection con = null;
  dataoutputstream out = null;
  datainputstream in = null;
  try {
    con = (httpconnection) connector.open(server_url);
    con.setrequestmethod(httpconnection.post);

    out = con.opendataoutputstream();

    //向服务器发送时间表
    string message = "score=" + second;
    byte[] messagebyte = message.getbytes();
    for (int i = 0; i < messagebyte.length; i++) {
      out.writebyte(messagebyte[i]);
    }
    out.close();

    //接收response
    in = con.opendatainputstream();
    int input;
    int i = 0;
    string s = "";
    while ((input = in.read()) != -1) {
      if ((char) input == '/n') {
        str[i] = s;
        i++;
        s = "";
        continue;
      }
      s = s + (char) input;
    }

  } catch (ioexception e) {
    e.printstacktrace();
  } finally {
    if (con != null) {
      try {
        con.close();
      } catch (ioexception e1) {
        e1.printstacktrace();
      }
    }
    if (out != null) {
      try {
        out.close();
      } catch (ioexception e1) {
        e1.printstacktrace();
      }
    }

    if (in != null) {
      try {
        in.close();
      } catch (ioexception e1) {
        e1.printstacktrace();
      }
    }
  }

  return str;
}

ex. 13

  2.3. 显示最高分

  通过游戏和游戏结束时,都显示最高分。用以下方法显示最高分:

/**
* 显示最高分
*/
public void painthighscore(graphics g){
  for (int i = 0; i < highscore.length; i++) {
    if(highscore[i] == null)break;
    g.drawstring(
    highscore[i],
    10,
    10 + i * 15,
    graphics.left | graphics.top);
  }
}

ex. 14

  2.4. 运行

  完成的source code如下:

blockapplication.java

blockcanvas.java

另外,服务器使用的servlet的source code 式如下:

nec_server.zip

运行后的结果如下:

开发midp联网应用程序(图五) 开发midp联网应用程序(图六)
开发midp联网应用程序(图七)

3. 总结

  在本讲中,介绍了可以利用http通信进行网络编程。利用本讲介绍的东西,能够制作简单的chat程序以及联网作战游戏等应用程序。请大家也试着制作一些新的独特的应用程序吧。

扫描关注微信公众号