我正在尝试在一个系统上工作,在该系统中,服务器将建立连接并实时向客户端发送多个数据。
为了模拟“实时”,我的服务器会一个接一个地发送2个数据,延迟1秒
class IphoneChat(Protocol):
def connectionMade(self):
print "a client connected"
self.transport.setTcpNoDelay(True)
msg = 'F#m'
b = msg.encode('utf-8')
msg2 = 'C'
c = msg2.encode('utf-8')
self.transport.write(b)
time.sleep(1)
self.transport.write(c)
我的Android客户端基本上会收到每个数据并立即打印出来
while(i<2){
Log.d("waiting", "waiting");
bytesRead = inputStream.read(buffer);
byteArrayOutputStream.write(buffer, 0, bytesRead);
response = byteArrayOutputStream.toString("UTF-8");
i++;
Log.d("response", response);
//immediately run UIthread
runOnUiThread(new Runnable() {
@Override
public void run() {
textResponse.setText(response);
}
});
}
然而,看起来客户端同时同时使用F#m和C并将它们一起显示为“F#mC”而不是“F#m”然后“C”。
是因为TCP无法做我提到的事情而且我必须使用UDP来完成它吗?
答案 0 :(得分:1)
基本上,是的,那是因为TCP无法做到你所提到的。 TCP是字节流,而不是消息流。就TCP而言,您已发送字节F
,#
,m
和C
,以及客户端是否将其读取为3个字节1个字节,一次4个字节,或2个字节后跟2个字节完全是任意的。*
但这并不意味着你必须使用UDP。如果你想通过TCP发送单独的消息,你只需要想出一些方法来自己分离消息 - 长度前缀,终结符或分隔符,消息的自我描述格式等。
在Twisted中,您通常在Protocol
类中执行此操作;事实上,这几乎就是协议的重点。
有关在TCP之上构建简单协议的一些常规(非Twisted)示例,请参阅Sockets are byte streams, not message streams。但是,如果你的消息是纯文本而其中没有可能的换行符,那么一个简单的(并且易于人工调试!)一个,只是将每个消息发送到一个单独的行,就像写消息时一样。一个文件:
b = (msg + '\n').encode('utf-8')
客户端需要缓冲收到的字节,存储它们直到看到一个或多个\n
个字符,然后将每个完整的行拆分并作为消息处理,并记住最后的不完整行并继续从那里缓冲。 Python / Twisted有很多工具可以让这部分变得简单;我不了解Android。但是你总是可以手动完成它,比如这样(未经测试的准Java伪代码):
ByteArray buf = new ByteArray();
while(i<2){
Log.d("waiting", "waiting");
bytesRead = inputStream.read(buffer);
buf.append(buffer, 0, bytesRead);
Array<ByteArray> lines = buf.split('\n');
buf = lines.popLast();
for (ByteArray line in lines) {
byteArrayOutputStream.write(line, 0, line.length());
response = byteArrayOutputStream.toString("UTF-8");
i++;
Log.d("response", response);
//immediately run UIthread
runOnUiThread(new Runnable() {
@Override
public void run() {
textResponse.setText(response);
}
});
}
}
*实际上,由于数据包和缓冲区等的工作方式,您有时会看到读取与写入完全匹配 - 尤其是在本地主机上测试时,在卸载的机器上,写入之间存在长距离等等。但你不能在实际条件下依赖它。
答案 1 :(得分:0)
我实际上是根据@abarnert的建议修改了代码库。
我的客户现在可以单独打印字符了。然而问题是,它不是实时打印出来,而是等待所有数据发送之后才按顺序打印出结果,但差异为ms。
我的服务器实际上每隔5秒发送2个数据: 连接开始后,等待5秒,发送第1个数据,等待5秒,发送第2个数据。 但是,在我的Android客户端,它在顺序打印两个数据之前等待了10秒。
我在这里做错了,以至于无法实时打印它们吗?
此致
\\\\\\\\\\\\\\\\\\\\\\\\\\\ 更新的服务器代码 \\\\\\\\\\\\\\\\\\\\\\\\\\\
class IphoneChat(Protocol):
def connectionMade(self):
print "a client connected"
self.transport.setTcpNoDelay(True)
int = 0
while(True):
time.sleep(5)
msg = 'F#m'
b = (msg + '/').encode('utf-8')
msg2 = 'C'
c = (msg2 + '/').encode('utf-8')
if int==0:
self.transport.write(b)
int = 1
else:
self.transport.write(c)
int = 0
break
\\\\\\\\\\\\\\\\\\\\\\\\\\\ 更新客户代码 \\\\\\\\\\\\\\\\\\\\\\\\\\\
socket = new Socket(dstAddress, dstPort);
Log.d("socket created", "socket created");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(
1024);
byte[] buffer = new byte[1];
int bytesRead;
InputStream inputStream = socket.getInputStream();
/*
* notice: inputStream.read() will block if no data return
*/
//while ((bytesRead = inputStream.read(buffer)) != -1) {
while(true){
Log.d("waiting", "waiting");
while(!byteArrayOutputStream.toString().contains("/")){
bytesRead = inputStream.read(buffer);
byteArrayOutputStream.write(buffer, 0, bytesRead);
Log.d("buffer", buffer.toString());
}
//byteArrayOutputStream.write(buffer, 0, bytesRead);
response = byteArrayOutputStream.toString("UTF-8");
response = response.substring(0, response.length()-1);
byteArrayOutputStream = new ByteArrayOutputStream(
1024);
Log.d("response", response);
//immediately run UIthread
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.d("printing", "printing");
textResponse.setText(response);
}
});
}