2

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?

3
  • "it crashes...". How? what is the stacktrace of the crash? What line does it crash at? Did you make any effort at all to make sure that the stuff you write from one side is read in sensibly on the other side? For example, Java's DataInput/DataOutput readUTF()/writeUTF() aren't compatible with plain python socket.send() and socket.recv(). Commented Aug 24, 2017 at 1:56
  • The server code becomes unresponsive when I add following two lines: q = raw_input() c.send(q) I have to disconnect and reconnect. Commented Aug 24, 2017 at 2:03
  • @JamesKPolk I did a log.d and I actually get the bytes up to 5 characters.The bytes are numbers so I need to decode the received data. Commented Aug 24, 2017 at 4:51

1 Answer 1

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)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.