创建一个python服务器,使用socket将数据发送到Android应用程序

时间:2017-08-24 00:28:39

标签: android python sockets chat

我正在尝试使用python(我的电脑)中的套接字创建一个简单的聊天服务器程序,以便与我的Android客户端代码(我的Android手机)进行通信。

我有一个简单的服务器代码,它接收消息,但当我尝试从服务器向客户端发送消息时,它会阻止客户端应用程序崩溃。

客户端代码基于本教程:Simple Android Chat Application, client side.

客户代码:

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

服务器代码:

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)

当添加以下两行来发送消息时,它不起作用。

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

关于如何修复它的任何想法?

1 个答案:

答案 0 :(得分:1)

Java中的DataOutput.writeUTF()DataInput.readUTF()方法在python中没有任何直接的等价物。作为DataOutput.writeUTF()状态的Javadocs:

  

将两个字节的长度信息写入输出流,然后   通过修改的字符串中每个字符的UTF-8表示   秒。如果s为null,则抛出NullPointerException。中的每个角色   字符串s转换为一个,两个或三个字节的组,   取决于角色的价值。

两个长度字节是big-endian顺序。因此,至少,读取此信息的python程序必须首先读取这两个长度字节以确定后续数据的长度,然后读入那么多字节的特殊编码字符数据,最后解码它。根据所使用的编码here的讨论,在python端对其进行解码似乎并不重要,称为修改过的UTF-8':

  

此格式与标准UTF-8格式之间存在差异   以下内容:

     
      
  • 空字节' \ u0000'以2字节格式而不是1字节编码,   这样编码的字符串就不会有嵌入的空值。
  •   
  • 仅使用1字节,2字节和3字节格式。
  •   
  • 补充字符以代理对的形式表示。
  •   

作为替代方案,我认为会更容易,在Java方面考虑放弃readUTf()writeUTF()方法,并将它们替换为您自己的版本,如下所示:

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

然后,在python方面,等效代码可以是:

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)