在J2ME中基于UDP协议编程

作者:mingjava   文章来源:http://www.j2medev.com/Article/ShowArticle.asp?ArticleID=129

在GCF中提供了DatagramConnection和Datagram两个接口,借助他们我们可以在J2ME中基于UDP协议开发联网应用程序,在MIDP2.0中,添加了UDPDatagramConnection这个接口。他扩展了DatagramConnection并添加了两个方法getLocalAddress()和getLocalPort()。我们知道UDP服务是不可靠的,如果你希望开发更可靠的联网应用的话可以采用SocketConnection,因为TCP服务是面向连接且可靠的。我们还必须清楚地一点是以上所说的各种连接方式都不是MIDP规范中规定必须实现的。因此在使用之前请参考特定设备的开发文档。MIDP中只有Http连接是必须支持的。

    同样,我们要获得DatagramConnection的话,必须通过Connector的open方法,其中的URL应该满足如下的形式。

  1. datagram://localhost:5555 这样的话表示建立了一个客户端模式的连接。在指定ip:localhost和指定端口:5555
  2. datagram://:5555  这样建立的是一个服务器端模式的连接,在本地的5555端口。

建立连接后,我们可以通过DatagramConnection的newDatagram()方法构造一个Datagram,然后调用DatagramConnection的send()方法。这样数据报将会发送到指定的接受方。例如你可以构建这个一个负责发送数据的Sender类。

package com.siemens.datagramtest;

import javax.microedition.io.Datagram;
import javax.microedition.io.DatagramConnection;

public class Sender extends Thread
{

    private DatagramConnection dc;

    private String address;

    private String message;

    public Sender(DatagramConnection dc)
    {
        this.dc = dc;
        start();
    }

    public synchronized void send(String addr, String msg)
    {
        address = addr;
        message = msg;
        notify();
    }

    public synchronized void run()
    {

        while (true)
        {

            // If no client to deal, wait until one connects
            if (message == null)
            {
                try
                {
                    wait();
                } catch (InterruptedException e)
                {
                }
            }

            try
            {
                byte[] bytes = message.getBytes();
                Datagram dg = null;
                // Are we a sender thread for the client ? If so then there's
                // no address parameter
                if (address == null)
                {
                    dg = dc.newDatagram(bytes, bytes.length);
                } else
                {
                    dg = dc.newDatagram(bytes, bytes.length, address);
                    System.out.println(address);
                }
                dc.send(dg);
            } catch (Exception ioe)
            {
                ioe.printStackTrace();
            }

            // Completed client handling, return handler to pool and
            // mark for wait
            message = null;
        }
    }

}
注意联网的时候我们应该在另外一个线程中而不是在主线程中。

     服务器端的目的就是启动后监听指定的端口,当客户端连接过来后接受数据并记录下客户端的地址,以便服务器端向客户端发送数据。
package com.siemens.datagramtest;

import java.io.IOException;

import javax.microedition.io.Connector;
import javax.microedition.io.Datagram;
import javax.microedition.io.DatagramConnection;
import javax.microedition.io.UDPDatagramConnection;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.StringItem;
import javax.microedition.lcdui.TextField;

public class Server implements Runnable, CommandListener
{

    private DatagramMIDlet parent;

    private Display display;

    private Form f;

    private StringItem si;

    private TextField tf;

    private Command sendCommand = new Command("Send", Command.ITEM, 1);

    Sender sender;

    private String address;

    public Server(DatagramMIDlet m)
    {
        parent = m;
        display = Display.getDisplay(parent);
        f = new Form("Datagram Server");
        si = new StringItem("Status:", " ");
        tf = new TextField("Send:", "", 30, TextField.ANY);
        f.append(si);
        f.append(tf);
        f.addCommand(sendCommand);
        f.setCommandListener(this);
        display.setCurrent(f);
    }

    public void start()
    {

        Thread t = new Thread(this);
        t.start();
    }

