我遇到了性能问题,在同一局域网上通过WiFi聊天的2个安卓平板电脑之间的tcp套接字连接速度一致。偶尔(恰好足以成为真正的问题),在设备之间绕过一个小的有效载荷(<1400字节)可以花费许多秒。 10+秒并不罕见,在最糟糕的情况下,我看到 4分钟的往返时间。套接字没有损坏 - 它是通常在客户端或服务器端阻塞读操作,一旦往返最终完成,下一个可能只需几毫秒。
如果我不断地通过套接字推送数据,那么我没有看到任何问题,它通常会保持快速(<100毫秒)并且整天连接。然而,当我滴灌饲料有效载荷 - 比如说每隔几秒钟一次,那么不仅每次往返都需要更长的时间,而且偶尔会看到这些愚蠢的时间为10秒或更长。我不是在寻找高性能,任何长达3秒的事情都不是真正的问题。
据我所知,在有效负载之间暂停时,Android会通过暂时关闭WiFi无线电来保留电池,而TCP堆栈也可能会添加一个小延迟,以便让应用层有时间向有效负载添加更多数据。这两点很容易解释当有效载荷连续发送时,~120ms的rtrtrips与1-5ms的往返。但是,在发送之前,我从未听说过TCP挂起缓冲数据超过30秒。
这不是Nagle问题 - TCP_NO_DELAY设置为true,并且我使用线程优先级和其他TCP调整标志无效。
我正在使用2台三星Galaxy Tabs运行Lollipop和Marshmallow,不过我也尝试过华硕,爱可视,联想和华为设备。
没有什么花哨的东西 - 写入套接字看起来像这样:
try {
clientSocket = new Socket(serverIp, ECHO_PORT);
SocketTransport transport = new SocketTransport(clientSocket);
while (running) {
// Blocking call ;-)
onStatusChange("Waiting for next message", 0);
String msg = theQ.take();
onStatusChange("Writing new message", 0);
long timeStart = System.currentTimeMillis();
transport.write(msg);
onStatusChange("Waiting for response", 0);
String result = transport.read();
onStatusChange(result, System.currentTimeMillis() - timeStart);
if (result == null) {
running = false;
}
}
}
实际阅读&amp;在一个看起来像这样的简单包装类中写一下:
package com.problem.sockettester;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
/**
* wrap up the reading and writing to sockets.
*/
public class SocketTransport {
static final int IPTOS_LOWCOST = 0x02;
static final int IPTOS_RELIABILITY = 0x04;
static final int IPTOS_THROUGHPUT = 0x08;
static final int IPTOS_LOWDELAY = 0x10;
private DataInputStream reader;
private DataOutputStream writer;
private byte[] readBuffer = new byte[4096];
public SocketTransport(Socket socket) throws IOException {
socket.setKeepAlive(true);
socket.setTcpNoDelay(true);
socket.setTrafficClass(IPTOS_LOWDELAY | IPTOS_RELIABILITY);
socket.setReceiveBufferSize(4096);
socket.setSendBufferSize(4096);
reader = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
writer = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
}
public String read() throws IOException {
int messageSize = reader.readInt();
int bytesRead;
int totalRead = 0;
int offset = 0;
boolean moreToRead = true;
while (moreToRead) {
bytesRead = reader.read(readBuffer, offset, messageSize);
totalRead += bytesRead;
if (totalRead == messageSize) {
moreToRead = false;
}
offset += bytesRead;
}
return new String(readBuffer, 0, messageSize);
}
public int write(String message) throws IOException {
writer.writeInt(message.length());
writer.writeBytes(message);
writer.flush();
return message.length();
}
}
对于那些喜欢挑战的人,可以在https://github.com/NigelDyson/androidsocketissue
的github上找到最小服务器和客户端应用的完整来源任何想法或帮助都会非常感激 - 我的想法很快就会消失。