2014-01-07 35 views
0

工作在一个宠物项目从Android设备为我的电脑创建一个工作鼠标,我有一台运行在PC上的python服务器和android应用程序向它发送所需的数据。Python套接字缓冲和数据丢失

我对创建鼠标的想法是使用Motion_Event UP和MOVE在设备屏幕上记录您的手指移动,计算您的最后和新x,y坐标之间的差异,并将差异发送到PC,以便移动鼠标在相同的模式

现在我有几个问题从发送自己到计算,我真的想让你们的意见,我应该如何做这个更好的算法明智或只是一个糟糕的实现代码在我的部分。

的Java:

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    if(event.getAction() == MotionEvent.ACTION_DOWN){ 
     oldX = (int) event.getX(); 
     oldY = (int) event.getY(); 
    } 
    else if(event.getAction() == MotionEvent.ACTION_MOVE){ 
     newX = (int) event.getX(); 
     newY = (int) event.getY(); 

     xDiff = newX - oldX; 
     yDiff = newY - oldY; 
     Log.v("xdiff", ""+xDiff); 
     Log.v("ydiff", ""+yDiff); 
     oldX = newX; 
     oldY = newY; 
     a.mouse(xDiff, yDiff); 
    } 
    else if(event.getAction() == MotionEvent.ACTION_UP){ 

    } 
    return true; 
} 

插座:

@Override 
protected Void doInBackground(Void... params) { 
    try { 
    this.sock = new Socket("10.0.0.2", 9871); 
    outToServer = new DataOutputStream(this.sock.getOutputStream()); 
    } 
    catch (UnknownHostException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return null; 
} 

     public void mouse(int x, int y) { 

      try { 

       this.outToServer.writeBytes(""+x+","+y); 


      } catch (UnknownHostException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

     } 

蟒蛇插座:

def __init__(self, IP, port): 
    try: 
     self.acceptor = socket.socket() 
     self.acceptor.bind((IP, port)) 
     self.acceptor.listen(1)  
    except socket.error, e: 
     print e 

def start_server(self): 
    try: 
     print "serv up" 
     self.sock, self.connecting_ip = self.acceptor.accept() 
     print self.connecting_ip[0] + " connected!" 

    except socket.error, e: 
     print e 

数据处理本身:

def mouse(self): 
    try: 
     while True: 
      data = self.sock.recv(1024) 
      if data: 
       coords = data.split(",") 
       x = int(coords[0]) 
       y = int(coords[1]) 
       current_x = win32api.GetCursorPos()[0] 
       current_y = win32apo.GetCursorPos()[1] 
       win32api.SetCursorPos((current_x+x,current_y+y)) 
      else: 
       self.sock.close() 
    except socket.error, e: 
     print e 

我得到的问题是:

1)而不是像我发送它(“”+ x +“,”+ y)获取数据,它将更多的数据加载到缓冲区,并出现为x,y ,x,y,x,y,x,y,x,y,x,y ... 我试图搞乱缓冲区大小但是没有做太多 (注意关于这个的奇怪的是我不知道当我在我的模拟器上运行应用程序时,我得到了这个错误,并且我准确地得到了我想要进入缓冲区的x,y,但是当我在我的android设备上运行它时(如果它全部是SGS2的话)事情)的数据去掩体,并一次全部发送)

2)我得到的另一件事是数据被“损坏”或缺少发送''而不是一个数字或有4和-5发送4-5而不是4,-5

总而言之,我很确定我已经在这里主要搞砸了,我希望有人能够阐明我应该怎么去关于这样做。

UDP实现:

