Android的UDP通讯 [英] Android UDP Communication

查看:239
本文介绍了Android的UDP通讯的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经就如何在Android中接收UDP数据包这个网站看了很多帖子。然而,这一切都不是为我工作!

一些基本知识:

我正在测试我的HTC不可思议(安卓2.2)在3G(没有WiFi或其他任何东西)上运行。没有仿真器都在这里参与。

我的code是简单的:

  1. 在我的服务器(我的电脑上运行)被监听UDP通信端口8752。
  2. 在我的Andr​​oid应用程序打开一个随机端口一个DatagramSocket,并发送一个数据包发送到我的服务器使用此端口。
  3. 在我然后保存该信息(InetAddress是否形成接收数据包,并在包内发现的端口)。
  4. 我试图从我的服务器发送一个UDP包(同样,我的电脑),以我的Andr​​oid应用程序(我的手机上运行),这是行不通的。

//服务器code初始化UDP套接字(片段) 公共无效的init(){     datagram_server_socket =新的DatagramSocket(端口,LOCAL_ADDR);     datagram_server_socket.setSoTimeout(1000); }

//片段对Android应用程序code发送数据包到服务​​器

 公共无效连接(){
    随机R =新的随机(System.currentTimeMillis的());
    INT udp_port = 0;
    而(真){
        尝试 {
            udp_port = r.nextInt(1000)+8000;
            udp_port = 8000;
            comm_skt =新的DatagramSocket(udp_port);
            Log.i(ServerWrapper,UDP监听端口:+ udp_port);
            打破;
        }赶上(SocketException E){
            Log.e(ServerWrapper,无法绑定到端口+ udp_port);
        }
    }
    byte []的SDATA =新的字节[4 + tid.length]。
    I = 0;
    SDATA [i ++在] =(字节)(0XFF及(udp_port>> 24));
    SDATA [i ++在] =(字节)(0XFF及(udp_port>> 16));
    SDATA [i ++在] =(字节)(0XFF及(udp_port>→8));
    SDATA [i ++在] =(字节)(0XFF及(udp_port));
    对于(字节B:TID){
        SDATA [我+ +] = B;
    }
    DatagramPacket类PKT =新的DatagramPacket(SDATA,sdata.length,
                                InetAddress.getByName(主机名),端口);
    comm_skt.send(PKT);
}
 

//服务器的UDP套接字监听code 公共无效serverUDPListener(){     尝试 {         datagram_server_socket.receive(rpkt);         INT端口= 0;         byte []的RDATA = rpkt.getData();         端口+ = RDATA [0]<< 24;         端口+ = RDATA [1];&所述; 16;         端口+ = RDATA [2]<< 8;         端口+ =(0XFF)及RDATA [3];         byte []的TID =新的字节[rdata.length]         对(INT I = 4; I&其中; rdata.length&安培;&安培; RDATA [I]大于0;我++){             TID [I-4] = RDATA [I];         }         字符串的thread_id =新的String(TID).trim();         的for(int i = 0; I< threads.size();我++){         ClientThread吨= threads.get(ⅰ);         如果(t.getThreadId()的compareTo(thread_id单)== 0){             t.se​​tCommSocket(rpkt,口);         } 其他 {             通信System.err.println(线程ID+的thread_id +无法找到);         }         }     }赶上(IOException异常E){         如果((E的instanceof SocketException)及!&安培;!(五的instanceof SocketTimeoutException如果))         log.warning(错误的同时监听一个UDP包。);     } }

//对应于setCommSocket调用上面保存传入UDP数据包的IP和端口的服务器端 公共无效setCommSocket(DatagramPacket类PKT,INT端口){     comm_ip = pkt.getAddress();     comm_port = pkt.getPort(); //尝试从数据包的端口? }

//发送一个UDP数据包从服务器到Android应用 公共无效sendIdle(){     如果(comm_ip!= NULL){         通信System.err.println(已发送IDLE分组(+ comm_ip.getHostAddress()+:+ comm_port +));         DatagramPacket类SPKT =新的DatagramPacket(新的byte [] {1,} ProtocolWrapper.IDLE,2,comm_ip,comm_port);         DatagramSocket的SKT;         尝试 {             SKT =新的DatagramSocket();             skt.send(SPKT);         }赶上(例外五){             e.printStackTrace();         }     } }

