2013-04-03 184 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