【问题标题】:Socket connection stays ESTABLISHED after I close the socket关闭套接字后,套接字连接保持 ESTABLISHED
【发布时间】:2013-04-03 17:39:11
【问题描述】:

所以我有一个简单的小服务器从我的主程序的一个单独的线程启动(这个线程的代码在底部),一切都很好,我可以通过 telnet 连接到它并发送消息和什么的。如果我发送“退出”,程序完全按照预期执行,它会退出,但如果我发送任何其他消息,我会在日志中显示套接字已关闭,但来自 telnet 的连接仍然保持活动状态 - 我知道这一点因为我 lsof 并且因为 telnet 仍然像它已连接一样。为什么telnet的连接没有被切断?为什么它在“ESTABLISHED”状态下还活着?

lsof:

bash      24122  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
bash      24813  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
bash      25782  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
bash      26395  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
vim       26462  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
vim       26462  Dan    4u     REG                1,2     16384 16889838 /Users/Dan/Dropbox/PersonalDev/cruentus/.cruentus.c.swp
cruentus  26474  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
cruentus  26474  Dan  txt      REG                1,2     14840 16889520 /Users/Dan/Dropbox/PersonalDev/cruentus/obj/cruentus
cruentus  26474  Dan  txt      REG                1,2    600576   748159 /usr/lib/dyld
cruentus  26474  Dan  txt      REG                1,2 303132672 15641156 /private/var/db/dyld/dyld_shared_cache_x86_64
cruentus  26474  Dan    0u     CHR               16,0  0t532754      899 /dev/ttys000
cruentus  26474  Dan    1u     CHR               16,0  0t532754      899 /dev/ttys000
cruentus  26474  Dan    2u     CHR               16,0  0t532754      899 /dev/ttys000
cruentus  26474  Dan    3u    IPv4 0x5e17dc80b705100f       0t0      TCP *:terabase (LISTEN)
cruentus  26474  Dan    5u    IPv4 0x5e17dc80a55f88d7       0t0      TCP localhost:krb524->localhost:55775 (ESTABLISHED)
telnet    26482  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
lsof      26483  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
grep      26484  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus

服务器代码:

void *controller_thread(void *a __unused) {
    puts("Starting controller thread");
    int contsock, asock, alen;
    struct sockaddr_in saddr, inaddr;
    struct timeval tv;
    struct linger lingading;

    if ((contsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("controller : socket");
        return NULL;
    }

    bzero((void*)&saddr, sizeof(struct sockaddr_in));
    saddr.sin_len = sizeof(struct sockaddr_in);
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(4444);
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if (bind(contsock, (const struct sockaddr*)&saddr, (socklen_t)saddr.sin_len) != 0) {
        perror("controller : bind");
        return NULL;
    }

    if (listen(contsock, 1) != 0) {
        perror("controller : listen");
    }
    lingading.l_onoff = 1;
    lingading.l_linger = 5;
    if (setsockopt(contsock, SOL_SOCKET, SO_LINGER_SEC, (const void*)&lingading, (socklen_t)sizeof(struct linger)) != 0) {
        perror("controller : setsockopt1");
        return NULL;
    }
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    if (setsockopt(contsock, SOL_SOCKET, SO_SNDTIMEO, (const void*)&tv, (socklen_t)sizeof(struct timeval)) != 0) {
        perror("controller : setsockopt2");
        return NULL;
    }
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    if (setsockopt(contsock, SOL_SOCKET, SO_RCVTIMEO ,(const void*)&tv, (socklen_t)sizeof(struct timeval)) != 0) {
        perror("controller : setsockopt3");
        return NULL;
    }

    bzero((void*)&inaddr, sizeof(struct sockaddr_in));
    alen = sizeof(struct sockaddr_in);
    if ((asock = accept(contsock, (struct sockaddr *)&inaddr, (socklen_t*)&alen)) != -1) {
        printf("Got controller connection: %s:%d\n", inet_ntoa(inaddr.sin_addr), ntohs(inaddr.sin_port));
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        if (setsockopt(asock, SOL_SOCKET, SO_RCVTIMEO ,(const void*)&tv, (socklen_t)sizeof(struct timeval)) != 0) {
            perror("controller : setsockopt3");
            return NULL;
        }
        char abuf[4];
        if (read(asock, abuf, 4) == 4 && strncmp("quit", abuf, 4) == 0) {
            puts("Quitting now!");
            exit(0);
        }
    } else {
        perror("controller : accept");
    }

    puts("Failed to quit from controller");

    if (shutdown(contsock, SHUT_WR) != 0) {
        if (errno != ENOTCONN)
            perror("controller : shutdown");
    }
    char tmp;
    while (read(contsock, &tmp, 1) == 1) {
        // remove all packets...
    }
    puts("Shutdown controller socket");
    if (close(contsock) != 0) {
        perror("controller : close");
    }
    puts("Closed controller socket");
    return NULL;
}

【问题讨论】:

    标签: c sockets networking


    【解决方案1】:

    您正在关闭您的监听套接字 (contsock) 但不是您的连接套接字 (asock)。然后你回到你的主线,连接套接字仍然打开!

    我建议将 contsock 和 asock 都预先设置为 -1 以标记为“未打开”。在任何返回之前,如果其中一个不是 -1,请关闭它。这将确保您在返回之前关闭所有套接字,即使是在您的错误条件之一。

    【讨论】:

      【解决方案2】:
          if (read(asock, abuf, 4) == 4 && strncmp("quit", abuf, 4) == 0) {
              puts("Quitting now!");
              exit(0);
          }
      

      ==>

         if (read(asock, abuf, 4) == 4 && strncmp("quit", abuf, 4) == 0) {
              puts("Quitting now!");
              close(contsock);
              exit(0);
          }
      

      对不起,我不会写英文,好吧... 如果要使用exit()或return,必须使用close()。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多