现在我已经很难codeD我的应用程序使用,以8000然而端口,有什么奇怪的是,每次测试我的程序(并查看IP /端口是救了我的服务器上),港口包的来源始终是33081.我有AA线程不断监听UDP流量在我的Andr​​oid应用程序,但code从不执行通过了接收(数据包)部分:

公共无效AndroidUDPListener(){     而(真){         同步(停止){         如果(停止)返回;         }         byte []的recieve_data =新的字节[64];         DatagramPacket类rpkt =新的DatagramPacket(recieve_data,recieve_data.length);         尝试 {         如果(comm_skt == NULL)                 继续;         comm_skt.receive(rpkt);         byte []的数据= rpkt.getData();         开关(数据[1]){             空闲的情况下:             如果(OCL!= NULL)ocl.onCompletion(空);             打破;             案例KEEP_ALIVE:             打破;         }         }赶上(例外五){         如果((E的instanceof SocketException)及!&安培;!(五的instanceof SocketTimeoutException如果))                 Log.w(ServerWrapper,错误的同时监听一个UDP包。);         }     } }

有谁看到一个问题,我的code?或者是有一些权限/设置我需要在我的应用程序中设置的第一?我有互联网通信功能。

实例输出(使用该端口的数据包的getPort()):

  

Android应用程序 - 现在在端口8000监听UDP流量

     

Android应用程序 - 发送数据包到服务​​器

     

服务器 - 从XXXXXX收到的报文:33081

     

服务器 - 发送空闲数据包发送到XXXXXX:33081

实施例的输出(使用从分组数据的端口):

  

Android应用程序 - 现在在端口8000监听UDP流量

     

Android应用程序 - 发送数据包到服务​​器

     

服务器 - 从XXXXXX收到的数据包:8000

     

服务器 - 发送空闲数据包发送到XXXXXX:8000

Android应用程序从未收到使用该端口或者任何UDP流量。

解决方案

对不起,不更新此越快。问题是固定如下:

我需要存储DatagramSocket的每个线程。侦听套接字也应用于继续在服务器和客户之间的通信的插座。以下是更新code位。

上线新的套接字注册code:

 公共无效setCommSocket(DatagramPacket类PKT,INT端口,DatagramSocket类SKT)
{
  comm_ip = pkt.getAddress();
  comm_port = pkt.getPort();
  同步(comm_pkt){
    comm_pkt = PKT;
  }
  comm_skt = SKT;
}
 

新服务器侦听code:

 公共无效UDPListen(){
        而(真){
            同步(停止){
                如果(停止)
                    打破;
            }

            byte []的recieve_data =新的字节[64];
            DatagramPacket类rpkt =新的DatagramPacket(recieve_data,recieve_data.length);
            尝试 {
                datagram_server_socket.receive(rpkt);
                INT端口= 0;
                byte []的RDATA = rpkt.getData();
                端口+ = RDATA [0]<< 24;
                端口+ = RDATA [1];&所述; 16;
                端口+ = RDATA [2]<< 8;
                端口+ =(0XFF)及RDATA [3];
                byte []的TID =新的字节[rdata.length]
                的for(int i = 4; I< rdata.length和放大器;&放大器; RDATA [1]  -  GT; 0;我++)
                {
                    TID [I-4] = RDATA [I];
                }
                字符串的thread_id =新的String(TID).trim();
                的for(int i = 0; I< threads.size();我++){
                    ClientThread吨= threads.get(ⅰ);
                    如果(t.getThreadId()的compareTo(thread_id单)== 0)
                    {
                        t.se​​tCommSocket(rpkt,港口,datagram_server_socket);
                    } 其他 {
                        通信System.err.println(线程ID+的thread_id +无法找到);
                    }
                }
            }赶上(IOException异常E){
                如果((E的instanceof SocketException)及!&安培;!(五的instanceof SocketTimeoutException如果))
                    log.warning(错误的同时监听一个UDP包。);
            } 最后 {
                的for(int i = 0; I< threads.size();我++){
                    ClientThread吨= threads.get(ⅰ);
                    t.se​​ndKeepAlive();
                }
            }
        }
    }
 

有一些更新到服务器/线程,我将omitt的结构。这里最重要的部分是,在该分组是:收到与被插座重新用于发送数据返回给客户端。此外,实际的数据包被重新用来发送数据传回:

 公共无效sendIdle(){
        如果(comm_ip!= NULL){
            同步(comm_pkt){
                尝试 {
                    comm_pkt.setData(新的byte [] {1,ProtocolWrapper.IDLE});
                    comm_skt.send(comm_pkt);
                }赶上(例外五){
                    e.printStackTrace();
                }
            }
        }

    }
 

