首页 > 解决方案 > Android Socket 每 20 秒卡住一次

问题描述

我在动作游戏中使用 TCP 套接字连接,我们使用锁步同步,客户端每秒将接收 20 - 40 个数据包。游戏在PC上运行正常,但在Android设备上运行时,套接字每20秒就会卡住一次

服务器每秒发送 5 个数据包

我尝试使用 Unity3D 的 C# 套接字、Android Java 套接字和 Android 原生 C 套接字和阻塞/非阻塞模式,每个数据包的小/大(1 字节/100 字节)数据,每秒更少/更多(5/50)个数据包,使用单线程/主线程,在多个 Android 设备上,它们都有相同的问题。

PS:似乎 20 秒的持续时间是基于设备,而不是我的应用程序或连接;这意味着如果最后一次卡住发生在 1:00:00,下一次卡住将发生在 1:00:20,即使我们重新连接或重新启动应用程序也是如此。

Android原生C代码:

    extern "C" JNIEXPORT int JNICALL
Java_com_example_ymoon_sockettest_MainActivity_connect(JNIEnv *env, jobject /* this */)
{
    __android_log_print(ANDROID_LOG_INFO, "CSocket", "Connecting...");

    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) return -1;

    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));

    server.sin_family = AF_INET;
    server.sin_port   = htons(12350);
    server.sin_addr.s_addr = inet_addr("192.168.3.66");

    if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0)
    {
        close(sock);
        return -2;
    }

    __android_log_print(ANDROID_LOG_INFO, "CSocket", "Connected");

    char buf[100];

    int t = -1;
    int received = 0;
    while (true)
    {
        int count = recv(sock, &buf, 100, 0);
        if (count < 1) break;

        received += count;

        struct timeval tv;
        gettimeofday(&tv, NULL);

        int m = tv.tv_sec * 1000 + tv.tv_usec / 1000;
        int diff = m - t;
        t = m;
        std::string p = t < 0 ? "" : diff < 50 ? "-" : diff < 100 ? "-|" : diff < 150 ? "--|" :
            diff < 250 ? "---|" :  diff < 500 ? "----|" : diff < 1000 ? "-----|" : "------|";
        __android_log_print(diff > 500 ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO,
                            "CSocket", "%i | %s %i", received, p.c_str(), diff);
    }

    close(sock);

    return 0;
}

难道我做错了什么 ?这是我第一次在stackoverflow上提出问题,对不起我的英语不好,任何帮助或建议都非常感谢,谢谢。

编辑:添加服务器代码,我重写了一个简单的 tcp 服务器来测试(Window 平台)

 int main()
{

    addrinfo conf, *add = nullptr;
    memset(&conf, 0, sizeof(conf));

    conf.ai_flags    = AI_PASSIVE;
    conf.ai_socktype = SOCK_STREAM;
    conf.ai_family   = AF_INET;

    if (getaddrinfo(nullptr, "12350", &conf, &add)) return 0;

    SOCKET serverSock = socket(AF_INET, SOCK_STREAM, 0);

    char opt = 1;
    if (setsockopt(serverSock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
        setsockopt(serverSock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) == -1 ||
        bind(serverSock, add->ai_addr, add->ai_addrlen) == -1 ||
        listen(serverSock, 0) == -1)
    {
        close(serverSock);
        return 0;
    }

    printf("Listening....\n");

    sockaddr_storage incoming_addr;

    int size = sizeof(incoming_addr);
    SOCKET clientSock = accept(serverSock, (sockaddr*)&incoming_addr, &size);

    printf("Client connected\n");

    char buf[1] = { 0 };
    int sendCount = 0;
    while (true)
    {
        time_t t = time(nullptr);
        tm *lt = localtime(&t);
        printf("%02d:%02d:%02d Send to client %i\n", lt->tm_hour, lt->tm_min, lt->tm_sec, ++sendCount);

        if (send(clientSock, buf, 1, 0) < 1) break;
        Sleep(200);
    }

    close(serverSock);

    return 0;
}

编辑:添加 WireShark 捕获图像: 发生卡住时 Wireshark 拍摄

标签: androidcsocketstcp

解决方案


我已经在我家和另一个 WIFI 环境中对其进行了测试(代码发布在这里),它运行良好。唯一的区别是WIFI环境,所以我认为可能是我们公司的WIFI网络设置导致了这个问题。


推荐阅读