Android:如何使用线程或asynctask发送UDP数据包

时间:2014-04-03 20:01:12

标签: java android sockets

我正在使用UDP在Android上编写一个简单的聊天应用程序。我有一个用于接收数据包的线程(内部类)。 fSocket侦听端口11200以获取数据包。

private class fThread extends Thread {
    private int LISTENING_PORT = 11200;
    DatagramSocket fSocket;
    DatagramPacket fpacket;

    public fThread() {
        try {
                 fSocket= new DatagramSocket(LISTENING_PORT); 
                 fSocket.setBroadcast(false);
            }catch (IOException e) {}
    }
    public void run() {
        try {
                 while (true) {
                     byte[] buf = new byte[1024];
                     fpacket = new DatagramPacket(buf, buf.length); 
                     fSocket.receive(fpacket);
                     //some other code below
                 }
            }
    }
        private void Write(byte[] newfpacket,String DestIP1) {
   try {
        String data = new String (newfpacket);
            DatagramPacket toForward = new DatagramPacket(data.getBytes(),data.length(),InetAddress.getByName(DestIP1.trim()), LISTENING_PORT);
                uniSocket.setBroadcast(false);
                uniSocket.send(toForward);
                catch (UnknownHostException e1) {
                android.util.Log.i(TAG1,"Unknown host exception:"+e1.getMessage());
                e1.printStackTrace();
             } catch (IOException e) {
                android.util.Log.i(TAG1,"Some IO exception: "+e.getMessage());
                e.printStackTrace();
            }

当我点击一个按钮时,我打电话给 fThread fthread = new fThread(); fthread.Write(somemessage," 192.168.1.105"),我得到一个我知道的networkonmainthread异常 这是因为写入是在主线程上完成的,并且必须是它自己的线程或AsyncTAsk。 基本上我想在按下按钮时发送UDP数据包,在某些destIP上发送LISTENING_PORT。我尝试这样做,但不知道如何进一步使线程发送单个数据包,每当我点击一个按钮。

 private class sendThread extends Thread { //for sending packet to listening port
     DatagramSocket uniSocket;

     void run (){

     }
 } 

1 个答案:

答案 0 :(得分:0)

您可以做的一件事是使用ConcurrentLinkedQueue<Object>。在ThreadAsynTask中,您需要检查该队列是否有要发送的内容,在这种情况下,您将从队列中删除它(轮询)并发送它。在单击按钮的主线程中,您只需创建对象并将其放入队列queue.add(),这样您就不会收到异常。 object只是一个保存要发送的数据(字节)的类,还有数据,您可以保留目标IP地址,端口号等。请参阅ConcurrentLinkedQueue手册对于addpoll对象的方法。我有工作的例子,如果你需要它,是为TCP,虽然这个想法适用于你的情况。

您需要在启动时启动AyncTask或Thread,例如,当队列为空时,此线程或asyntask会休眠Thread.sleep(250)。当你有什么要从队列发送poll并发送它。

编辑(exmaples):

// this is the class used to send the packets (data)
public class QueueItem
{
    private static final String defaultIP = "192.168.1.150";
    private static final short defaultPort = 3030;
    public byte[] data = null;
    public String dstIP;
    public short dstPort;

    public QueueItem(byte[] theData) {
        this(theData, "", 0);
    }

    public QueueItem(byte[] theData, String theIP) {
        this(theData, theIP, 0);
    }

    public QueueItem(byte[] theData, String theIP, int thePort) {
        this.data = null;
        if (theData != null && theData.length > 0)
        {
            data = new byte[theData.length];
            for (int i = 0; i < theData.length; i++)
                this.data[i] = theData[i];
        }
        if (theIP.trim().length() > 0) this.dstIP = theIP.trim();
        else this.dstIP = defaultIP; // for example
        if (thePort != 0) this.dstPort = (short) thePort;
        else this.dstPort = defaultPort; // for example
    }
}

// To declare the Queue
public static final ConcurrentLinkedQueue<QueueItem> myQueue = new ConcurrentLinkedQueue<QueueItem>();
public static boolean Terminated=false;

// To queue something do like this:
    QueueItem qItem = new QueueItem("This is a test message".getBytes());
    myQueue.add(qItem);

// in the doInBackground of your AsyncTask
while (!Terminated) 
{
    while (!Terminated && myQueue.isEmpty()) 
    { 
        Thread.sleep(250);
    }
    if (Terminated) break;
    QueueItem qItem = myQueue.poll();
    if (qItem != null)
    {
        DatagramPacket toForward = new DatagramPacket(qItem.data, qItem.data.length,InetAddress.getByName(qItem.dstIP, qItem.dstPort));
        uniSocket.setBroadcast(false);
        uniSocket.send(toForward);
    }
}