简体   繁体   English

Python(Server)从Java(client)接收数据,在单独的行中..(TCP)

[英]Python(Server) receiving Data from Java(client) In separate lines.. (TCP)

Okay so I read many questions and couldn't figure it out. 好的,所以我读了许多问题,无法解决。 I am facing problem with the data which I receive from my Android App. 我从Android应用程序接收到的数据面临问题。 Basically I want to control a servo. 基本上我想控制一个伺服器。 The code works, but the data sent by the app to the server is received in separate lines. 该代码有效,但是应用发送到服务器的数据在单独的行中接收。 Yes i know i need to use buffer, I researched a bit but couldn't find a way to add a buffer to my code. 是的,我知道我需要使用缓冲区,我做了一些研究,但找不到找到在我的代码中添加缓冲区的方法。 Also I don't think I need to show my Java Code because its just basic Commands (Strings like Up, Down, etc) Sending from the Button Clicks. 另外,我认为我不需要显示Java代码,因为它只是从按钮单击发送的基本命令(如Up,Down等字符串)。

...Python Code(Server)...
  ctrCmd = ['Up','Down', 'ON', 'OFF']
  ...
  ...
  while True:
        print ("Waiting for connection")
        tcpCliSock,addr = tcpSerSock.accept()
        print ("...connected from :", addr)

    try:
            while True:
                    data = ''
                    data = tcpCliSock.recv(BUFSIZE).decode()
                    print("This",data)

                    if not data:
                            print ("No Data",data)
                            break
                    if data == ctrCmd[0]:
                            print("I am here")
                            Servomotor.ServoUp()
                            print ("Increase: ",Servomotor.cur_X)
                            #tcpCliSock.send("Servo Increases".encode())
                    if data == ctrCmd[1]:
                            Servomotor.ServoDown()
                            print ("Decrease: ",Servomotor.cur_X)
                            #tcpCliSock.send("Servo Decreases".encode())
                    if data == ctrCmd[2]:
                            Servomotor.ledOn()
                            print ("Led On")
                            #tcpCliSock.send("Led On".encode())
                    if data == ctrCmd[3]:
                            Servomotor.ledOff()
                            print ("Led Off")
                           # tcpCliSock.send("Led Off".encode())
    except KeyboardInterrupt:
            Servomotor.close()
            GPIO.cleanup()
tcpSerSock.close();

在此处输入图片说明

Also i dont understand why it says No data even when it shows recieved data? 我也不明白为什么即使显示收到的数据也说没有数据? Please Help I'm really a noob and am trying to learn. 请帮助我真的是菜鸟,正在尝试学习。 THANKS!! 谢谢!!

UPDATE!! UPDATE! After I changed the decode() Suggested, 在我更改了decode()建议后,

在此处输入图片说明

    public class MainActivity extends AppCompatActivity {
    //UI Element
    Button btnUp;
    Button btnDown;
    Button btnLedOn;
    Button btnLedOff;
    EditText txtAddress;
    /*TextView message;*/
    Socket myAppSocket = null;
    public static String wifiModuleIp = "";
    public static int wifiModulePort = 0;
    public static String CMD = "0";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnUp = (Button) findViewById(R.id.btnUp);
        btnDown = (Button) findViewById(R.id.btnDown);
        btnLedOn = (Button) findViewById(R.id.btnLedOn);
        btnLedOff = (Button) findViewById(R.id.btnLedOff);
        txtAddress = (EditText) findViewById(R.id.ipAddress);
        /*message = (TextView) findViewById(R.id.message);*/

        btnUp.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getIPandPort();
                CMD = "Up";
                Socket_AsyncTask cmd_increase_servo = new Socket_AsyncTask();
                cmd_increase_servo.execute();
            }
        });
        btnDown.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getIPandPort();
                CMD = "Down";
                Socket_AsyncTask cmd_increase_servo = new Socket_AsyncTask();
                cmd_increase_servo.execute();
            }
        });
        btnLedOn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getIPandPort();;
                CMD = "ON";
                Socket_AsyncTask cmd_led_on = new Socket_AsyncTask();
                cmd_led_on.execute();
            }
        });
        btnLedOff.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getIPandPort();
                CMD = "OFF";
                Socket_AsyncTask cmd_led_off = new Socket_AsyncTask();
                cmd_led_off.execute();
            }
        });

    }
    public void getIPandPort()
    {
        String iPandPort = txtAddress.getText().toString();

        Log.d("MYTEST","IP String: "+ iPandPort);
        String temp[]= iPandPort.split(":");
        wifiModuleIp = temp[0];
        wifiModulePort = Integer.valueOf(temp[1]);
        Log.d("MY TEST","IP:" +wifiModuleIp);
        Log.d("MY TEST","PORT:"+wifiModulePort);
    }
    public class Socket_AsyncTask extends AsyncTask<Void,Void,Void>
    {
        Socket socket;

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

            try{

                InetAddress inetAddress = InetAddress.getByName(MainActivity.wifiModuleIp);
                socket = new java.net.Socket(inetAddress,MainActivity.wifiModulePort);
                //read input msg from server

                DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
                dataOutputStream.writeBytes(CMD);
                System.out.println(CMD);
                dataOutputStream.close();

                socket.close();
            }catch (UnknownHostException e){e.printStackTrace();}catch (IOException e){e.printStackTrace();}
            return null;
        }
    }
}