    public void run()
    {
        try
        {

            si.setText("Waiting for connection");
            DatagramConnection dc =(DatagramConnection)Connector.open("datagram://:5555");
          

            sender = new Sender(dc);

            while (true)
            {
                Datagram dg = dc.newDatagram(100);
                dc.receive(dg);
                address = dg.getAddress();
                si.setText("Message received - "
                        + new String(dg.getData(), 0, dg.getLength()));
             
            }

        } catch (IOException ioe)
        {
            Alert a = new Alert("Server", "Port 5000 is already taken.", null,
                    AlertType.ERROR);
            a.setTimeout(Alert.FOREVER);
            a.setCommandListener(this);
            display.setCurrent(a);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public void commandAction(Command c, Displayable s)
    {
        if (c == sendCommand && !parent.isPaused())
        {
            if (address == null)
            {
                si.setText("No destination address");
            } else
            {
                sender.send(address, tf.getString());
            }
        }
        if (c == Alert.DISMISS_COMMAND)
        {
            parent.destroyApp(true);
            parent.notifyDestroyed();
        }
    }

    public void stop()
    {
    }

}

客户端代码则是建立连接后向服务器端发送数据,并等待接受服务器返回的数据。
package com.siemens.datagramtest;

import java.io.IOException;

import javax.microedition.io.ConnectionNotFoundException;
import javax.microedition.io.Connector;
import javax.microedition.io.Datagram;
import javax.microedition.io.DatagramConnection;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.StringItem;
import javax.microedition.lcdui.TextField;

public class Client implements Runnable, CommandListener
{

    private DatagramMIDlet parent;

    private Display display;

    private Form f;

    private StringItem si;

    private TextField tf;

    private Command sendCommand = new Command("Send", Command.ITEM, 1);

    Sender sender;

    public Client(DatagramMIDlet m)
    {
        parent = m;
        display = Display.getDisplay(parent);
        f = new Form("Datagram Client");
        si = new StringItem("Status:", " ");
        tf = new TextField("Send:", "", 30, TextField.ANY);
        f.append(si);
        f.append(tf);
        f.addCommand(sendCommand);
        f.setCommandListener(this);
        display.setCurrent(f);

    }

    public void start()
    {
        Thread t = new Thread(this);
        t.start();
    }

    public void run()
    {
        try
        {

            DatagramConnection dc = (DatagramConnection) Connector
                    .open("datagram://localhost:5555");
           

            si.setText("Connected to server");

            sender = new Sender(dc);

            while (true)
            {
                Datagram dg = dc.newDatagram(100);
                dc.receive(dg);
                // Have we actually received something or is this just a timeout
                // ?
                if (dg.getLength() > 0)
                {
                    si.setText("Message received - "
                            + new String(dg.getData(), 0, dg.getLength()));
                }
            }

        } catch (ConnectionNotFoundException cnfe)
        {
            Alert a = new Alert("Client", "Please run Server MIDlet first",
                    null, AlertType.ERROR);
            a.setTimeout(Alert.FOREVER);
            display.setCurrent(a);
        } catch (IOException ioe)
        {
            ioe.printStackTrace();
        }
    }

    public void commandAction(Command c, Displayable s)
    {
        if (c == sendCommand && !parent.isPaused())
        {
            sender.send(null, tf.getString());
        }
    }

    public void stop()
    {
    }

}
本文的代码取自WTK demo中的例子,您可以参考demo中的源代码!下面给出MIDlet的代码
package com.siemens.datagramtest;

import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.ChoiceGroup;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.MIDlet;

public class DatagramMIDlet extends MIDlet implements CommandListener
{

    private static final String SERVER = "Server";

    private static final String CLIENT = "Client";

    private static final String[] names = { SERVER, CLIENT };

    private static Display display;

    private Form f;

    ChoiceGroup cg;

    private boolean isPaused;

    private Command exitCommand = new Command("Exit", Command.EXIT, 1);

    private Command startCommand = new Command("Start", Command.ITEM, 1);

    public DatagramMIDlet()
    {
        display = Display.getDisplay(this);
        f = new Form("Datagram Demo");
        cg = new ChoiceGroup("Please select peer", Choice.EXCLUSIVE, names,
                null);
        f.append(cg);

        f.addCommand(exitCommand);
        f.addCommand(startCommand);
        f.setCommandListener(this);

        display.setCurrent(f);
    }

    public static Display getDisplay()
    {
        return display;
    }

    public boolean isPaused()
    {
        return isPaused;
    }

    public void startApp()
    {
        isPaused = false;
    }

    public void pauseApp()
    {
        isPaused = true;
    }

    public void destroyApp(boolean unconditional)
    {
    }

    public void commandAction(Command c, Displayable s)
    {
        if (c == exitCommand)
        {
            destroyApp(true);
            notifyDestroyed();
        } else if (c == startCommand)
        {
            String name = cg.getString(cg.getSelectedIndex());
            if (name.equals(SERVER))
            {
                Server server = new Server(this);
                server.start();
            } else
            {
                Client client = new Client(this);
                client.start();
            }
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值