Create a python server to send data to Android app using socket

主宰稳场 提交于 2019-12-05 05:29:22

问题


I am trying to create a simple chat server program using socket in python ( my pc ) to communicate with my Android client code ( my Android phone ) .

I have a simple server code which receives messages but it blocks the client app and crashes when I try to send messages from server to client.

The client code is based on this tutorial: Simple Android Chat Application, client side.

Client code:

    private class ChatClientThread extends Thread {

    String name;
    String dstAddress;
    int dstPort;

    String msgToSend = "";
    boolean goOut = false;

    ChatClientThread(String name, String address, int port) {
        this.name = name;
        dstAddress = address;
        dstPort = port;
    }

    @Override
    public void run() {
        Socket socket = null;
        DataOutputStream dataOutputStream = null;
        DataInputStream dataInputStream = null;

        try {
            socket = new Socket(dstAddress, dstPort);
            dataOutputStream = new DataOutputStream(
                    socket.getOutputStream());
            dataInputStream = new DataInputStream(socket.getInputStream());
            dataOutputStream.writeUTF(name);
            dataOutputStream.flush();

            while (!goOut) {
                if (dataInputStream.available() > 0) {
                    msgLog += dataInputStream.readUTF();

                    MainActivity.this.runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            chatMsg.setText(msgLog);
                        }
                    });
                }

                if(!msgToSend.equals("")){
                    dataOutputStream.writeUTF(msgToSend);
                    dataOutputStream.flush();
                    msgToSend = "";
                }
            }

        } catch (UnknownHostException e) {
            e.printStackTrace();
            final String eString = e.toString();
            MainActivity.this.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    Toast.makeText(MainActivity.this, eString, Toast.LENGTH_LONG).show();
                }

            });
        } catch (IOException e) {
            e.printStackTrace();
            final String eString = e.toString();
            MainActivity.this.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    Toast.makeText(MainActivity.this, eString, Toast.LENGTH_LONG).show();
                }

            });
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            if (dataOutputStream != null) {
                try {
                    dataOutputStream.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            if (dataInputStream != null) {
                try {
                    dataInputStream.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            MainActivity.this.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    loginPanel.setVisibility(View.VISIBLE);
                    chatPanel.setVisibility(View.GONE);
                }

            });
        }

    }

    private void sendMsg(String msg){
        msgToSend = msg;
    }

    private void disconnect(){
        goOut = true;
    }
}

Server code:

import socket

s = socket.socket()
host = "192.168.1.82"
port = 8080

s.bind((host, port))
print host
s.listen(5)
c = None

while True:
   if c is None:
       # Halts
       print '[Waiting for connection...]'
       c, addr = s.accept()
       print 'Got connection from', addr
   else:
       # Halts
       print '[Waiting for response...]'
       print c.recv(1024)

When add following two lines to send messages then it doesn't work.

   # Halts
   print '[Waiting for response...]'
   print c.recv(1024)
  q = raw_input()
  c.send(q)

Any ideas on how to fix it?


回答1:


The DataOutput.writeUTF() and DataInput.readUTF() methods in Java do not have any direct equivalents in python. As the Javadocs for DataOutput.writeUTF() state:

Writes two bytes of length information to the output stream, followed by the modified UTF-8 representation of every character in the string s. If s is null, a NullPointerException is thrown. Each character in the string s is converted to a group of one, two, or three bytes, depending on the value of the character.

The two length bytes are in big-endian order. Thus, at a minimum, a python program reading in this information must first read in those two length bytes to determine the length of the subsequent data, then read in that many bytes of specially-encoded character data, and finally decode it. Decoding it on the python side appears to be non-trivial based on the discussion here on the encoding used, called 'modified UTF-8':

The differences between this format and the standard UTF-8 format are the following:

  • The null byte '\u0000' is encoded in 2-byte format rather than 1-byte, so that the encoded strings never have embedded nulls.
  • Only the 1-byte, 2-byte, and 3-byte formats are used.
  • Supplementary characters are represented in the form of surrogate pairs.

As an alternative that I think would be much easier, on the Java side consider abandoning the readUTf() and writeUTF() methods and replacing them with your own versions like the following:

public void writeUTF8(String s, DataOutput out) throws IOException {
    byte [] encoded = s.getBytes(StandardCharsets.UTF_8);
    out.writeInt(encoded.length);
    out.write(encoded);
}

public String readUTF8(DataInput in) throws IOException {
    int length = in.readInt();
    byte [] encoded = new byte[length];
    in.readFully(encoded);
    return new String(encoded, StandardCharsets.UTF_8);
}

And then, on the python side, the equivalent code could be:

def recvall(sock, size):
    received_chunks = []
    buf_size = 4096
    remaining = size
    while remaining > 0:
        received = sock.recv(min(remaining, buf_size))
        if not received:
            raise Exception('unexcepted EOF')
        received_chunks.append(received)
        remaining -= len(received)
    return b''.join(received_chunks)


def read_utf8(sock):
    len_bytes = recvall(sock, 4)
    length = struct.unpack('>i', len_bytes)[0]
    encoded = recvall(sock, length)
    return str(encoded, encoding='utf-8')


def write_utf8(s: str, sock: socket.socket):
    encoded = s.encode(encoding='utf-8')
    sock.sendall(struct.pack('>i', len(encoded)))
    sock.sendall(encoded)


来源:https://stackoverflow.com/questions/45851162/create-a-python-server-to-send-data-to-android-app-using-socket

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!