Output of the Android Code Android代码的输出 在此处输入图片说明

UPDATED 17May I tried writeUTF it gives some null data before Up(See Image) 更新17 May我尝试了writeUTF,它在Up之前给出了一些空数据(参见图像) 在此处输入图片说明

Give it a try: 试试看:

socket = new java.net.Socket(inetAddress,MainActivity.wifiModulePort);
//read input msg from server
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeChars(CMD);
System.out.println(CMD);
dataOutputStream.close();

socket.close();

If this adds additional spaces then the simples solution would be to keep using writeutf and substring the data on the server side 如果这增加了额外的空间,那么简单的解决方案将是继续使用writeutf并在服务器端对数据进行子字符串化

socket = new java.net.Socket(inetAddress,MainActivity.wifiModulePort); 套接字=新的java.net.Socket(inetAddress,MainActivity.wifiModulePort);

//read input msg from server
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF(CMD);
System.out.println(CMD);
dataOutputStream.close();

socket.close();

and on the server side: 在服务器端:

data = tcpCliSock.recv(BUFSIZE).decode()
data = data[2:]

Quote from Javadoc: 引用Javadoc:

Writes a string to the underlying output stream using modified UTF-8 encoding in a machine-independent manner. 使用修改后的UTF-8编码以与机器无关的方式将字符串写入基础输出流。

First, two bytes are written to the output stream as if by the writeShort method giving the number of bytes to follow. 首先,将两个字节写入输出流,就像通过writeShort方法给出要跟随的字节数一样。 This value is the number of bytes actually written out, not the length of the string. 该值是实际写入的字节数,而不是字符串的长度。 Following the length, each character of the string is output, in sequence, using the modified UTF-8 encoding for the character. 按照长度,使用修改后的字符的UTF-8编码,依次输出字符串的每个字符。 If no exception is thrown, the counter written is incremented by the total number of bytes written to the output stream. 如果未引发异常,则写入的计数器将增加写入输出流的字节总数。 This will be at least two plus the length of str, and at most two plus thrice the length of str. 这将是至少2加str的长度,最多2加3的str的长度。

Please can you provide you Android code snippet (where you are sending the message) to the server. 请您向您的服务器提供Android代码段(用于在其中发送消息)。

When I run the code on my local machine (I don't have a raspberry controller so I commented out certain lines): 当我在本地计算机上运行代码时(我没有树莓派控制器,因此我注释掉了某些行):

import sys
import socket
import select

ctrCmd = ['Up', 'Down', 'Left', 'Right', 'Stop', 'Connect']

HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST, PORT)

tcpSerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpSerSock.bind(ADDR)

tcpSerSock.listen(1)
print('Waiting for connection')

sendInterval = 1.0  # interval(sec) for sending messages to connected clients

rxset = [tcpSerSock]
txset = []
while True:
    print("Waiting for connection")
    tcpCliSock, addr = tcpSerSock.accept()
    print("...connected from :", addr)

    try:
        while True:
            data = ''
            data = tcpCliSock.recv(BUFSIZE).decode()
            print("This", data)

            if not data:
                print("No Data", data)
                break
            if data == ctrCmd[0]:
                print("I am here")
                # Servomotor.ServoUp()
                print("Increase: ")
                #tcpCliSock.send("Servo Increases".encode())
            if data == ctrCmd[1]:
                # Servomotor.ServoDown()
                print("Decrease: ")
                #tcpCliSock.send("Servo Decreases".encode())
            if data == ctrCmd[2]:
                # Servomotor.ledOn()
                print("Led On")
                #tcpCliSock.send("Led On".encode())
            if data == ctrCmd[3]:
                # Servomotor.ledOff()
                print("Led Off")
               # tcpCliSock.send("Led Off".encode())
    except KeyboardInterrupt:
        # Servomotor.close()
        # GPIO.cleanup()
        print('Exception')
tcpSerSock.close()

And on the client side a run the following code: 在客户端运行以下代码:

import sys
import socket
import time

ctrCmd = [b'Up', b'Down', b'Left', b'Right', b'Stop', b'Connect']

HOST = '127.0.0.1'
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST, PORT)

tcpCliSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

tcpCliSock.connect(ADDR)
time.sleep(1)
for i in range(len(ctrCmd)):
    tcpCliSock.send(ctrCmd[i])
    time.sleep(1)
