Python套接字缓冲和数据丢失

时间:2014-01-07 13:20:49

标签: java android python sockets buffer

在一个宠物项目上工作,从一个Android设备为我的电脑创建一个可用的鼠标,我在PC上运行一个python服务器,Android应用程序向它发送所需的数据。

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

现在我从发送到计算中遇到了一些问题,我真的希望你们的观点是我应该如何更好地完成这个算法,或者只是对我的代码执行不好的实现。

爪哇:

@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();
            }

        }

python套接字:

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();
            }

        }

python 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"

3 个答案:

答案 0 :(得分: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之间还存在其他非常显着的差异!请勿基于此单独切换。)

答案 1 :(得分:0)

我注意到的第一件事是,在你打电话

后你没有冲洗流
this.outToServer.writeBytes(""+x+","+y);

如果你打电话

out.flush();

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

我认为第二号问题应该是第一号问题的结果。 除此之外,您应该考虑使用适当的协议。

答案 2 :(得分:0)

您的实施中存在两个主要问题。

  1. 首先,数据在没有缓冲的情况下在流上发送,这意味着当发送坐标开始或结束时,接收端无法进行。

    在包完成后,您应该使用刷新向输出流添加缓冲。这将在接收方提供最佳行为。发送文本时,还可以在将文本添加到流时使用Writer。但最重要的是,您需要一种方法来为一次鼠标更新包装所有传出信息(例如添加前缀和后缀字符,如{x,y})。

  2. 您的第二个问题是您不使用onInterceptTouchEvent(在移动时返回true)以在开始监视onTouchData()之前获得移动数据的独占权限。我建议检查至少有一个移动

    ViewConfiguration.get(getContext()).getScaledTouchSlop 
    
    在拦截移动之前。这样可以避免在鼠标光标上轻微抖动/搅拌。并且您可以避免其他应用程序干扰警示检测等。当您收到关闭消息时,您可以暂时保存在截取delta计算后使用的起始值。