技术开发 频道

Windows CE,PocketPC上的Java编程


【IT168 技术文档】网络联机的过程介绍

    笔者先为各位介绍一下基本的Java网络程序联机的原理,如图所述在Server端要先开启一个连接阜准备接收Client的联机,当一收到Client端的联机的时候便可以将Server的位置及连接阜号(Socket)传给Client然后Client便取联机的信息再将资料及Socket一起透过网络(Socket记载着IP Address及Port)将讯息送到Server端,就可以开始和作交易啰!


图Client-Server联机示意图

开始撰写网络程序吧!!
    我们先撰写一个简单的Server吧!!

import java.io.*; import java.net.*; public class netServer { String clientMessage; ServerSocket sSocket; //宣告使用ServerSocket的类别 Socket csocket; //取得Client联机封包的Socket,各为别想太多就是Client端的联机 public netServer() { try { sSocket = new ServerSocket(900,200); //开启Port 900,并限定Client联机的数量为200,若开启正常则开始等待Client端的联机 csocket = sSocket.accept(); //Client端已经联机上了取得Socket System.out.println("取得一个Client端从 "+csocket.getInetAddress().getHostAddress()); //显示出Client IP } catch(IOException ioe) { System.out.println("开启Server异常!!!"); } } public static void main(String[] args) { new netServer(); } }

执行
    编译成功后打java netServer画面如下图所示就会开始等待接受Client端的要求啰!!


图netServer开始等待Client端发出要求



    接着我们切换到DOS模式(再开一个DOS窗口)输入telnet 127.0.0.1 900(注意空格)画面会一闪就过去了。接着我们观察Server的画面是否有出现取得一个Client端从 127.0.0.1如下图图10-4所示。接着我们就开始撰写PocketPC中的Client吧!!


图netServer开始等待Client端发出要求


注意 :目前Server的程序皆在PC端执行喔!!待下个Client范例开始才移到PocketPC中执行。

    打造个Hello NetWork吧!! 皆下来我们撰写个输入您的姓名,Server会打对您打招呼的程序吧!!这个程序的原理是在Server端执行一个无线回圈,然后提供服务如接受到Client传来的讯息之后就传回一个讯息Hello的讯息给Client,另外我们为了达到一次能够同时服务多个使用者所以我们使用了Thread的技术。

//此为Server端程序 import java.io.*; import java.net.*; public class netHelloServer { String clientMessage; ServerSocket sSocket; //宣告使用ServerSocket的类别 Socket csocket; //取得Client联机封包的Socket,各为别想太多就是Client端的联机 public netHelloServer() { try { sSocket = new ServerSocket(900,200); //开启Port 900,并限定Client联机的数量为200,若开启正常则开始等待Client端的联机 while(true) { csocket=sSocket.accept(); Thread t=new MyThread(csocket); t.start(); } } catch(IOException ioe) { System.out.println("开启Server异常!!!"); } } public static void main(String[] args) { new netHelloServer(); } } class MyThread extends Thread { Socket conn; String tempStr; DataInputStream dis; DataOutputStream dos; //建构者 public MyThread(Socket inSocket) { conn = inSocket; } public void run() { try{ System.out.println("Server go connect from:"+conn.getInetAddress().getHostName()); dos = new DataOutputStream(conn.getOutputStream()); dos.writeUTF("输入您的姓名的资料"); //get the request conntent dis = new DataInputStream(conn.getInputStream()); tempStr = dis.readUTF(); //响应一下 dos.writeUTF("您输入的资料为"+tempStr+"系统正在为您准备中请稍后..."); //复杂的动作可以写在这边 dos.writeUTF(tempStr+" 您好..."); System.out.println("Server recivews data ="+tempStr); conn.close();//断线 } catch(IOException e) { System.out.println(e); } } } //Client端的程序 import java.awt.*; import java.awt.event.*; import java.net.*; import java.io.*; public class HelloClient extends Frame { Label lb1 = new Label("请输入姓名"); TextField tf1 = new TextField("",14); Label lb2 = new Label("请输入Server的IP"); TextField tf2 = new TextField("",14); TextArea ta1 = new TextArea(""); Button btn1 = new Button("送出讯息"); Button btn2 = new Button("离开"); Panel pl1 = new Panel(); Panel pl2 = new Panel(); static Socket csocket = null; MouseClickevent bce = new MouseClickevent(); public HelloClient() { //窗口设定 btn1.addMouseListener (bce); btn2.addMouseListener (bce); pl1.setLayout(new GridLayout(2,1)); pl1.add(lb1); pl1.add(tf1); pl1.add(lb2); pl1.add(tf2); add(pl1,BorderLayout.NORTH); add(ta1,BorderLayout.CENTER); pl2.add(btn1); pl2.add(btn2); add(pl2,BorderLayout.SOUTH); setSize(240,320); setVisible(true); } public static void main(String[] args) { new HelloClient(); } //以下为按钮事件处理 class MouseClickevent implements MouseListener { public void mouseClicked(MouseEvent e) {} public void mousePressed(MouseEvent e) { if(e.getSource() == btn1) { if(!tf2.getText().equals("")&&!tf1.getText().equals("")) try{ //csocket = new Socket("127.0.0.1",900); csocket = new Socket(tf2.getText(),900); DataInputStream dis = new DataInputStream(csocket.getInputStream()); String data = dis.readUTF(); //System.out.println("\nClient get datafrom server = "+data); ta1.append("\n送一个讯息到Server: "+data); //write response to server DataOutputStream dos = new DataOutputStream(csocket.getOutputStream()); //dos.writeUTF("Bye! all done"); dos.writeUTF(tf1.getText()); data = ""; data = dis.readUTF(); //System.out.println("Client get datafrom server = "+data); ta1.append("\n收到Server的讯息: "+data); data = dis.readUTF(); //System.out.println("Client get datafrom server = "+data); ta1.append("\n收到Server的讯息: "+data); csocket.close(); } catch(IOException IOe) { System.out.println(e); } } else if(e.getSource() == btn2) { //System.out.println("Btn2 is Clicked"); System.exit(1); } } public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} } }


    编译及激活程序 Server端 执行方法在PC端编译及执行 javac –classpath %pjeeclasspath%;. netHelloServer.java(编译) java –classpath %pjeeclasspath%;. netHelloServer(执行)


图 netServer开始等待Client端发出要求


注意 :Server激活之后就不要关掉了,可以测试Client端的联机。

    Client端 请各位读者照着下面输入指令,记得您的PocketPC要连上网络唷!! javac –classpath %pjeeclasspath%;. Clinet.java(Enter) java –classpath %pjeeclasspath%;. Client(Enter)


图Client的仿真器画面


图 在PDA中的画面


注意!!
1. 各位读者可以从程序中注意到Server端及Client端中的Read及Write是互相对称的,希望大家在撰写程序中需要这个要点。
2. 配合无线网络卡、是蓝芽技术、及行动通讯等技术,这就是相当实用的应用程序了,感谢人类创造了网络还有Java。

    一个URL的类别需要下面几个两个主要的参数: 协议的定义(如http或是ftp)等 资源的名称(包含网址或是port) 关于URL的部分笔者只有为各位作简单的介绍,接着附上个读取网页的范例,当然啦!!先玩玩看啰!!然后再讨论一下吧。

//httptest.java import java.awt.*; import java.awt.event.*; import java.net.*; import java.io.*; public class httptest extends Frame { private Label lb1 = new Label("URL"); private TextField tf1 = new TextField(10); private TextArea ta1 = new TextArea(); private Button btn1 = new Button("Get"); Panel p1 = new Panel(); public httptest() { p1.add(lb1); p1.add(tf1); p1.add(btn1); //sp1.add(ta1); add(p1,BorderLayout.NORTH); add(ta1,BorderLayout.CENTER); btn1.addActionListener(new btn1ActionEvent()); setSize(240,320); //for iPAQ setVisible(true); } public static void main(String args[]) { new httptest(); } class btn1ActionEvent implements ActionListener { public void actionPerformed(ActionEvent e) { String URLStr; try { //开启一个新的URL对象 URL u = new URL(tf1.getText()); ta1.append("\t You hava entered:"+lb1.getText()+"\n"); ta1.append("\t URL info"+u.toString()+"\n"); InputStreamReader ir = new InputStreamReader(u.openStream()); BufferedReader bf = new BufferedReader(ir); ta1.append("\t URL stream connection: Read file now...\n"); String aLine; while((aLine = bf.readLine())!=null) { ta1.append(aLine + "\n"); } bf.close(); ir.close(); } catch(MalformedURLException mue) { //System.out.println("网址不正确"); } catch(IOException ioe) { //System.out.println("Error "+ioe); } } } }

编译及执行程序

javac –classpath %pjeeclasspath%;. httptest.java(编译)
pjava –classpath %pjeeclasspath%;. httptest (执行)

    接着输入个网址,记得要连上网络啊!!笔者是输http://www.javatwo.net,接着会跑出很多很多东西唷!!


图 在仿真器中的画面(1)


图 在仿真器中的画面(2)

    相信大家都觉得很奇怪,为什么无法看看到如我们浏览器一般的美丽图样及文字呢?因为我们必须要在为这些取得的字符串还有档案作剖析(parse)的动作,如读到了图形的字节就需要使用使用绘图软件打开,读到音乐的字节就需要使用媒体播放工具来开启,这是可一门相当大的学问也是相当的苦工唷。

分布式的应用程序

    在为各位读着介绍下一个更炫更酷的RMI技术之前笔者先为各位介绍一些分布式应用程序的观念,另外附上一个网络程序与数据库连接的范例架构如下图所示,我们将SocketServer中间安置许多真实的程序逻辑,最后再透过JDBC连接到数据库,如此我们可以将数据库的联机降至最低,至于Client端联机的处理则就需要靠各位撰写程序的技巧啰!!这是常常看到的多层式(N-tier)架构或是分布式的应用程序皆是以此技巧发展出来的笔者所附上的范例程序是属于三层式架构(3-tier)。

图(三层式)的系统架构


Server端的应用程序


    皆下来的程序满有趣而且也很实用的,希望各位读者会喜欢。下面附上的Server端中具有连接数据库查询及提供Socket服务的Server,各位读者可以在PC端执行。

//netDBServer.java import java.sql.*; import java.net.*; import java.io.*; import java.util.*; import org.hsql.util.*; public class netDBServer { String clientMessage; ServerSocket sSocket; //宣告使用ServerSocket的类别 Socket csocket; //取得Client联机封包的Socket,各为别想太多就是Client端的联机 public netDBServer() { try { sSocket = new ServerSocket(900,200); //开启Port 900,并限定Client联机的数量为200,若开启正常则开始等待Client端的联机 while(true) { csocket=sSocket.accept(); Thread t=new MyThreadDB(csocket); t.start(); } } catch(IOException ioe) { System.out.println("开启Server异常!!!"); } } public static void main(String[] args) { new netDBServer(); } } class MyThreadDB extends Thread { Socket conn; String tempStr; DataInputStream dis; DataOutputStream dos; int ikey; String val; static Connection con = null; String sTestData[]= { "create table Place (Code integer,Name varchar(255))", "create index iCode on Place (Code)", "delete from place", "insert into Place values (4900,'Langenthal')", "insert into Place values (8000,'Zurich')", "insert into Place values (3000,'Berne')", "insert into Place values (1200,'Geneva')", "insert into Place values (6900,'Lugano')", "create table Customer (Nr integer,Name varchar(255),Place integer)", "create index iNr on Customer (Nr)", "delete from Customer", "insert into Customer values (1,'Meier',3000)", "insert into Customer values (2,'Mueller',8000)", "insert into Customer values (3,'Devaux',1200)", "insert into Customer values (4,'Rossi',6900)", "insert into Customer values (5,'Rickli',3000)", "insert into Customer values (6,'Graf',3000)", "insert into Customer values (7,'Mueller',4900)", "insert into Customer values (8,'May',1200)", "insert into Customer values (9,'Berger',8000)", "insert into Customer values (10,'D''Ascoli',6900)", "insert into Customer values (11,'Padruz',1200)", "insert into Customer values (12,'Hug',4900)" }; static boolean DBCheckInit; //建构者 public MyThreadDB(Socket inSocket) { conn = inSocket; } public void run() { try{ System.out.println ("Server go connect from:"+conn.getInetAddress().getHostName()); dos = new DataOutputStream(conn.getOutputStream()); dos.writeUTF("输入查询的资料"); //get the request conntent dis = new DataInputStream(conn.getInputStream()); tempStr = dis.readUTF(); //响应一下 try{ new org.hsql.jdbcDriver(); Class.forName("org.hsql.jdbcDriver").newInstance(); }catch (Exception e){System.out.println(e);} try{ con = DriverManager.getConnection("jdbc:HypersonicSQL:test","sa",""); Statement select = con.createStatement(); ResultSet result = select.executeQuery("Select Code,Name FROM Place"); //初始化数据库 System.out.println("初始化数据库"); for(int i=0;i>sTestData.length;i++) select.executeQuery(sTestData[i]); ResultSet result = select.executeQuery("Select Code,Name FROM Place Where Code ="+tempStr); System.out.println("Got results:"); while(result.next()){ ikey = result.getInt(1); if(result.wasNull()){ikey=-1;} val = result.getString(2); if(result.wasNull()){val=null;} System.out.println("Code = "+ikey); System.out.println("Name = "+val); } }catch(Exception e) { System.out.println(e); }/*finally { if(con!=null){try{con.close();} catch(Exception e){e.printStackTrace();}} }*/ //dos.writeUTF("您查询的资料为"+tempStr+"系统正在为您查询中请稍后..."); dos.writeUTF("您查询的资料为"+val+"系统正在为您查询中请稍后..."); System.out.println("Server recivews data ="+tempStr); conn.close();//断线 } catch(IOException e) {System.out.println(e);} } } Client端的应用程序 Client端的应用程序笔者并没有作窗口程序的设计,只是提供一个雏形给大家使用。 //Client.java import java.net.*; import java.io.*; public class Client { public Client() { try{ //请配合Server的IP修改 Socket csocket = new Socket("192.168.0.1",900); DataInputStream dis = new DataInputStream(csocket.getInputStream()); String data = dis.readUTF(); System.out.println("Client get datafrom server = "+data); //write response to server DataOutputStream dos = new DataOutputStream(csocket.getOutputStream()); dos.writeUTF("3000"); data = ""; data = dis.readUTF(); System.out.println("Client get datafrom server = "+data); data = dis.readUTF(); System.out.println("Client get datafrom server = "+data); csocket.close(); }catch(IOException e) { System.out.println(e); } } public static void main(String[] args) { new Client(); } }

编译及执行程序

注意!!

此部分的编译方法为jdk1.1.8的编译方法,若想在计算机中当Server且和J2SE联机的话,你需要设定C:\jdk1.3.1\jre\lib\security 中的 java.policy 一些联机权限的设定,另外产生 stub 及 skeleton 的时候也需要使用rmic –v1.1的参数,因为 Perosnal Java 是参照jdk.1.1.x的规格实作出来的。
编译程序Server端的Interface及Service
c:\jdk1.1.8\bin\javac –classpath %pjeeclasspath%;. CustWork.java(1)
c:\jdk1.1.8\bin\javac –classpath %pjeeclasspath%;. CustWorkImpl.java(2)
产生Stub及Skeleton
c:\jdk1.1.8\bin\rmic -classpath %pjeeclasspath%;. CustWorkImpl(3)
编译Server端程序
c:\jdk1.1.8\bin\javac -classpath %pjeeclasspath%;. JSESocketFactory.java(4)
编译Client端程序
c:\jdk1.1.8\bin\javac -classpath %pjeeclasspath%;. RMIClient.java(5)
执行程序
注意您需要开两个DOS窗口来执行这两只程序
激活RMI Server程序 pjava -classpath %pjeeclasspath%;. JSESocketFactory(1)

 




图 RMI Server激活画面


激活RMI Client程序

pjava -classpath %pjeeclasspath%;. RMIClient


图 RMI Client激活画面

    另外将Client端移植到WinCE中千万别忘了把XXXX_Stub档案也一起移动过去喔。

结论

    当网络技术,配合无线网络卡,或是其它的产品,相信会是相当有趣的事情喔。

0
相关文章