@Override 
protected Void doInBackground(Void... params) { 
    try { 

     this.clientSocket = new DatagramSocket(); 
      this.IPAddress = InetAddress.getByName("10.0.0.2"); 
      this.sendData = new byte[1024]; 

    } 
    catch (UnknownHostException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return null; 
} 

     public void mouse(int x, int y) { 

      try { 

        String sentence = "{" + x + "," + y + "}"; 
        this.sendData = sentence.getBytes(); 
        DatagramPacket sendPacket = new DatagramPacket(this.sendData, this.sendData.length, this.IPAddress, 9871); 
        this.clientSocket.send(sendPacket); 

      } catch (UnknownHostException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

     } 

蟒UDP SERV:

import socket 

PORT = 9871 
IP = socket.gethostbyname(socket.gethostname()) 

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP 
sock.bind((IP, PORT)) 
print "Server %s" % IP 

while True: 
     data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes 
     if data: 
      print "received message:", data 
     else: 
      print "dead" 

回答

1

TCP是一个流协议。这意味着,当您多次访问send()(或在您的案例中为.writeBytes())时,将保留不同调用的参数之间的边界。

例如,当你发送:

send("1,2"); 
send("-3,4"); 
send("5,6"); 
send("-7,8"); 

那么这可能在另一端为到达:

"1,2-3,45,6-7,8" 

如果您想使用TCP和消息之间保持界限,你需要添加提供此协议的图层。有两种传统的方法可以实现这一点:

  • 使用标记消息结尾的分隔符字节。确保有效的消息永远不会包含分隔符字节。
  • 在每个消息上添加一个固定长度的字段,例如:一个32位整数。

在你的情况下,采取的第一个选项,只需添加新行可能做的伎俩:

send("1,2\n"); 
send("-3,4\n"); 
send("5,6\n"); 
send("-7,8\n"); 

这将在另一端到达,就像这样:

"1,2\n-3,4\n5,6\n-7,8" 

当你读取,然后可以使用换行符重建原始消息。

请注意不完整的线条。当我们说数据必然会以"1,2\n-3,4\n5,6\n-7,8"到达时,我们正在简化一点点。它也可以一次到达:

"1,2\n-3," // from the first read call 
"4\n5,6\n-7,8" // from the second read call 

当您从TCP流中读取消息时,需要将读入的内容放入缓冲区。除非您处理了完整的消息(或者直到某些事情导致您完全想要放弃连接),否则无法丢弃数据。例如,如果缓冲区以不完整的消息"-3,"结束,那么您需要阅读,直到您有剩余消息:"4\n"

另一个可能适合的解决方案是使用数据报协议,如UDP,其中发送方的消息确实对应于接收方的消息。 (请注意,也有TCP和UDP之间的其他非常显著的差别!不要在此基础上单独切换。)

+0

我试图改变我的代码以使用UDP,因为它确实看起来更加的方式使用的逻辑在这种情况下是,但我确实遇到了另外一个奇怪的问题,我已经实现了新的代码为蟒蛇和Android应用程序,它完美的工作(数据发送),但只在模拟器上,当我尝试从我的设备,它只是崩溃..(我已经添加了新的代码到我的文章) – Shay

0

我注意到的第一件事情是,你不要冲洗流你叫

this.outToServer.writeBytes(""+x+","+y); 

如果你会打电话给

out.flush(); 

之后,该数据将被发送(描述将被刷新)立即。

我觉得第二个问题应该是第一个问题的结果。除此之外,你应该真的考虑使用适当的协议。

+0

试图改变为UDP和它完美的作品只有在我的模拟器上,当我尝试运行我的设备上的代码时,它崩溃(更新后的代码) – Shay

0

您的实施有两个主要问题。

  1. 首先将数据没有缓冲在流这意味着没有办法为接收端现在当发送的坐标开始或结束发送的传出。

    您应该在包完成后使用刷新功能向输出流添加缓冲。这会给接收方带来最好的行为。发送文本时,在将文本添加到流中时也可以使用Writer。但最重要的是,您需要一种方法来将所有外发信息打包为一次鼠标更新(例如,添加像{x,y}这样的前缀和后缀字符)。

  2. 第二个问题是,在开始监视onTouchData()之前,您不要使用onInterceptTouchEvent(在进行交互时返回true)以获取移动数据的独占权。我会建议检查一下,在拦截移动之前至少有一个移动方式是

    ViewConfiguration.get(getContext()).getScaledTouchSlop 
    

    。这将避免您在鼠标光标上产生小震动/搅动。你可以避免其他应用程序干扰罢工检测等。当您收到关闭消息时,您可以临时保存起始值,以便在截距之后进行增量计算。