data = tcpCliSock.recv(BUFSIZE)
print(data)
tcpCliSock.close()

What I finally receive is : 我最终收到的是:

Waiting for connection
Waiting for connection
...connected from : ('127.0.0.1', 54430)
This Up
I am here
Increase:
This Down
Decrease:
This Left
Led On
This Right
Led Off
This Stop
This Connect

As you may have noticed the key is that on the client side instead of sending string I am sending a byte array (b'Up', instead of 'Up'). 您可能已经注意到,关键是在客户端而不是发送字符串,而是发送字节数组(b'Up',而不是'Up')。 So as you see there is no problem on the server side. 因此,如您所见,服务器端没有问题。

Probably on your Android side yo will need something like: 在您的Android方面,您可能需要类似以下内容:

String msg = "Up"
byte[] byteArr = msg.getBytes();

Update 更新

Ok, I think I see what's happening there. 好的,我想我知道那里发生了什么。 Using the Socket's output stream you can only send byte data. 使用套接字的输出流,您只能发送字节数据。 And what it actually does is converting your message to an array of bytes (CMD.getBytes()). 它实际上所做的是将您的消息转换为字节数组(CMD.getBytes())。 Not surprisingly your server is receiving everything step by step, byte by byte. 毫不奇怪,您的服务器一步一步地接收所有信息。 What you need to do is: 您需要做的是:

    public class MainActivity extends AppCompatActivity {
    //UI Element
    Button btnUp;
    Button btnDown;
    Button btnLedOn;
    Button btnLedOff;
    EditText txtAddress;
    /*TextView message;*/
    Socket myAppSocket = null;
    public static String wifiModuleIp = "";
    public static int wifiModulePort = 0;
    public static String CMD = "0";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnUp = (Button) findViewById(R.id.btnUp);
        btnDown = (Button) findViewById(R.id.btnDown);
        btnLedOn = (Button) findViewById(R.id.btnLedOn);
        btnLedOff = (Button) findViewById(R.id.btnLedOff);
        txtAddress = (EditText) findViewById(R.id.ipAddress);
        /*message = (TextView) findViewById(R.id.message);*/

        btnUp.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getIPandPort();
                CMD = "Up";
                Socket_AsyncTask cmd_increase_servo = new Socket_AsyncTask();
                cmd_increase_servo.execute();
            }
        });
        btnDown.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getIPandPort();
                CMD = "Down";
                Socket_AsyncTask cmd_increase_servo = new Socket_AsyncTask();
                cmd_increase_servo.execute();
            }
        });
        btnLedOn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getIPandPort();;
                CMD = "ON";
                Socket_AsyncTask cmd_led_on = new Socket_AsyncTask();
                cmd_led_on.execute();
            }
        });
        btnLedOff.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getIPandPort();
                CMD = "OFF";
                Socket_AsyncTask cmd_led_off = new Socket_AsyncTask();
                cmd_led_off.execute();
            }
        });

    }
    public void getIPandPort()
    {
        String iPandPort = txtAddress.getText().toString();

        Log.d("MYTEST","IP String: "+ iPandPort);
        String temp[]= iPandPort.split(":");
        wifiModuleIp = temp[0];
        wifiModulePort = Integer.valueOf(temp[1]);
        Log.d("MY TEST","IP:" +wifiModuleIp);
        Log.d("MY TEST","PORT:"+wifiModulePort);
    }
    public class Socket_AsyncTask extends AsyncTask<Void,Void,Void>
    {
        Socket socket;
        OutputStreamWriter osw;

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

                InetAddress inetAddress = InetAddress.getByName(MainActivity.wifiModuleIp);
                socket = new java.net.Socket(inetAddress,MainActivity.wifiModulePort);
                //read input msg from server
                osw = new OutputStreamWriter(socket.getOutputStream(), 'UTF-8');
                osw.write(CMD, 0, CMD.length());
                out.flush();
                socket.close();
            }catch (UnknownHostException e){e.printStackTrace();}catch (IOException e){e.printStackTrace();}
            return null;
        }
    }
}

if not "some string" won't be equal to True. if not "some string"将不等于True。 You might want to change it to: 您可能需要将其更改为:

if data != "" :
    # process here
    pass

You received data in separate line, it might be because of sending separately. 您在单独的行中接收到数据,这可能是因为单独发送。 you can look at my code that i once written for TCP socket. 您可以看一下我曾经为TCP套接字编写的代码。 TCP Socket TCP套接字

Also ctrCmd[0] is equal to 'Up' and your data content as i see in shell are characters like 'U' and 'P' . 另外ctrCmd[0]等于'Up' ,我在shell中看到的数据内容是'U''P''U'字符。 So the line 所以线

if data == ctrCmd[0]:
    print("I am here")

won't run, because 'Up' is not equal to 'U' . 将不会运行,因为'Up'不等于'U'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM