2015-11-19 82 views
0

我的「遠程」應用程序出現問題。我想要做的就是使用我的手機作爲觸摸屏來控制我的電腦的鼠標光標,這個工作到目前爲止,還有一個小問題,那就是在移動光標太多之後,我得到一個異常。太多AsyncTask的UDP(DatagramSocket)在執行時拋出異常

以下代碼只包含最重要的片段。

在我的手機,我有以下的「觸摸屏」 - 面積:

RelativeLayout mouse = (RelativeLayout) findViewById(R.id.relative_layout_mouse); 
    mouse.setOnTouchListener(new View.OnTouchListener() { 
     @Override 
     public boolean onTouch(View v, MotionEvent e) { 
      int action = e.getAction(); 
      if (action == MotionEvent.ACTION_MOVE) { 
       int historySize = e.getHistorySize(); 
       if(historySize > 0){ 
        //calculations on how to get x and y differences between current x/y and previous (historySize-1) x/y 
        new ClientUDPTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new String[]{difference_x, difference_y}); 
       } 
      } 
      return true; 
     } 
    }); 

它發送許多小變化協調我的AsyncTask當鼠標移動:

public class ClientUDPTask extends AsyncTask<String,String,String> { 
@Override 
protected String doInBackground(String[] params) { 
    ByteBuffer buffer = ByteBuffer.wrap(new byte[7]); 
    //put the coordinates into the ByteBuffer... 
    byte[] bytes = buffer.array(); 
    InetAddress adress = null; 
    DatagramSocket socket = null; 
    try { 
     socket = new DatagramSocket(); 
     adress = InetAddress.getByName("192.168.1.108"); 
     DatagramPacket packet = new DatagramPacket(bytes, bytes.length, adress, 9000); 
     socket.send(packet); 
    } catch (UnknownHostException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

,然後我的服務器我用那些移動光標:

public class UDPServer { 

private DatagramSocket socket; 

public void listen() { 
    try { 
     socket = new DatagramSocket(9000); 
     byte[] buffer = new byte[7]; 
     DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 
     while (true) { 
      try { 
       socket.receive(packet); 
       byte[] data = packet.getData(); 
       //get coordinates out of bytearray... 
       Robot robot = new Robot(); 
       int newX = x - Integer.valueOf(x); 
       int newY = y - Integer.valueOf(y); 
       robot.mouseMove(newX, newY); 
      } catch (AWTException e) { 
       e.printStackTrace(); 
      } 
     } 
    } catch (SocketException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

現在,你可以猜測,當移動mou SE身邊多了,很多任務被創建的數據發送到服務器的那些片段,直到我得到這個異常:

java.net.SocketException: socket failed: EMFILE (Too many open files) 
    at libcore.io.IoBridge.socket(IoBridge.java:623) 
    at java.net.PlainDatagramSocketImpl.create(PlainDatagramSocketImpl.java:93) 
    at java.net.DatagramSocket.createSocket(DatagramSocket.java:157) 
    at java.net.DatagramSocket.<init>(DatagramSocket.java:80) 
    at java.net.DatagramSocket.<init>(DatagramSocket.java:65) 
    at com.example.johnsmith.remote.ClientUDPTask.doInBackground(ClientUDPTask.java:31) 
    at com.example.johnsmith.remote.ClientUDPTask.doInBackground(ClientUDPTask.java:15) 
    at android.os.AsyncTask$2.call(AsyncTask.java:288) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
    at java.lang.Thread.run(Thread.java:818) 
Caused by: android.system.ErrnoException: socket failed: EMFILE (Too many open files) 
    at libcore.io.Posix.socket(Native Method) 
    at libcore.io.BlockGuardOs.socket(BlockGuardOs.java:282) 
    at libcore.io.IoBridge.socket(IoBridge.java:608) 
    ... 11 more 

此異常點:

socket = new DatagramSocket(); 

ClientUDPTask.java

在移動LogCat顯示我的網絡使用率〜1 KB/s。這一切都在我的WiFi上運行。

當我使用TCP而不是UDP時,我已經有過這個問題。雖然這是非常緩慢,雖然我也沒有使用.executeOnExecutor(...)。 PlayStation上有無數的應用程序可以完成這個Remote-Thingie,它非常流暢,但他們是如何做到的?

我的錯誤是什麼?

+0

您應該只有一個插座。創建新的線程和每秒50次的套接字將會減慢你的速度。 – WalterM

回答

0

嘗試在客戶端使用單個DatagramSocket,而不是爲每個要發送的DatagramPacket創建一個新的DatagramSocket。或者用socket.close();完成後關閉插槽。我想你只是打開了太多的套接字。

+0

我將如何創建一個單一的永久性套接字?每次我運行Asynctask一個新的必須打開,因爲這是我可以打開它的唯一地方。我曾經想過,但我不知道該怎麼做。 – Arekai

+0

@Arekai你可以爲自定義的AsyncTask創建一個構造函數,它接受一個套接字,然後在doInBackground()中使用該套接字。我認爲在UI線程上創建套接字是安全的,只是不要使用它在UI線程上傳遞任何數據。 – Coeffect

+0

哦,哇,簡單地給它的構造函數...爲什麼我沒有想到這一點。非常感謝你! – Arekai