Android上的非常慢的套接字通过wifi

时间:2017-08-21 07:44:26

标签: java android sockets tcp wifi

我遇到了性能问题,在同一局域网上通过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上找到最小服务器和客户端应用的完整来源

任何想法或帮助都会非常感激 - 我的想法很快就会消失。

0 个答案:

没有答案