我正在尝试使用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)
关于如何修复它的任何想法?
答案 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)