下面是我的包装类的相关部分,显示了每个线程持有:

 公共类PeerWrapper {

    私人InetAddress类ip地址;
    私人整数口;
    私人插槽client_socket;
    私人的InetAddress comm_ip;
    私人DatagramSocket的comm_skt;
    私人DatagramPacket类comm_pkt;
    私人诠释comm_port;
    私人字节状态;
 

I've read many posts on this site on how to receive UDP packets in Android. However, none of this is working for me!

Some basics:

I am testing on my HTC Incredible (Android 2.2) running on 3G (not wifi or anything else). No emulators are involved here.

My code is simple:

  1. My server (running on my PC) is listening for UDP traffic on port 8752.
  2. My Android application opens a DatagramSocket on a random port and sends a packet to my server with this port.
  3. I then save this information (the InetAddress form the received packet and the port found within the packet).
  4. I try to send an UDP packet from my server (again, on my PC) to my Android app (running on my phone) and it does NOT work.

//Server code to initialize the UDP socket (snippet)
public void init() {
    datagram_server_socket = new DatagramSocket(port,local_addr);
    datagram_server_socket.setSoTimeout(1000);
}

//Snippet of code on the ANDROID APP that sends a packet to the server

public void connect() {
    Random r = new Random(System.currentTimeMillis());
    int udp_port = 0;
    while(true){
        try {
            udp_port = r.nextInt(1000)+8000;
            udp_port = 8000;
            comm_skt = new DatagramSocket(udp_port);
            Log.i("ServerWrapper", "UDP Listening on port: " + udp_port);
            break;
        } catch(SocketException e) {
            Log.e("ServerWrapper", "Could not bind to port " + udp_port);
        }
    }
    byte[] sdata = new byte[4+tid.length];
    i = 0;
    sdata[i++] = (byte)(0XFF&(udp_port>>24));
    sdata[i++] = (byte)(0XFF&(udp_port>>16));
    sdata[i++] = (byte)(0XFF&(udp_port>>8));
    sdata[i++] = (byte)(0XFF&(udp_port));
    for(byte b: tid){
        sdata[i++] = b;
    }
    DatagramPacket pkt = new DatagramPacket(sdata, sdata.length, 
                                InetAddress.getByName(hostname), port);
    comm_skt.send(pkt);
}

//Server's UDP socket listening code
public void serverUDPListener() {
    try {
        datagram_server_socket.receive(rpkt);
        int port = 0;
        byte[] rdata = rpkt.getData();
        port += rdata[0]<<24;
        port += rdata[1]<<16;
        port += rdata[2]<<8;
        port += (0XFF)&rdata[3];
        byte[] tid = new byte[rdata.length];
        for(int i = 4; i < rdata.length && rdata[i] > 0; i++) {
            tid[i-4] = rdata[i];
        }
        String thread_id = new String(tid).trim();
        for(int i = 0; i < threads.size(); i++) {
        ClientThread t = threads.get(i);
        if(t.getThreadId().compareTo(thread_id) == 0) {
            t.setCommSocket(rpkt, port);
        } else {
            System.err.println("THREAD ID " + thread_id + " COULD NOT BE FOUND");
        }
        }
    } catch (IOException e) {
        if(!(e instanceof SocketException) && !(e instanceof SocketTimeoutException))
        log.warning("Error while listening for an UDP Packet.");
    }
}

//Corresponds to the setCommSocket call above to save the IP and Port of the incoming UDP packet on the server-end
public void setCommSocket(DatagramPacket pkt, int port) {
    comm_ip = pkt.getAddress();
    comm_port = pkt.getPort(); //Try the port from the packet?
}

//Sends an UDP packet from the SERVER to the ANDROID APP
public void sendIdle() {
    if(comm_ip != null) {
        System.err.println("Sent IDLE Packet (" + comm_ip.getHostAddress() + ":" + comm_port + ")");
        DatagramPacket spkt = new DatagramPacket(new byte[]{1, ProtocolWrapper.IDLE}, 2, comm_ip, comm_port);
        DatagramSocket skt;
        try {
            skt = new DatagramSocket();
            skt.send(spkt);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Right now I've hard coded the port my application uses to 8000. However, what's odd is that EVERYTIME I test my program (and view the IP/Port that is saved on my server), the port the packet came from is always 33081. I have a a thread constantly listening for UDP traffic in my Android App but the code never executes passed the "receive(packet)" part:

public void AndroidUDPListener() {
    while(true) {
        synchronized(stop) {
        if(stop) return;
        }
        byte[] recieve_data = new byte[64];
        DatagramPacket rpkt = new DatagramPacket(recieve_data, recieve_data.length);
        try {
        if(comm_skt == null) 
                continue;
        comm_skt.receive(rpkt);
        byte[] data = rpkt.getData();
        switch(data[1]) {
            case IDLE:
            if(ocl != null) ocl.onCompletion(null);
            break;
            case KEEP_ALIVE:
            break;
        }
        } catch (Exception e) {
        if(!(e instanceof SocketException) && !(e instanceof SocketTimeoutException))
                Log.w("ServerWrapper", "Error while listening for an UDP Packet.");
        }
    }
}

Does anyone see an issue in my code? Or is there some permission/settings I need to set on my application first? I have internet communication enabled.

Example Output (using the port from the packet getPort()):

Android App - Now listening for UDP traffic on port 8000

Android App - Sending packet to server

Server - Received packet from XXXXXX:33081

Server - Sending IDLE packet to XXXXXX:33081

Example Output (using the port from the packet data):

Android App - Now listening for UDP traffic on port 8000

Android App - Sending packet to server

Server - Received packet from XXXXXX:8000

Server - Sending IDLE packet to XXXXXX:8000

The Android App never receives any UDP traffic from using either of the ports.

解决方案

Sorry for not updating this sooner. The problem was fixed as follows:

I needed to store the DatagramSocket to each thread. The listening socket should also be the socket used to continue communication between the server and client. Here are the bits of updated code.

New socket registration code on thread:

public void setCommSocket(DatagramPacket pkt, int port, DatagramSocket skt)
{
  comm_ip = pkt.getAddress();
  comm_port = pkt.getPort();
  synchronized(comm_pkt) {
    comm_pkt = pkt;
  }
  comm_skt = skt;
}

New Server Listening Code:

public void UDPListen() {
        while(true) {
            synchronized(stop) {
                if(stop)
                    break;
            }

            byte[] recieve_data = new byte[64];
            DatagramPacket rpkt = new DatagramPacket(recieve_data, recieve_data.length);
            try {
                datagram_server_socket.receive(rpkt);
                int port = 0;
                byte[] rdata = rpkt.getData();
                port += rdata[0]<<24;
                port += rdata[1]<<16;
                port += rdata[2]<<8;
                port += (0XFF)&rdata[3];
                byte[] tid = new byte[rdata.length];
                for(int i = 4; i < rdata.length && rdata[i] > 0; i++)
                {
                    tid[i-4] = rdata[i];
                }
                String thread_id = new String(tid).trim();
                for(int i = 0; i < threads.size(); i++) {
                    ClientThread t = threads.get(i);
                    if(t.getThreadId().compareTo(thread_id) == 0)
                    {
                        t.setCommSocket(rpkt, port, datagram_server_socket);
                    } else {
                        System.err.println("THREAD ID " + thread_id + " COULD NOT BE FOUND");
                    }
                }
            } catch (IOException e) {
                if(!(e instanceof SocketException) && !(e instanceof SocketTimeoutException))
                    log.warning("Error while listening for an UDP Packet.");
            } finally {
                for(int i = 0; i < threads.size(); i++) {
                    ClientThread t = threads.get(i);
                    t.sendKeepAlive();
                }
            }
        }
    }

There was some update to the structure of the server/threads that I will omitt. The important part here is that the socket in which the packet was recieved with was re-used to send data back to the client. Additionally, the actual packet was re-used to send data back:

public void sendIdle() {
        if(comm_ip != null) {
            synchronized(comm_pkt) {
                try {
                    comm_pkt.setData(new byte[]{1, ProtocolWrapper.IDLE});
                    comm_skt.send(comm_pkt);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }

Here is the relevant parts of my wrapper class that shows what each thread was holding:

public class PeerWrapper {

    private InetAddress ipaddress;
    private Integer port;
    private Socket client_socket;
    private InetAddress comm_ip;
    private DatagramSocket comm_skt;
    private DatagramPacket comm_pkt;
    private int comm_port;
    private byte status;

这篇关于Android的UDP通讯的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