2013-04-03 183 views
0

因此,我有一个简单的小型服务器从我的主程序的单独线程开始(此线程的代码位于底部),一切都很好,我可以用telnet连接到它并发送消息和什么。如果我发送“quit”,程序完全按照预期执行,它会退出,但如果我发送任何其他消息,则会收到套接字已关闭的日志,但从telnet连接仍然保持活动状态 - 我知道这一点因为我知道,因为telnet仍然像其连接一样。为什么telnet的连接不被切断?它如何在“ESTABLISHED”状态下保持活跃状态​​?关闭套接字后,套接字连接保持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; 
} 

回答

2

你关闭你的监听套接字(contsock),但不是你的连接插座(asock)。然后您返回到主线,连接套接字仍处于打开状态!

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

+0

谢谢!起初没有看到! – DanZimm

0
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); 
    } 

对不起,我不会写英文,嗯...... 如果你想使用退出()或返回,close()方法必须使用。

+0

这不能解决我所问的问题...... – DanZimm