首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME UDP 協定程式設計:DatagramConnection 完整實戰

     編輯:J2ME

GCF (Generic Connection Framework) 提供 DatagramConnection 與 Datagram 介面支援 UDP 通訊。MIDP 2.0 新增 UDPDatagramConnection 擴充介面,提供 getLocalAddress()、getLocalPort() 方法。本文完整示範 UDP 客戶端/伺服器雙向通訊實作。

UDP 連線 URL 格式

  • datagram://host:port — 客戶端模式,指定目標位址
  • datagram://:port — 伺服器模式,綁定本地埠號監聽

通用發送器元件

public class Sender extends Thread {
    private DatagramConnection conn;
    private String targetAddr;
    private String message;

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

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

    public void run() {
        while (true) {
            synchronized (this) {
                if (message == null) {
                    try { wait(); } catch (InterruptedException e) {}
                }
            }
            try {
                byte[] data = message.getBytes();
                Datagram dg;
                if (targetAddr == null) {
                    dg = conn.newDatagram(data, data.length);
                } else {
                    dg = conn.newDatagram(data, data.length, targetAddr);
                }
                conn.send(dg);
            } catch (IOException e) {
                e.printStackTrace();
            }
            message = null;
        }
    }
}

伺服器端實作

public class UdpServer implements Runnable, CommandListener {
    private DatagramMIDlet midlet;
    private Display display;
    private Form form;
    private StringItem status;
    private TextField input;
    private Sender sender;
    private String clientAddr;

    public UdpServer(DatagramMIDlet midlet) {
        this.midlet = midlet;
        display = Display.getDisplay(midlet);
        form = new Form("UDP Server");
        status = new StringItem("狀態:", "等待連線...");
        input = new TextField("發送:", "", 30, TextField.ANY);
        form.append(status);
        form.append(input);
        form.addCommand(new Command("發送", Command.ITEM, 1));
        form.setCommandListener(this);
        display.setCurrent(form);
    }

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

    public void run() {
        try {
            DatagramConnection dc = (DatagramConnection) 
                Connector.open("datagram://:5555");
            sender = new Sender(dc);
            status.setText("監聽埠 5555...");

            while (true) {
                Datagram dg = dc.newDatagram(100);
                dc.receive(dg);
                clientAddr = dg.getAddress();
                String msg = new String(dg.getData(), 0, dg.getLength());
                status.setText("收到: " + msg);
            }
        } catch (IOException e) {
            showAlert("錯誤", "埠 5555 已被佔用");
        }
    }

    public void commandAction(Command c, Displayable d) {
        if (c.getLabel().equals("發送") && clientAddr != null) {
            sender.send(clientAddr, input.getString());
        }
    }
}

客戶端實作

public class UdpClient implements Runnable, CommandListener {
    private DatagramMIDlet midlet;
    private Display display;
    private Form form;
    private StringItem status;
    private TextField input;
    private Sender sender;

    public UdpClient(DatagramMIDlet midlet) {
        this.midlet = midlet;
        display = Display.getDisplay(midlet);
        form = new Form("UDP Client");
        status = new StringItem("狀態:", "");
        input = new TextField("發送:", "", 30, TextField.ANY);
        form.append(status);
        form.append(input);
        form.addCommand(new Command("發送", Command.ITEM, 1));
        form.setCommandListener(this);
        display.setCurrent(form);
    }

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

    public void run() {
        try {
            DatagramConnection dc = (DatagramConnection)
                Connector.open("datagram://localhost:5555");
            sender = new Sender(dc);
            status.setText("已連線至伺服器");

            while (true) {
                Datagram dg = dc.newDatagram(100);
                dc.receive(dg);
                if (dg.getLength() > 0) {
                    String msg = new String(dg.getData(), 0, dg.getLength());
                    status.setText("收到: " + msg);
                }
            }
        } catch (ConnectionNotFoundException e) {
            showAlert("錯誤", "請先啟動伺服器");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void commandAction(Command c, Displayable d) {
        if (c.getLabel().equals("發送")) {
            sender.send(null, input.getString()); // null 表示用連線目標
        }
    }
}

主 MIDlet 整合

public class DatagramMIDlet extends MIDlet implements CommandListener {
    private Form menu;
    private ChoiceGroup modeChoice;
    private boolean paused;

    protected void startApp() {
        paused = false;
        if (menu == null) {
            menu = new Form("UDP Demo");
            modeChoice = new ChoiceGroup("選擇模式", Choice.EXCLUSIVE);
            modeChoice.append("伺服器", null);
            modeChoice.append("客戶端", null);
            menu.append(modeChoice);
            menu.addCommand(new Command("啟動", Command.ITEM, 1));
            menu.addCommand(new Command("離開", Command.EXIT, 2));
            menu.setCommandListener(this);
        }
        Display.getDisplay(this).setCurrent(menu);
    }

    public void commandAction(Command c, Displayable d) {
        if (c.getCommandType() == Command.EXIT) {
            destroyApp(true); notifyDestroyed();
        } else if (c.getLabel().equals("啟動")) {
            String mode = modeChoice.getString(modeChoice.getSelectedIndex());
            if (mode.equals("伺服器")) new UdpServer(this).start();
            else new UdpClient(this).start();
        }
    }
    public boolean isPaused() { return paused; }
    public void pauseApp() { paused = true; }
    public void destroyApp(boolean u) {}
}

重要限制與注意事項

  • ⚠️ 非必選功能:MIDP 僅強制支援 HTTP,UDP/TCP 屬選配,部署前必須確認目標裝置支援
  • ⚠️ 不可靠傳輸:UDP 不保證送達、順序、不重複,重要資料需自行實作確認/重傳
  • ⚠️ NAT 穿透:行動網路常有 NAT 阻擋入站封包,伺服器模式在真機可能無法運作
  • ✅ 執行緒隔離:所有網路操作必須在非主執行緒
  • ✅ 資源釋放:finally 中關閉 DatagramConnection

適用場景

  • 即時遊戲位置同步(容忍丟包)
  • 廣播發現服務
  • 簡單遙控/指令傳送
  • 本地網路(Wi-Fi)裝置間通訊

UDP 適合對延遲敏感、可容忍偶發丟包的應用。若需可靠傳輸,請改用 TCP (SocketConnection) 或 HTTP。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved